Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

App localization and language controller addition #811

Merged
Merged
3 changes: 3 additions & 0 deletions lang/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"hello-world": "Hello World"
}
3 changes: 3 additions & 0 deletions lang/es.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"hello-world": "Hola Mundo"
}
3 changes: 3 additions & 0 deletions lang/fr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"hello-world": "Bonjour le monde"
}
3 changes: 3 additions & 0 deletions lang/hi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"hello-world": "नमस्ते दुनिया"
}
3 changes: 3 additions & 0 deletions lang/zh-CN.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"hello-world": "你好"
}
52 changes: 52 additions & 0 deletions lib/controllers/lang_controller.dart
Original file line number Diff line number Diff line change
@@ -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<void> 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();
}
}
97 changes: 59 additions & 38 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -28,6 +31,8 @@ LogHelper logHelper = LogHelper();
Future<void> 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])
Expand All @@ -39,6 +44,7 @@ Future<void> main() async {
ChangeNotifierProvider<OrgController>(create: (_) => OrgController()),
ChangeNotifierProvider<AuthController>(create: (_) => AuthController()),
ChangeNotifierProvider<Preferences>(create: (_) => Preferences()),
ChangeNotifierProvider.value(value: AppLanguage()),
ChangeNotifierProvider<CommentHandler>(create: (_) => CommentHandler()),
ChangeNotifierProvider<GroupController>(
create: (_) => GroupController()),
Expand All @@ -56,45 +62,60 @@ Future<void> 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<NavigationService>().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<AppLanguage>(
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<NavigationService>().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();
},
),
),
),
);
Expand Down
60 changes: 60 additions & 0 deletions lib/services/app_localization.dart
Original file line number Diff line number Diff line change
@@ -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<AppLocalizations>(context, AppLocalizations);
}

// Static member to have a simple access to the delegate from the MaterialApp
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();

Map<String, String> _localizedStrings;

Future<bool> load() async {
// Load the language JSON file from the "lang" folder
final String jsonString =
await rootBundle.loadString('lang/${locale.languageCode}.json');
final Map<String, dynamic> jsonMap =
json.decode(jsonString) as Map<String, dynamic>;

_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<AppLocalizations> {
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<AppLocalizations> 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;
}
17 changes: 11 additions & 6 deletions lib/views/pages/newsfeed/newsfeed.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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',
Expand Down Expand Up @@ -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,
),
),
),
],
Expand Down
16 changes: 10 additions & 6 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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:
Expand All @@ -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
Expand Down