How can I set localization in flutter custom library? - flutter

I've created some lib in my project. There are a lot of words and phrases, so I must translate everything.
I set the app's language using bloc but I don't know how to use it in my custom library.
I think I should use something related to context. I don't know at all.
Help me, please.
It's my class for localizations.
import 'dart:convert';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'constants/constants.dart';
class AppLocalizations {
Locale locale;
AppLocalizations(this.locale);
/// Helper method to keep the code in the widgets concise
/// Localizations are accessed using an InheritedWidget "of" syntax
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<AppLocalizations> delegate =
_AppLocalizationsDelegate();
late Map<String, String> _localizedStrings;
Future<bool> load() async {
String jsonString =
await rootBundle.loadString('assets/langs/${locale.languageCode}.json');
Map<String, dynamic> jsonMap = json.decode(jsonString);
_localizedStrings = jsonMap.map((key, value) {
return MapEntry(key, value.toString());
});
return true;
}
String? translate(String key) {
return _localizedStrings[key];
}
}
class _AppLocalizationsDelegate
extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
// add all languages code here
#override
bool isSupported(Locale locale) {
return LanguageKeys.LANGUAGE_KEYS_LIST.contains(locale.languageCode);
}
// load all localization files
#override
Future<AppLocalizations> load(Locale locale) async {
AppLocalizations localizations = new AppLocalizations(locale);
await localizations.load();
return localizations;
}
#override
bool shouldReload(LocalizationsDelegate<AppLocalizations> old) => false;
}

