I am trying to localize my app in flutter. I created the needed string.arb files for the supported languages.
Why does AppLocalizations.of(context)
need a context?
I simply want to access the named strings in the files/locales files/classes. At some point in the app I build a List and fill it later via overriding some fields with a separate class.
However, this class has no context but I want to use localized strings in it. Can I write a method which gets me the Localization of whatever String I put in?
We can resolve this by using get_it easily, we can use the string anywhere after this setup.
Install this to your vscode Flutter Intl VSCode Extension
setup pubspec.yaml
dependencies:
flutter:
sdk: flutter
flutter_localizations: # Add this line
sdk: flutter # Add this line
intl: ^0.17.0 # Add this line
get_it: ^7.2.0 # Add this line
flutter:
uses-material-design: true
generate: true # Add this line
flutter_intl: # Add this line
enabled: true # Add this line
class_name: I10n # Add this line
main_locale: en # Add this line
arb_dir: lib/core/localization/l10n # Add this line
output_dir: lib/core/localization/generated # Add this line
Setup main.dart
import 'package:component_gallery/core/localization/generated/l10n.dart';
import 'package:component_gallery/locator.dart';
import 'package:component_gallery/ui/pages/home.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
void main() {
setupLocator();
runApp(App());
}
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: [
I10n.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: I10n.delegate.supportedLocales,
localeResolutionCallback: (deviceLocale, supportedLocales) {
if (supportedLocales
.map((e) => e.languageCode)
.contains(deviceLocale?.languageCode)) {
return deviceLocale;
} else {
return const Locale('en', '');
}
},
home: HomePage(),
);
}
}
setup locator.dart
import 'package:component_gallery/core/services/navigation_service.dart';
import 'package:get_it/get_it.dart';
GetIt locator = GetIt.instance;
void setupLocator() {
locator.registerLazySingleton(() => I10n());
}
Use it with Get_it without context as
final I10n _i10n = locator<I10n>();
class MessageComponent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text(
_i10n.sample,
textAlign: TextAlign.center,
);
}
}
If you would prefer to not use a package then here is a solution that worked for me. Now the most common implementation of AppLocalizations
I've seen usually has these two lines:
//.........
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
//.........
The implementation of the delegate would look something like this:
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
@override
Future<AppLocalizations> load(Locale locale) async {
AppLocalizations localizations = new AppLocalizations(locale);
await localizations.load();
return localizations;
}
//... the rest omitted for brevity
}
Notice the load method on the delegate returns a Future<AppLocalizations>
. The load method is usually called once from main and never again so you can take advantage of that by adding a static instance of AppLocalizations
to the delegate. So now your delegate would look like this:
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
static AppLocalizations instance;
@override
Future<AppLocalizations> load(Locale locale) async {
AppLocalizations localizations = new AppLocalizations(locale);
await localizations.load();
instance = localizations; // set the static instance here
return localizations;
}
//... the rest omitted for brevity
}
Then on your AppLocalizations
class you would now have:
//.........
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
static AppLocalizations get instance => _AppLocalizationsDelegate.instance; // add this
//.........
Now in your translate helper method you could have:
String tr(String key) {
return AppLocalizations.instance.translate(key);
}
No context needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With