So far I was using dynamic strings as shown in the solution of this post: Flutter internationalization - Dynamic strings
Here's an example:
AppLocalizations.of(context).userAge(18)
And on AppLocalizations.dart:
userAge(age) => Intl.message(
"My age is $age",
name: "userAge",
args: [age]);
// Return "My age is 18"
But then I read this article about flutter internationalization: https://medium.com/flutter-community/flutter-internationalization-the-easy-way-using-provider-and-json-c47caa4212b2 Which shows how to localize using json files as resource files for the strings. It looks way more convenient so I prefer to use this method, but don't know how to get strings from json file with dynamic values.
Any solution?
To get the string with the dynamic value from JSON file you can use
final age = 18 //user input.
final ageString = 'user_age'
.localisedString()
.replaceAll(new RegExp(r'\${age}'), age)
en.json
{
"user_age": "My age is ${age}",
"user_name_age": "My name is ${name} and age is ${age}"
}
string_extension.dart
extension Localisation on String {
String localisedString() {
return stringBy(this) ?? '';
}
}
Also, you could do something like,
String localisedString(Map<String, String> args) {
String str = localisedString();
args.forEach((key, value) {
str = str.replaceAll(new RegExp(r'\${'+key+'}'), value);
});
return str;
}
//usecase
final userName = 'Spider Man'
final age = '18'
final nameAgeString = 'user_name_age'.localisedString({'name': userName, 'age': age})
app_localisation.dart
Map<String, dynamic> _language;
String stringBy(String key) => _language[key] as String ?? 'null';
class AppLocalisationDelegate extends LocalizationsDelegate {
const AppLocalisationDelegate();
// override the following method if you want to specify the locale you are supporting.
final _supportedLocale = ['en'];
@override
bool isSupported(Locale locale) => _supportedLocale.contains(locale.languageCode);
@override
Future load(Locale locale) async {
String jsonString = await rootBundle
.loadString("assets/strings/${locale.languageCode}.json");
_language = jsonDecode(jsonString) as Map<String, dynamic>;
print(_language.toString());
return SynchronousFuture<AppLocalisationDelegate>(
AppLocalisationDelegate());
}
@override
bool shouldReload(AppLocalisationDelegate old) => false;
}
Create a folder say json
in your assets
directory. Put your language files in it.
assets
json
- en.json // for English
- ru.json // for Russian
Now in en.json
, write your string, for example.
{
"myAge": "My age is"
}
Similarly, in ru.json
,
{
"myAge": "Мой возраст"
}
Add this to the pubspec.yaml
file (mind the spaces)
flutter:
uses-material-design: true
assets:
- assets/json/
Run flutter pub get
Initial work done. Let's move to the code side.
Copy this boilerplate code in your file:
Map<String, dynamic> language;
class AppLocalizations {
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
String getText(String key) => language[key];
String userAge(int age) => '${getText('myAge')} $age';
}
class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const AppLocalizationsDelegate();
@override
bool isSupported(Locale locale) => ['en', 'ru'].contains(locale.languageCode);
@override
Future<AppLocalizations> load(Locale locale) async {
final string = await rootBundle.loadString('assets/json/${locale.languageCode}.json');
language = json.decode(string);
return SynchronousFuture<AppLocalizations>(AppLocalizations());
}
@override
bool shouldReload(AppLocalizationsDelegate old) => false;
}
Set up few things in MaterialApp
widget:
void main() {
runApp(
MaterialApp(
locale: Locale('ru'), // switch between "en" and "ru" to see effect
localizationsDelegates: [const AppLocalizationsDelegate()],
supportedLocales: [const Locale('en'), const Locale('ru')],
home: HomePage(),
),
);
}
Now, you can simply use above delegate:
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
var age = AppLocalizations.of(context).userAge(18);
// prints "My age is 18" for 'en' and "Мой возраст 18" for 'ru' locale.
print(age);
return Scaffold();
}
}
I've tried various solutions to implement localization, and the best I've come across is the Flutter Intl plugin for VS Code or Android Studio/IntelliJ made by Localizely.com (not affiliated).
With it, basically you install the plugin using the marketplace/plugin library, then initialize for your project using the menu option. This creates a default english locale in lib/l10n/intl_en.arb (which sounds scary but is actually just JSON) and sets up all the scaffolding for the internationalization in lib/generated
.
You also have to add the following to your dependencies.
flutter_localizations:
sdk: flutter
You can then add keys to this file and they'll be automatically available in your app, by importing generated/l10n.dart
which contains a class called S.
To get flutter to use it, wherever it is that you initialize your MaterialApp, make sure to pass S.delegate
into MaterialApp's localizationsDelegates parameter (most likely as part of an array with GlobalMaterialLocalizations.delegate
, GlobalWidgetsLocalizations.delegate
, and possibly GlobalCupertinoLocalizations.delegate
.) You also have to add S.delegate.supportedLocales
to MaterialApp's supportedLocales
.
To add more locales, use the option in the menu (in intellij at least) or simply create more intl_.arb files, and the plugin will automatically recognize this and set up the relevant code.
Say you have an intl_en file with the following:
{ "name": "Name" }
You'd then use S.of(context).name
to use the string in your code.
All this is more eloquently explained on localizely's website.
Now, to use keys in these .arb files, you simply have to wrap it in {...}. So for example:
{ "choose1OfNumOptions": "Choose 1 of {numoptions} options" }
would lead to a usage of S.of(context).choose1OfNumOptions(numOptions);
. I don't know that the plugin supports the full ARB specification but it does support at least the basics.
Also, I'm not using Localizely but it seems like it'd be a pretty useful way to manage the translations and the plugin integrates automatically, although I think it's also pretty horrendously overpriced - at least for my app, which happens to have a ton of text. I actually just have a google sheet where I store all my translations, and when it's time to update it I download it as a .tsv and wrote a simple little parser to write out to the .arb files.
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