I don't know much about bloc pattern since I have always used provider.
But the basic step would be:
(1) Inject the AppLocalizations class localization into material app
MaterialApp(
supportedLocales: [
Locale('en'),
Locale('es'),
],
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
localeResolutionCallback: (locale, supportedLocales) {
for (var supportedLocale in supportedLocales) {
if (supportedLocale.languageCode == locale.languageCode &&
supportedLocale.countryCode == locale.countryCode) {
return supportedLocale;
}
}
return supportedLocales.first;
},
locale: Locale('en'), // translate to this language
.......
);
(2) For any translation pass the key to Applocalization
AppLocalizations.of(context).translate("understood")
You can change translate method in AppLocalizations class
(3) If you want to change app locale/lang add your stateful variable to locale key in Material App and put the Consumer above MaterialApp itself.
ChangeNotifierProvider<LangSettingsProvider>(
create: (_) => LangSettingsProvider(),
child: Consumer<LangSettingsProvider>(
builder: (context, lang, _) {
return MaterialApp(
locale : lang.appLocal
....
(4) Include assets inside assets folder and specify in the pubspec yml file
assets:
- assets/icon/
- assets/lang/en.json
- assets/lang/es.json
(5) Sample of the json key value pair
//en.json
"understood":"Understood",
//es.json
"understood":"Entendido",

Related

UnsupportedError thrown when setting localizationsDelegates

I'm trying to implement internationalization for my Flutter app but it won't let me use my preferred language (Indonesian).
From the docs, it told me to add localizationsDelegates to my MaterialApp. Since I am using GetX, the MaterialApp here are wrapped inside the GetMaterialApp.
But when I did that, it throws me an error:
Exception has occurred.
UnsupportedError (Unsupported operation: Cannot modify unmodifiable map)
I tried to remove the localizationsDelegates, it throws me yet another error:
Exception has occurred.
FlutterError (No MaterialLocalizations found.
TabBar widgets require MaterialLocalizations to be provided by a Localizations widget ancestor.
The material library uses Localizations to generate messages, labels, and abbreviations.
To introduce a MaterialLocalizations, either use a MaterialApp at the root of your application to include them automatically, or add a Localization widget with a MaterialLocalizations delegate.
The specific widget that could not find a MaterialLocalizations ancestor was:
TabBar
But when I hard code the locale property of my GetMaterialApp to Locale('en', 'US') and commented the localizationsDelegates, it works.
Do you guys know why and how to fix this?
Anyways, here is how my main.dart (and some related files) look like.
main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Get.putAsync(() => EnvService().init());
await Get.putAsync(() => IntlService().init());
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return GetMaterialApp(
title: "MyApp",
initialRoute: AppPages.INITIAL,
getPages: AppPages.routes,
themeMode: ThemeMode.dark,
theme: MyAppTheme.light,
darkTheme: MyAppTheme.dark,
debugShowCheckedModeBanner: false,
// translations: AppTranslations(),
locale: const Locale('en', 'US'),
fallbackLocale: const Locale('id', 'ID'),
supportedLocales: const [
Locale('en', 'US'),
Locale('id', 'ID'),
],
//
//
// UNCOMMENT THIS LINE, YOUR PHONE WILL EXPLODE!
// localizationsDelegates: GlobalMaterialLocalizations.delegates,
);
}
}
env_service.dart
class EnvService extends GetxService {
static EnvService get instance => Get.find();
Future<EnvService> init() async {
await dotenv.load();
return this;
}
Locale get defaultLocale {
final locale = dotenv.get('DEFAULT_LOCALE', fallback: 'id');
if (locale != 'id') {
return const Locale('en', 'US');
}
return Locale(locale, locale.toUpperCase());
}
}
intl_service.dart
class IntlService extends GetxService {
static IntlService get instance => Get.find();
Locale get _locale {
return Get.locale ?? EnvService.instance.defaultLocale;
}
Future<IntlService> init() async {
await initializeDateFormatting(_locale.countryCode);
return this;
}
String formatCurrency(double number) {
final formatter = NumberFormat.simpleCurrency(decimalDigits: 0);
return formatter.format(number);
}
String formatDate(DateTime? dateTime, [String? format]) {
if (dateTime == null) {
return '';
}
return DateFormat(format).format(dateTime);
}
}
try add this in GetMaterialApp:
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
It should work if you remove initializeDateFormatting(). And be aware that Hot Reload might not work if you make this change.
This works because initializeDateFormatting() calls initializeDatePatterns() with a const Map setting dateTimePatterns which is immutable after that. But GlobalMaterialLocalizations.delegate calls initializeDateFormattingCustom() which tries to write its map into dateTimePatterns at the end. That results in an "Unsupported operation: Cannot modify unmodifiable map". So if we do not call initializeDateFormatting(), this error does not happen because dateTimePatterns is not immutable when initializeDateFormattingCustom() is called. But the date formatting is initialized anyway because that is what initializeDateFormattingCustom() does with the formatting from GlobalMaterialLocalizations.
This depends on intl ^0.17.0.

Non-nullable instance field '_localizedStrings' must be initialized

To be honest, I didn't meet this kind of error before. I am following a tutorial which you can see here:
https://resocoder.com/2019/06/01/flutter-localization-the-easy-way-internationalization-with-json/
Here is my code:
MAIN.dart:
import 'app_localizations.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
supportedLocales: [Locale('en', 'US'), Locale('vi', 'VN')],
localizationsDelegates: [
// THIS CLASS WILL BE ADDED LATER
// A class which loads the translations from JSON files
AppLocalizations.delegate,
// Built-in localization of basic text for Material widgets
GlobalMaterialLocalizations.delegate,
// Built-in localization for text direction LTR/RTL
GlobalWidgetsLocalizations.delegate,
],
localeResolutionCallback: (locale, supportedLocales) {
for (var supportedLocale in supportedLocales) {
if (supportedLocale.languageCode == locale!.languageCode &&
supportedLocale.countryCode == locale.countryCode) {
return supportedLocale;
}
}
return supportedLocales.first;
},
home: MyHomePage(),
);
}
}
APP_LOCALIZATIONS.dart:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class AppLocalizations {
final Locale locale;
//error right here
AppLocalizations(this.locale);
//error right here
//modify
static AppLocalizations? of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
//modify
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();
Map<String, String> _localizedStrings;
Future<bool> load() async {
String jsonString =
await rootBundle.loadString('lang/${locale.languageCode}.json');
Map<String, dynamic> jsonMap = json.decode(jsonString);
_localizedStrings = jsonMap.map((key, value) {
return MapEntry(key, value.toString());
});
return true;
}
//modify
String? translate(String key) {
return _localizedStrings[key];
}
}
//modify
class _AppLocalizationsDelegate
extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
#override
bool isSupported(Locale locale) {
return ['en', 'vi'].contains(locale.languageCode);
}
#override
Future<AppLocalizations> load(Locale locale) async {
AppLocalizations localizations = new AppLocalizations(locale);
await localizations.load();
return localizations;
}
#override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
Some code here is modified because of some error so it is a little different from the tutorial (to fix error.). So maybe it is the reason. I put some comment about that modification up there.
P/S: I tried searching for other answer about this but I couldn't understand much so pls explains for me!
Just initialize _localizedStrings to an empty map.
Map<String, String> _localizedStrings = {};
This way it will never be null even if it doesn't have data yet.
The other option is to add the late modifier before declaration which tells the compiler it will be initialized later on.
late Map<String, String> _localizedStrings;

