diff --git a/lang/en.json b/lang/en.json new file mode 100644 index 000000000..5eb2716ed --- /dev/null +++ b/lang/en.json @@ -0,0 +1,3 @@ +{ + "hello-world": "Hello World" +} \ No newline at end of file diff --git a/lang/es.json b/lang/es.json new file mode 100644 index 000000000..9d4ceac68 --- /dev/null +++ b/lang/es.json @@ -0,0 +1,3 @@ +{ + "hello-world": "Hola Mundo" +} \ No newline at end of file diff --git a/lang/fr.json b/lang/fr.json new file mode 100644 index 000000000..0845c5046 --- /dev/null +++ b/lang/fr.json @@ -0,0 +1,3 @@ +{ + "hello-world": "Bonjour le monde" +} \ No newline at end of file diff --git a/lang/hi.json b/lang/hi.json new file mode 100644 index 000000000..0c011946b --- /dev/null +++ b/lang/hi.json @@ -0,0 +1,3 @@ +{ + "hello-world": "नमस्ते दुनिया" +} \ No newline at end of file diff --git a/lang/zh-CN.json b/lang/zh-CN.json new file mode 100644 index 000000000..65a1f520b --- /dev/null +++ b/lang/zh-CN.json @@ -0,0 +1,3 @@ +{ + "hello-world": "你好" +} \ No newline at end of file diff --git a/lib/controllers/lang_controller.dart b/lib/controllers/lang_controller.dart new file mode 100644 index 000000000..7e75b26a5 --- /dev/null +++ b/lib/controllers/lang_controller.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class AppLanguage extends ChangeNotifier { + Locale _appLocale = const Locale('en'); + + Locale get appLocal => _appLocale ?? const Locale("en"); + fetchLocale() async { + final prefs = await SharedPreferences.getInstance(); + if (prefs.getString('language_code') == null) { + _appLocale = const Locale('en'); + return Null; + } + _appLocale = Locale(prefs.getString('language_code')); + return Null; + } + + Future changeLanguage(Locale type) async { + final prefs = await SharedPreferences.getInstance(); + if (_appLocale == type) { + return; + } + + if (type == const Locale("es")) { + //If selected language is spanish + _appLocale = const Locale("es"); + await prefs.setString('language_code', 'es'); + await prefs.setString('countryCode', 'ES'); + } else if (type == const Locale("fr")) { + //If selected language is french + _appLocale = const Locale("fr"); + await prefs.setString('language_code', 'fr'); + await prefs.setString('countryCode', 'FR'); + } else if (type == const Locale("hi")) { + //If selected language is hindi + _appLocale = const Locale("hi"); + await prefs.setString('language_code', 'hi'); + await prefs.setString('countryCode', 'IN'); + } else if (type == const Locale("zh-CN")) { + //If selected language is Chinese + _appLocale = const Locale("zh-CN"); + await prefs.setString('language_code', 'zh-CN'); + await prefs.setString('countryCode', 'CN'); + } else { + //If selected language is english + _appLocale = const Locale("en"); + await prefs.setString('language_code', 'en'); + await prefs.setString('countryCode', 'US'); + } + notifyListeners(); + } +} diff --git a/lib/main.dart b/lib/main.dart index 6b3e3315a..44e1d5868 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,15 +1,18 @@ //Flutter Packages are imported here import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; //Pages are imported here import 'package:provider/provider.dart'; import 'package:talawa/controllers/auth_controller.dart'; import 'package:talawa/controllers/groups_controller.dart'; +import 'package:talawa/controllers/lang_controller.dart'; import 'package:talawa/controllers/org_controller.dart'; import 'package:talawa/controllers/signup_login_controller.dart'; import 'package:talawa/controllers/url_controller.dart'; import 'package:talawa/locator.dart'; +import 'package:talawa/services/app_localization.dart'; import 'package:talawa/services/comment.dart'; import 'package:talawa/controllers/news_feed_controller.dart'; import 'package:talawa/services/navigation_service.dart'; @@ -28,6 +31,8 @@ LogHelper logHelper = LogHelper(); Future main() async { //ensuring weather the app is being initialized or not WidgetsFlutterBinding.ensureInitialized(); + final AppLanguage appLanguage = AppLanguage(); + await appLanguage.fetchLocale(); setupLocator(); await logHelper.init(); // To intialise FlutterLog SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]) @@ -39,6 +44,7 @@ Future main() async { ChangeNotifierProvider(create: (_) => OrgController()), ChangeNotifierProvider(create: (_) => AuthController()), ChangeNotifierProvider(create: (_) => Preferences()), + ChangeNotifierProvider.value(value: AppLanguage()), ChangeNotifierProvider(create: (_) => CommentHandler()), ChangeNotifierProvider( create: (_) => GroupController()), @@ -56,45 +62,60 @@ Future main() async { class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - return GestureDetector( - onTap: () { - final FocusScopeNode currentFocus = FocusScope.of(context); - if (!currentFocus.hasPrimaryFocus && - currentFocus.focusedChild != null) { - FocusManager.instance.primaryFocus.unfocus(); - } - }, - child: MaterialApp( - title: UIData.appName, - theme: ThemeData( - primaryColor: UIData.primaryColor, - fontFamily: UIData.quickFont, - primarySwatch: UIData.primaryColor as MaterialColor, - ), - debugShowCheckedModeBanner: false, - showPerformanceOverlay: false, - navigatorKey: locator().navigatorKey, - onGenerateRoute: router.generateRoute, - home: FutureBuilder( - future: preferences.getUserId(), - initialData: "Initial Data", - builder: (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.data.toString() == "Initial Data") { - return Scaffold( - body: Container( - child: const Center( - child: CircularProgressIndicator(), + return Consumer( + builder: (context, appLang, _) => GestureDetector( + onTap: () { + final FocusScopeNode currentFocus = FocusScope.of(context); + if (!currentFocus.hasPrimaryFocus && + currentFocus.focusedChild != null) { + FocusManager.instance.primaryFocus.unfocus(); + } + }, + child: MaterialApp( + locale: appLang.appLocal, + supportedLocales: [ + const Locale('en', 'US'), + const Locale('es', 'ES'), + const Locale('fr', 'FR'), + const Locale('hi', 'IN'), + const Locale('zh-CN', 'CN'), + ], + localizationsDelegates: [ + AppLocalizations.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ], + title: UIData.appName, + theme: ThemeData( + primaryColor: UIData.primaryColor, + fontFamily: UIData.quickFont, + primarySwatch: UIData.primaryColor as MaterialColor, + ), + debugShowCheckedModeBanner: false, + showPerformanceOverlay: false, + navigatorKey: locator().navigatorKey, + onGenerateRoute: router.generateRoute, + home: FutureBuilder( + future: preferences.getUserId(), + initialData: "Initial Data", + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.data.toString() == "Initial Data") { + return Scaffold( + body: Container( + child: const Center( + child: CircularProgressIndicator(), + ), ), - ), - ); - } else if (snapshot.hasError) { - throw FlutterError( - 'There is some error with "${snapshot.data}"\n'); - } else if (snapshot.data != null) { - return const HomePage(); - } - return UrlPage(); - }, + ); + } else if (snapshot.hasError) { + throw FlutterError( + 'There is some error with "${snapshot.data}"\n'); + } else if (snapshot.data != null) { + return const HomePage(); + } + return UrlPage(); + }, + ), ), ), ); diff --git a/lib/services/app_localization.dart b/lib/services/app_localization.dart new file mode 100644 index 000000000..dfc398d48 --- /dev/null +++ b/lib/services/app_localization.dart @@ -0,0 +1,60 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class AppLocalizations { + AppLocalizations(this.locale); + final Locale locale; + + // Helper method to keep the code in the widgets concise + static AppLocalizations of(BuildContext context) { + return Localizations.of(context, AppLocalizations); + } + + // Static member to have a simple access to the delegate from the MaterialApp + static const LocalizationsDelegate delegate = + _AppLocalizationsDelegate(); + + Map _localizedStrings; + + Future load() async { + // Load the language JSON file from the "lang" folder + final String jsonString = + await rootBundle.loadString('lang/${locale.languageCode}.json'); + final Map jsonMap = + json.decode(jsonString) as Map; + + _localizedStrings = jsonMap.map((key, value) { + return MapEntry(key, value.toString()); + }); + + return true; + } + + // This method will be called from every widget which needs a localized text + String translate(String key) { + return _localizedStrings[key]; + } +} + +class _AppLocalizationsDelegate + extends LocalizationsDelegate { + const _AppLocalizationsDelegate(); + + @override + bool isSupported(Locale locale) { + // Include all of your supported language codes here + return ['en', 'es', 'fr', 'hi', 'zh-CN'].contains(locale.languageCode); + } + + @override + Future load(Locale locale) async { + // AppLocalizations class is where the JSON loading actually runs + final AppLocalizations localizations = AppLocalizations(locale); + await localizations.load(); + return localizations; + } + + @override + bool shouldReload(_AppLocalizationsDelegate old) => false; +} diff --git a/lib/views/pages/newsfeed/newsfeed.dart b/lib/views/pages/newsfeed/newsfeed.dart index 350c65d39..dbc64213e 100644 --- a/lib/views/pages/newsfeed/newsfeed.dart +++ b/lib/views/pages/newsfeed/newsfeed.dart @@ -7,6 +7,7 @@ import 'package:persistent_bottom_nav_bar/persistent-tab-view.dart'; import 'package:provider/provider.dart'; import 'package:talawa/controllers/news_feed_controller.dart'; import 'package:talawa/model/posts.dart'; +import 'package:talawa/services/app_localization.dart'; import 'package:talawa/utils/custom_toast.dart'; import 'package:talawa/utils/ui_scaling.dart'; import 'package:talawa/views/pages/newsfeed/add_post.dart'; @@ -25,6 +26,7 @@ class NewsFeed extends StatelessWidget { @override Widget build(BuildContext context) { + //print(AppLocalizations.of(context).translate('hello-world')); return Scaffold( appBar: CustomAppBar( 'NewsFeed', @@ -118,12 +120,15 @@ class NewsFeed extends StatelessWidget { .safeBlockHorizontal * 7.5, ), - Text( - post.title.toString(), - softWrap: true, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 20.0, + // ignore: avoid_unnecessary_containers + Container( + child: Text( + post.title ?? '', + style: const TextStyle( + fontWeight: + FontWeight.bold, + fontSize: 20.0, + ), ), ), ], diff --git a/pubspec.yaml b/pubspec.yaml index 28d0e25b3..79c9c4c49 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -22,6 +22,7 @@ dependencies: adhara_socket_io: ^0.4.1 async: ^2.5.0 carousel_slider: ^2.2.1 + crypto: ^2.1.3 cupertino_icons: ^0.1.2 data_connection_checker: ^0.3.4 datetime_picker_formfield: ^1.0.0 @@ -34,14 +35,14 @@ dependencies: flutter_logs: ^2.1.3 flutter_masked_text: ^0.8.0 flutter_password_strength: ^0.1.6 - flutter_pw_validator: ^1.2.1 - flutter_secure_storage: any - flutter_sticky_header: ^0.4.5 - flutter_svg: ^0.20.0-nullsafety.3 - fluttertoast: ^7.1.8 + flutter_pw_validator: + flutter_secure_storage: + flutter_sticky_header: + flutter_svg: + fluttertoast: font_awesome_flutter: get_it: ^4.0.4 - graphql_flutter: ^3.0.1 + graphql_flutter: ^3.1.0 grouped_buttons: ^1.0.4 http: ^0.12.0+1 image_picker: any @@ -60,6 +61,8 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. +dependency_overrides: + crypto: 3.0.1 dev_dependencies: flutter_driver: @@ -85,6 +88,7 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - assets/images/ + - lang/ # assets: # - images/a_dot_burr.jpeg