The Startup
Published in

The Startup

Flutter: i18n Made Easy

At the time of writing, the “basic” i18n approach in Flutter is complicated and heavyweight. That’s why I decided to start my own library: fast_i18n

Step 1: Add dependencies

Please don’t forget to include the build_runner. You will need that because the JSON files will be translated at compile-time!

It is recommended to add fast_i18n to dev_dependencies.

# pubspec.yaml

build_runner: any
fast_i18n: ^5.11.0

Step 2: Write JSON files

Now lets add some strings. Just make sure that they are inside the lib directory and all in one common package like lib/i18n/strings.i18n.json

Default Locale

File: strings.i18n.json{
"hello": "Hello $name",
"save": "Save",
"login": {
"success": "Logged in successfully",
"fail": "Logged in failed"

German Locale

File: strings_de.i18n.json{
"hello": "Hallo $name",
"save": "Speichern",
"login": {
"success": "Login erfolgreich",
"fail": "Login fehlgeschlagen"

Step 3: Generate the dart code

This will translate the .json files into .dart files.

flutter pub run fast_i18n


flutter pub run build_runner build --delete-conflicting-outputs

Step 4: Initialize the right language

Users expect that your app shows the right language at the start of the app.

There are 2 methods to set the locale: LocaleSettings.useDeviceLocale() and LocaleSettings.setLocaleRaw(String locale) . It is up to you how you implement it.

a) use device locale

void main() {

b) use specific locale

void initState() {
String storedLocale = loadFromStorage(); // your logic here

Step 4b: iOS-only

There is one small change needed for iOS users:

File: ios/Runner/Info.plist<key>CFBundleLocalizations</key>

Step 5: Finally use your translations!

That’s all! In the generated dart file you will see the famous t variable.

While most libraries goes for the t('somekey.anotherKey.blabla') solution with a plain string, the approach of fast_i18n is 100% safe, and it has nice autocompletion. Let’s try this out:

import 'package:my_app/i18n/strings.g.dart'; // import

String a = t.login.success; // plain
String b = t.hello(name: 'Tom'); // with argument
String c = t.step[3]; // with index (for arrays)
String d = t.type['WARNING']; // with key (for maps)

// advanced
TranslationProvider(child: MyApp()); // wrap your app
// [...]
final t = Translations.of(context); // get translation instance
String translateAdvanced = t.hello(name: 'Tom');

Supported Features

  • String Interpolation, e.g. t.hello(name: 'Tom')
  • Pluralization, e.g. t.apples(count: 3)
  • Gender, e. t.greet(context: Gender.male)
  • Arrays, e.g. t.step[2]
  • Maps, e.g.['LEADER']
  • Fully Dynamic, e.g. t['homeScreen.title']

More info at



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store