Flutter Localization with ARB - The getter was called on null

I've been having this error for a while and I think I need some second eyes of an expert to solve it and I'm really new in this language ^^.
I added localizable to my project in Flutter, added all the files.arb in different languages and tries to import it following Google's tutorial and other just different work around but keep getting the same error:
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building StyleguideScreen(dirty):
The getter 'welcomeGeneralInfoTitle' was called on null.
Receiver: null
Tried calling: welcomeGeneralInfoTitle
This is my AppLocalizations.dart class I'm using for the localicationDelegates
class AppLocalizations {
static const AppLocalizationsDelegate delegate = AppLocalizationsDelegate();
static Future<AppLocalizations> load(Locale locale) {
final String name = locale.countryCode.isEmpty ? locale.languageCode : locale.toString();
final String localeName = Intl.canonicalizedLocale(name);
return initializeMessages(localeName).then((_) {
Intl.defaultLocale = localeName;
return AppLocalizations();
});
}
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
String get welcomeGeneralInfoTitle {
return Intl.message('Bet Master', name: 'title', desc: 'App Title');
}
}
class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const AppLocalizationsDelegate();
List<Locale> get supportedLocales {
return const <Locale>[
Locale('en', ''),
Locale('de', ''),
Locale('es', ''),
Locale('es', 'ES'),
]; //Still need to add 18 languages, is there a better way to add them?
}
#override
bool isSupported(Locale locale) => _isSupported(locale);
#override
Future<AppLocalizations> load(Locale locale) => AppLocalizations.load(locale);
#override
bool shouldReload(AppLocalizationsDelegate old) => false;
bool _isSupported(Locale locale) {
if (locale != null) {
for (Locale supportedLocale in supportedLocales) {
if (supportedLocale.languageCode == locale.languageCode) {
return true;
}
}
}
return false;
}
}
and here is where I added to the root of the project
return MaterialApp(
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: AppLocalizations.delegate.supportedLocales,
title: 'AMP',
theme: Theme.darkTheme,
home: StyleguideScreen(),
);
And here is how I try to implement it and it crashes
class StyleguideScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
final welcome = AppStrings.current.welcomeGeneralInfoTitle;
return Scaffold(...)
}
}
The app generates correctly all the generated files per language that it needs to import and I think it looks pretty straight forward, when I debug it, it is getting the locale correctly. Has anyone any idea why could this be happening? Thanks in advance :pray:
FIX: I just needed to add into the localizationsDelegates the auto-generated AppStrings.delegate, from the file import 'generated/l10n.dart'; instead of creating a new AppLocalizations.delegate.
like this:
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
AppStrings.delegate,
],
and remove completely the AppLocationzations class I did and it works smooth! :)
PD: I add this new library flutter_localized_locales
I use Android Studio Flutter with Intl plugin and the problem was the same
In main.dart add import import 'generated/l10n.dart';
Also add S.delegate in list of localizationsDelegates
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
S.delegate,
],

Flutter - Using GetIt with BuildContext

