diff --git a/assets/i18n/en.json b/assets/i18n/en.json new file mode 100644 index 0000000..125b554 --- /dev/null +++ b/assets/i18n/en.json @@ -0,0 +1,4 @@ +{ + "title": "This is the main page", + "description": "Check the todo item below to open the menu above to check more pages." +} diff --git a/assets/i18n/pt.json b/assets/i18n/pt.json new file mode 100644 index 0000000..5442233 --- /dev/null +++ b/assets/i18n/pt.json @@ -0,0 +1,5 @@ +{ + "title": "Esta é a página inicial.", + "description": "Clica no item abaixo para abrir o menu acima para ver mais páginas." + } + \ No newline at end of file diff --git a/lib/app_localization.dart b/lib/app_localization.dart new file mode 100644 index 0000000..ceb89d5 --- /dev/null +++ b/lib/app_localization.dart @@ -0,0 +1,56 @@ +import 'dart:convert'; + +import 'package:app/settings.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +/// Utils class for app localization with delegate +class AppLocalization { + late final Locale _locale; + + AppLocalization(this._locale); + + static AppLocalization of(BuildContext context) { + return Localizations.of(context, AppLocalization)!; + } + + late Map _localizedValues; + + // This function will load requested language `.json` file and will assign it to the `_localizedValues` map + Future loadLanguage() async { + String jsonStringValues = await rootBundle.loadString("assets/i18n/${_locale.languageCode}.json"); + + Map mappedValues = json.decode(jsonStringValues); + + _localizedValues = mappedValues.map((key, value) => + MapEntry(key, value.toString())); // converting `dynamic` value to `String`, because `_localizedValues` is of type Map + } + + String? getTranslatedValue(String key) { + return _localizedValues[key]; + } + + static const LocalizationsDelegate delegate = _AppLocalizationDelegate(); +} + +/// Private overriden delegate class +class _AppLocalizationDelegate extends LocalizationsDelegate { + const _AppLocalizationDelegate(); + + // It will check if the user's locale is supported by our App or not + @override + bool isSupported(Locale locale) { + return ["en", "pt"].contains(locale.languageCode); + } + + // It will load the equivalent json file requested by the user + @override + Future load(Locale locale) async { + AppLocalization appLocalization = AppLocalization(locale); + await appLocalization.loadLanguage(); + return appLocalization; + } + + @override + bool shouldReload(_AppLocalizationDelegate old) => false; +} diff --git a/lib/main.dart b/lib/main.dart index 2d46563..8c1edee 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'app_localization.dart'; import 'menu.dart'; const iconKey = Key("menu_icon"); @@ -23,6 +25,24 @@ class App extends StatelessWidget { primarySwatch: Colors.blue, ), debugShowCheckedModeBanner: false, + supportedLocales: const [ + Locale('en', 'US'), + Locale('pt', 'PT'), + ], + localeResolutionCallback: (deviceLocale, supportedLocales) { + for (var locale in supportedLocales) { + if (locale.languageCode == deviceLocale!.languageCode && locale.countryCode == deviceLocale.countryCode) { + return deviceLocale; + } + } + return supportedLocales.first; + }, + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + AppLocalization.delegate + ], home: const HomePage()); } } @@ -82,16 +102,16 @@ class _HomePageState extends State with SingleTickerProviderStateMixin child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - const Text( - "This is the main page", - style: TextStyle(fontSize: 30), + Text( + AppLocalization.of(context).getTranslatedValue("title").toString(), + style: const TextStyle(fontSize: 30), ), - const Padding( - padding: EdgeInsets.all(16), + Padding( + padding: const EdgeInsets.all(16), child: Text( - "Check the todo item below to open the menu above to check more pages.", + AppLocalization.of(context).getTranslatedValue("description").toString(), textAlign: TextAlign.center, - style: TextStyle(fontSize: 15, color: Colors.black87), + style: const TextStyle(fontSize: 15, color: Colors.black87), ), ), ListTile( diff --git a/pubspec.lock b/pubspec.lock index 36234cb..52221d4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -174,6 +174,11 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" flutter_test: dependency: "direct dev" description: flutter @@ -192,6 +197,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + intl: + dependency: transitive + description: + name: intl + sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + url: "https://pub.dev" + source: hosted + version: "0.17.0" js: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 128ddfa..5948c25 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -31,7 +31,8 @@ environment: dependencies: flutter: sdk: flutter - + flutter_localizations: + sdk: flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. @@ -64,7 +65,8 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - assets/images/ - - assets/ + - assets/i18n/ + - assets/menu_items.json # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware