VS Code extension to create a binding between your translations from .json files and your Flutter app. You can also automagically generate translations for all your locales, based on Google Translate.
To install the extension just execute the following command:
ext install vscode-flutter-i18n-json
You may also install the extension from the visual studio code marketplace.
- Install the extension
- Open your project, open the command palette and find the
Flutter I18n Json: Initialize
command. - Enter a default locale, or press enter to use
en-US
.
Creates the inital binding between translations from .json files and your Flutter app. The command will ask you for the default locale, the locale that will be used when no other locale can be matched.
The following files will be created:
i18n/<default-locale>.json
lib/generated/i18n.dart
i18nconfig.json
Adds another locale to your Flutter app. The command will ask you for a new locale.
The following files will be created:
i18n/<new-locale>.json
and updated:
lib/generated/i18n.dart
i18nconfig.json
After you change or add any translations, run the update command to update
lib/generated/i18n.dart
to reflect your translation changes.
Removes an existing locale from your Flutter app. The command will ask you to pick a locale from the list of existing locales.
The following files will be removed:
i18n/<existing-locale>.json
and updated:
lib/generated/i18n.dart
i18nconfig.json
Sets the API code for the Google Translate API.
To obtain an API key, you need to have an account with the Google Cloud Platform:
- Go to: https://console.developers.google.com/apis/dashboard
- Select (or create) a project
- Click button "Enable API's and services" (on top)
- Search for "Cloud Translation API"
- Click "Enable"
- Once enabled, go to the "Credentials" (left side) section on your API overview
- Click "Create credential" (top bar)
- In de text "We'll help you set up the correct credentials. If you want you can skip this step and create an API key, client ID or service account.", choose the link "API key".
- Give it a name and click "Create"
You can copy the key now.
The following file will be updated:
i18nconfig.json
Generates and adds missing translations to i18n/<locale>.json
files, based on the translation keys and values in i18n/<default-locale>.json
.
When using this command, you don't have to manually add every translation key and translated value to all i18n/<locale>.json
files.
Use a simple key-value pair JSON format to define your translations.
{
"hello": "Hello"
}
In the above example "hello"
is the key for the translation value "Hello!"
.
Placeholders are automatically detected and are enclosed in curly brackets ({}
):
{
"greetTo": "Hello {name}"
}
Here, {name}
is a placeholder within the translation value for "greetTo"
.
Let's add some translations in i18n/en-US.json
:
{
"hello": "Hello!",
"greetTo": "Nice to meet you, {name}!"
}
After you run the update command, you will see that in lib/generated/i18n.dart
, a getter hello
and a method greetTo
were created:
class I18n implements WidgetsLocalizations {
const I18n();
static const GeneratedLocalizationsDelegate delegate =
const GeneratedLocalizationsDelegate();
static I18n of(BuildContext context) =>
Localizations.of<I18n>(context, WidgetsLocalizations);
@override
TextDirection get textDirection => TextDirection.ltr;
String get hello => "Hello!";
String greetTo(String name) => "Nice to meet you, ${name}!";
}
Using the generated I18n
class is showcased in the example below:
@override
Widget build(BuildContext context) {
final i18n = I18n.delegate;
return new MaterialApp(
localizationsDelegates: [
i18n
],
supportedLocales: i18n.supportedLocales,
localeResolutionCallback: i18n.resolution(fallback: new Locale("en", "US"))
// .. any other properties supported and required by your application
);
When translating something, simply call your translation like this:
I18n.of(context).hello
This returns a string you can direcly use in e.g. a Text() widget
Nesting is supported which allows you to hierarchically structure the translations.
{
"hello": "hello!",
"greeting": {
"formal": "Hello",
"informal": "Hi",
"placeholder": {
"formal": "Hello {name}",
"informal": "Hi {name}"
}
}
}
The above file will generate the following dart code
/// "hello!"
String get hello => "hello!";
/// "Hello"
String get greetingFormal => "Hello";
/// "Hi"
String get greetingInformal => "Hi";
/// "Hello ${name}"
String greetingPlaceholderFormal(String name) => "Hello ${name}";
/// "Hi ${name}"
String greetingPlaceholderInformal(String name) => "Hi ${name}";
Arrays of strings is supported too.
{
"hello": "hello!",
"greetings": [
"Hello",
"Hi"
]
}
The above file will generate the following dart code
/// "hello!"
String get hello => "hello!";
/// ["Hello", "Hi"]
List<String> get greetings => ["Hello", "Hi"];
Locale can be changed manually using static locale
parameter. To make application reload from anywhere in the app you can use static onLocaleChanged
callback:
import 'package:flutter_localizations/flutter_localizations.dart';
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final i18n = I18n.delegate;
@override
void initState() {
super.initState();
I18n.onLocaleChanged = onLocaleChange;
}
void onLocaleChange(Locale locale) {
setState(() {
I18n.locale = locale;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: app,
localizationsDelegates: [
i18n,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate // <-- needed for iOS
],
supportedLocales: i18n.supportedLocales,
home: <your home widget>
);
}
}
Calling this anywhere in your app will now change the app's language
I18n.onLocaleChanged(newLocale);
After you run the Create automagic translations-command, all translation files will be supplemented with the new translations.
For instance, if you added the greetTo
key from above, with this command your i18n/es-ES.json
goes from
{
"hello": "¡Hola!"
}
to
{
"hello": "¡Hola!",
"greetTo": "Encantado de conocerte, {name}!"
}
The run the update command will run automatically after any successful automagic translation, so you'll see that the Spanish WidgetsLocalizations are updated as:
class _I18n_es_ES extends I18n {
const _I18n_es_ES();
@override
String get hello => "¡Hola!";
@override
String greetTo(String name) => "Encantado de conocerte, ${name}!";
}
Starting form version 0.12.0 the module detects the text direction automatically - based on the language code.
If you want to change the automatic behaviour, you can change the text direction in the i18nconfig.json
file:
{
rtl: ["ar-AR"],
ltr: []
}
By default, your languages are not supported by iOS out of the box. To enable them, add the following to your your_project/ios/Runner/Info.plist
file:
<key>CFBundleLocalizations</key>
<array>
<string>en</string>
<string>es</string>
<string>ru</string>
</array>
(with en
, es
and ru
being examples for English, Spanish and Russian)
Your file should look something like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleLocalizations</key>
<array>
<string>en</string>
<string>es</string>
<string>ru</string>
</array>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
.
.
.
etc...
There are still some unresolved issues in Flutter when trying to use localization with the iOS simulators. For more information to address this issue check the flutter documentation.
Global widgets may throw exceptions informaing you that they cannot find any MaterialLocalizations (No MaterialLocalizations found.
). You need to install them manually and add their delegates to your localizationsDelegates.
in your pubspec.yaml:
dev_dependencies:
flutter_localizations:
sdk: flutter
in your app:
import 'package:flutter_localizations/flutter_localizations.dart';
return new MaterialApp(
localizationsDelegates: [
i18n,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate
...