I'm using Localizations in my app based on the flutter documentation.
See here: https://flutter.dev/docs/development/accessibility-and-localization/internationalization
I use get_it package (version 4.0.4) to retrieve singleton objects like the Localization delegate. Unfortunately it needs a BuildContext property. Sometimes in my app I don't have the context reference so it would be nice if it would work like this: GetIt.I<AppLocalizations>() instead of this: AppLocalizations.of(context). It still can be achieved without a problem if you setup get_it like this: GetIt.I.registerLazySingleton(() => AppLocalizations.of(context)); The problem is that you need the context at least once to make it work. Moreover if you would like to display a localized text instantly in your initial route it's more difficult to get a properly initialized BuildContext at a time when you need it.
It's a little hard for me to explain it properly so I recreated the issue in a minimal example.
I commented out some code that would cause compile time errors, but it shows how I imagined it to be done.
main.dart
GetIt getIt = GetIt.instance;
void setupGetIt() {
// How to get BuildContext properly if no context is available yet?
// Compile time error.
// getIt.registerLazySingleton(() => AppLocalizations.of(context));
}
void main() {
setupGetIt();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
// The above line also won't work. It has BuildContext but Applocalizations.of(context) won't work
// because it's above in the Widget tree and not yet setted up.
getIt.registerLazySingleton(() => AppLocalizations.of(context));
return MaterialApp(
supportedLocales: const [
Locale('en', 'US'),
Locale('hu', 'HU'),
],
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
localeResolutionCallback: (locale, supportedLocales) {
// check if locale is supported
for (final supportedLocale in supportedLocales) {
if (supportedLocale.languageCode == locale?.languageCode &&
supportedLocale.countryCode == locale?.countryCode) {
return supportedLocale;
}
}
// if locale is not supported then return the first (default) one
return supportedLocales.first;
},
// You may pass the BuildContext here for Page1 in it's constructor
// but in a more advanced routing case it's not a maintanable solution.
home: Page1(),
);
}
}
Initial route
class PageBase extends StatelessWidget {
final String title;
final Widget content;
PageBase(this.title, this.content);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: content,
);
}
}
class Page1 extends PageBase {
// It won't run because I need the context but clearly I don't have it.
// And in a real app you also don't want to pass the context all over the place
if you have many routes to manage.
Page1(String title)
: super(AppLocalizations.of(context).title, Center(child: Text('Hello')));
// Intended solution
// I don't know how to properly initialize getIt AppLocalizations singleton by the time
// it tries to retrieve it
Page1.withGetIt(String title)
: super(getIt<AppLocalizations>().title, Center(child: Text('Hello')));
}
locales.dart
String globalLocaleName;
class AppLocalizations {
//AppLocalizations(this.localeName);
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();
static Future<AppLocalizations> load(Locale locale) async {
final String name =
locale.countryCode.isEmpty ? locale.languageCode : locale.toString();
final String localeName = Intl.canonicalizedLocale(name);
return initializeMessages(localeName).then((_) {
globalLocaleName = localeName;
return AppLocalizations();
});
}
String get title => Intl.message(
'This is the title.',
name: 'title',
);
}
class _AppLocalizationsDelegate
extends LocalizationsDelegate<AppLocalizations> {
// This delegate instance will never change (it doesn't even have fields!)
// It can provide a constant constructor.
const _AppLocalizationsDelegate();
#override
bool isSupported(Locale locale) {
return ['en', 'hu'].contains(locale.languageCode);
}
#override
Future<AppLocalizations> load(Locale locale) => AppLocalizations.load(locale);
#override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
And some intl generated dart code and .arb files that is not so important to illustrate the problem.
So all in all, how can I achive to use my AppLocalizations class as a singleton without using a context for example in a situation like this? Maybe my initial approach is bad and it can be done in other ways that I represented. Please let me know if you have a solution.
Thank you.
To achieve what you have described you need to first make the navigation service using get_it. Follow these steps to achieve the result :
1. Create a navigation service
import 'package:flutter/material.dart';
class NavigationService {
final GlobalKey<NavigatorState> navigatorKey =
new GlobalKey<NavigatorState>();
Future<dynamic> navigateTo(String routeName) {
return navigatorKey.currentState!
.push(routeName);
}
goBack() {
return navigatorKey.currentState!.pop();
}
}
This allows you to navigate anywhere from any point throughout the app without build context. This navigator key is what you can use to achieve the AppLocalization instance for the current context.
Refer to the FilledStacks tutorials for this method of navigating without build context.
https://www.filledstacks.com/post/navigate-without-build-context-in-flutter-using-a-navigation-service/
2. Register
GetIt locator = GetIt.instance;
void setupLocator() {
...
locator.registerLazySingleton(() => NavigationService());
...
}
3. Assign the navigator key in the material app
return MaterialApp(
...
navigatorKey: navigationService.navigatorKey,
...
),
3. Create an instance for the AppLocalizations and import it wherever you want to use
localeInstance() => AppLocalizations.of(locator<NavigationService>().navigatorKey.currentContext!)!;
3. The actual use case
import 'package:{your_app_name}/{location_to_this_instace}/{file_name}.dart';
localeInstance().your_localization_variable
You can add a builder to your MaterialApp and setup the service locator inside it with the context available. Example:
Widget build(BuildContext context) {
return MaterialApp(
builder: (context, widget) {
setUpServiceLocator(context);
return FutureBuilder(
future: getIt.allReady(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return widget;
} else {
return Container(color: Colors.white);
}
});
},
);
}
Service Locator Setup:
void setUpServiceLocator(BuildContext context) {
getIt.registerSingleton<AppLocalizations>(AppLocalizations.of(context));
}
You could use some non-localizable splash screen with FutureBuilder and getIt.allReady().
Something like:
class SplashScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return FutureBuilder<void>(
future: getIt.allReady(),
builder: (context, snapshot) {
if (snapshot.hasData) {
// Navigate to main page (with replace)
} else if (snapshot.hasError) {
// Error handling
} else {
// Some pretty loading indicator
}
},
);
}
I'd like to recommend the injectable package for dealing with get_it also.

