i69n 0.5.0

  • Readme
  • Changelog
  • Example
  • Installing
  • 82

Simple internationalization (i18n) package for Dart and Flutter.

Build Status pub package open source


  • AngularDart
  • Flutter hot reload
  • deferred loading of translations

Overview #

Turn this YAML file:


  save: Save
  load: Load
  welcome(String name): "Hello $name!"
  logout: Logout

Into these generated Dart classes:

class ExampleMessages {
    const ExampleMessages();
    ButtonExampleMessages get button => ButtonExampleMessages(this);
    UsersExampleMessages get users => UsersExampleMessages(this);
class ButtonExampleMessages {
    final ExampleMessages _parent;
    const ButtonExampleMessages(this._parent);
    String get save => "Save";
    String get load => "Load";
class UsersExampleMessages {
    final ExampleMessages _parent;
    const UsersExampleMessages(this._parent);
    String get logout => "Logout";
    String welcome(String name) => "Hello $name!";

... and use them in your code - plain and simple.

ExampleMessages m = ExampleMessages();
// outputs: Hello World!

Package is an extension (custom builder) for build_runner (Dart standard for source generation) and it can be used with Flutter, AngularDart or any other type of Dart project.

i69n: 51 points simpler than your standard i18n! #

Motivation and goals #

  • The official Dart/Flutter approach to i18n seems to be ... complicated and kind of ... heavyweight.
  • I would like my messages to be checked during compile time. Is that message really there?
  • Key to the localized message shouldn't be just some arbitrary String, it should be a getter method!
  • And if the message takes some parameters, the method should take those parameters!
  • I like to bundle messages into thematic groups, the i18n tool should support that and help me with it.
  • Dart has awesome string interpolation, I want to leverage that!
  • I like build_runner and code generation.
  • I love the name. i69n is hilarious.

Solution #

Write your messages into a YAML file:

exampleMessages.i69n.yaml (default messages):

  ok: OK
  done: DONE
  create: Create invoice
  delete: Delete invoice

Write your translations into other YAML files:

exampleMessages_cs.i69n.yaml (_cs = Czech translation)

  done: Hotovo
  create: Vytvořit fakturu
  delete: Smazat fakturu

... run the webdev tool, or build_runner directly, and use your messages like this:

ExampleMessages m = ExampleMessages();
print(m.generic.ok); // output: OK
print(m.generic.done); // output: DONE

m = ExampleMessages_cs();
print(m.generic.ok); // output: OK
print(m.generic.done); // output: Hotovo

Parameters and pluralization #

The implementation is VERY straightforward, which allows you to do all sorts of crazy stuff:

  create: Create invoice
  delete: Delete invoice
  help: "Use this function
  to generate new invoices and stuff.
  count(int cnt): "You have created $cnt ${_plural(cnt, one:'invoice', many:'invoices')}."
  _apples(int cnt): "${_plural(cnt, one:'apple', many:'apples')}"
  count(int cnt): "You have eaten $cnt ${_apples(cnt)}."

Now see the generated classes:

class ExampleMessages {
    const ExampleMessages();
    InvoiceExampleMessages get invoice => InvoiceExampleMessages(this);        
    ApplesExampleMessages get apples => ApplesExampleMessages(this);
class InvoiceExampleMessages {
    final ExampleMessages _parent;
    const InvoiceExampleMessages(this._parent);
    String get create => "Create invoice";
    String get help => "Use this function to generate new invoices and stuff. Awesome!";
    String get delete => "Delete invoice";
    String count(int cnt) => "You have created $cnt ${_plural(cnt, one:'invoice', many:'invoices')}.";

class ApplesExampleMessages {
    final ExampleMessages _parent;
    const ApplesExampleMessages(this._parent);
    String _apples(int cnt) => "${_plural(cnt, one:'apple', many:'apples')}";
    String count(int cnt) => "You have eaten $cnt ${_apples(cnt)}.";

See how you can reuse the pluralization of _apples(int cnt)? 💯!!!

There are three functions you can use in your message:

String _plural(int count, {String zero, String one, String two, String few, String many, String other})

String _cardinal(int count, {String zero, String one, String two, String few, String many, String other})

String _ordinal(int count, {String zero, String one, String two, String few, String many, String other})

_plural and _cardinal do the same. I just felt that _plural is a little bit less scary name and in most cases that's the one you need.

We need only two forms of the word "apple" in English. "Apple" (one) and "apples" (many). But in Czech, we need three:

  _apples(int cnt): "${_plural(cnt, one:'jablko', few: 'jablka', many:'jablek')}"

See also:

How to use generated classes #

How to decide what translation to use (ExampleMessages_cs?, ExampleMessages_hu?) is up to you. The package simply generates message classes, that's all.

import 'exampleMessages.i69n.dart';
import 'exampleMessages_cs.i69n.dart' deferred as cs;

void main() async {
  ExampleMessages m = ExampleMessages();

  await cs.loadLibrary();
  m = cs.ExampleMessages_cs(); // see? ExampleMessages_cs extends ExampleMessages

Where and how to store instances of these message classes - again, up to you. I would consider ScopedModel for Flutter and registering messages instance into dependency injection in AngularDart.

But in this case a singleton would be acceptable also.

Dynamic access using String keys #

It's still useful to access your messages using the String keys in some cases. For example when the key of the message is composed dynamically at runtime, maybe like this:

var vehicleTypeMessageKey = "VehicleType.${data['type']'}";

You can access your messages like this:

print("static:  "+m.generic.ok);
print("dynamic: "+m.generic['ok']);
print("or even: "+m['generic.ok']);

How to use with Flutter #

Create YAML file with your messages, for example:


Add build_runner as a dev_dependency and i69n as a dependency to pubspec.yaml:

    sdk: flutter
  i69n: any

  build_runner: any
    sdk: flutter

Open a terminal and in the root of your Flutter project run:

flutter packages pub run build_runner watch

... and keep it running. Your message classes will appear next to YAML files and will be rebuilt automatically each time you change the source YAML.

For one-time (re)build of your messages run:

flutter packages pub run build_runner build

Import generated messages and use them:

import 'packages:my_app/messages/foo.i69n.dart'


Foo m = Foo();
return Text(m.bar);

How to use with AngularDart #

You are probably using webdev tool already, so you just need to add i69n as a dependency and that's all.

Custom pluralization #

The package can correctly decide between 'one', 'few', 'many', etc. only for English and Czech (for now). But you can easily plug your own language, see example/main.dart and Czech and English implementation.

If you implement support for your language, please let me know, I'll gladly embed it into the package.


  • Current limitation: default language must be english
  • TODO: support custom imports

Example #

See example. Clone the package repository (https://github.com/fnx-io/i69n) and run:

webdev serve example:8080


pub run build_runner serve example:8080

Now open the browser http://localhost:8080/ and watch the dev tools console.

Credits #

Created by https://fnx.io.

0.5.0 #

  • even more pedantic friendly - resolved all warnings

0.4.0 #

  • pedantic friendly - both project source files and generated messages

0.3.0 #

  • more benevolent dependencies (for web use angular: 5.3.1)

0.2.0 #

  • Upgrade to Dart 2.5.1 and build_runner 1.7.1
  • added possibility to access messages with string keys, not only Dart identifiers (i.e. m['generic.ok'])
  • output is formatted with Dartfmt

0.1.0 #

  • Seems good, let's move up

0.0.2 #

  • More README

0.0.1 #

  • Initial version, created by Stagehand
  • Just getting started.


// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:i69n/i69n.dart' as i69n;

import 'exampleMessages.i69n.dart';
import 'exampleMessages_cs.i69n.dart' deferred as cs;

void main() async {
  print('Hello from i69n!');
  print('Some english:');
  var m = ExampleMessages();

  print('Asynchronous load of Czech messages:');
  await cs.loadLibrary();
  print('Some czech:');
  m = cs.ExampleMessages_cs();
  print(m.generic.ok); // inherited from default

  print('Access messages at runtime, with plain old string keys');
  print('Static:  ' + m.generic.ok);
  print('Dynamic: ' + m.generic['ok']);
  print('Or even: ' + m['generic.ok']);

  // Override plurals for Czech or register support for your own language:
  i69n.registerResolver('cs', (int count, i69n.QuantityType type) {
    if (type == i69n.QuantityType.cardinal && count == 1)
      return i69n.QuantityCategory.one;
    return i69n.QuantityCategory.other;

  // See:
  // http://cldr.unicode.org/index/cldr-spec/plural-rules
  // https://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:

  i69n: ^0.5.0

2. Install it

You can install packages from the command line:

with pub:

$ pub get

with Flutter:

$ flutter pub get

Alternatively, your editor might support pub get or flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:

import 'package:i69n/i69n.dart';
Describes how popular the package is relative to other packages. [more]
Code health derived from static analysis. [more]
Reflects how tidy and up-to-date the package is. [more]
Weighted score of the above. [more]
Learn more about scoring.

We analyzed this package on Jan 19, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.0
  • pana: 0.13.4


Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
build ^1.2.0 1.2.2
build_config ^0.4.1 0.4.1+1
dart_style >=1.2.0 <2.0.0 1.3.3
yaml ^2.2.0 2.2.0
Transitive dependencies
_fe_analyzer_shared 1.0.3
analyzer 0.39.4
args 1.5.2
async 2.4.0
charcode 1.1.2
checked_yaml 1.0.2
collection 1.14.12
convert 2.1.1
crypto 2.1.4
csslib 0.16.1
glob 1.2.0
html 0.14.0+3
js 0.6.1+1
json_annotation 3.0.1
logging 0.11.4
meta 1.1.8
node_interop 1.0.3
node_io 1.0.1+2
package_config 1.1.0
path 1.6.4
pub_semver 1.4.2
pubspec_parse 0.1.5
source_span 1.6.0
string_scanner 1.0.5
term_glyph 1.1.0
typed_data 1.1.6
watcher 0.9.7+13
Dev dependencies
build_runner ^1.7.1
build_web_compilers ^2.5.2
pedantic ^1.8.0 1.9.0
test ^1.0.0