How to setup ChangeNotifier for loading locale files

I am new to flutter.
I am building a multi language app.
Before app start it needs to load current locale file.
Then every time user changes the locale it needs to load the new file.
At least in theory, I think this can be done using "ChangeNotifierProvider" , ProxyProvider or something similar.
So I have AppLanguage class load the correct locale file based on language code
class AppLanguage extends ChangeNotifier {
String _appLocale = 'en';
Map<String, String> _localizedStrings;
Map<String, String> get localeData => this._localizedStrings;
Future<bool> getLocaleData() async {
var prefs = await SharedPreferences.getInstance();
if (prefs.getString('language_code') == null) {
_appLocale = 'en';
await prefs.setString('language_code', _appLocale);
} else {
_appLocale = prefs.getString('language_code');
}
String jsonString = await rootBundle.loadString('i18n/$_appLocale.json');
Map<String, dynamic> jsonMap = json.decode(jsonString);
_localizedStrings = jsonMap.map((key, value) {
return MapEntry(key, value.toString());
});
return true;
}
Future<void> changeLanguage(String locale) async {
var prefs = await SharedPreferences.getInstance();
_appLocale = locale;
await prefs.setString('language_code', locale);
notifyListeners();
}
}
getLocaleData() function read the data and changeLanguage change current locale and fires notifyListeners
class Translator {
final Map<String, String> localizedStrings;
Translator(this.localizedStrings);
String translate(String key) {
return localizedStrings[key];
}
}
the Widgets will use translator class to get the correct translations.
The problem I have is, how to wire this up in main. I am stuck at how to setup the providers.
void main() async {
WidgetsFlutterBinding.ensureInitialized();
AppLanguage appLanguage = AppLanguage();
await appLanguage.getLocaleData();
runApp(MyApp(appLanguage: appLanguage));
}
class MyApp extends StatelessWidget {
final AppLanguage appLanguage;
MyApp({this.appLanguage});
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ProxyProvider<AppLanguage, Translator>(
update: (context, appLanguage, trans) =>
Translator(appLanguage.localeData),
),
],
child: MaterialApp(
title: 'Language Demo',
home: MyHomePage(),
),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hello'),
),
body: Container(),
);
}
}
Can someone kindly provide some help to wire this up?
Or maybe provide a better way of doing this?
A few things, ProxyProvider (or any type of ProxyProvider, ChangeNotifierProxyProvider, etc.) updates its value when the provider it depends on changes too, but you created the AppLanguage in main, without an inject dependency, just like a simple class (it's not really provided in the context) so it would be easier to just use a ChangeNotifierProvider in this case.
There is a parameter called window.locale that return the language the device it's using at that time, at the start of the app you can use it to know the language of the device if you're don't have it the sharedPreference the first time. Advante of this it's that in your example if there is not preference saved it will use the default 'en' for English, but you also support japanase, so if someone has its device in japanese and download your app for the first time it would be nice to use japanese since the beginning.
Future<Locale> _getLocaleData() async {
var prefs = await SharedPreferences.getInstance();
String languageCode = prefs.getString('language_code');
if (languageCode == null) {
return window.locale;
} else {
return Locale(languageCode);
}
}
void main() async {
Locale locale = await _getLocaleData();
runApp(MyApp(
appLanguage: locale,
));
}
class MyApp extends StatelessWidget {
final Locale language;
MyApp({this.language});
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<AppLanguage>(
builder: (_) => AppLanguage(language),
child: Consumer<AppLanguage>(builder: (context, model, _) {
return MaterialApp(
locale: model.appLocal,
supportedLocales: [
Locale('en', 'US'),
Locale('ja', ''),
],
localizationsDelegates: [
AppLocalizations.delegate, //create your AppLocalizations just like the article you shared
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
home: MyWidget(),
);
}),
);
}
}
class AppLanguage extends ChangeNotifier {
AppLanguage(Locale locale) : _appLocale = locale;
Locale _appLocale;
Locale get appLocal => _appLocale;
Future<void> changeLanguage(String locale) async {
var prefs = await SharedPreferences.getInstance();
_appLocale = Locale(locale);
await prefs.setString('language_code', locale);
notifyListeners();
}
}