Skip to content

Internationalization

AFib provides a simple i18n mechanism, because I could not figure out how to make Flutter's native mechanism work for third party libraries.

AFib Internationalization in Apps

You can hard-code primary-language strings by default

In your own app, you can hard code primarily language strings for prototyping purposes. If you use the theme's child methods, those strings will automatically be run through the translation mechanism. For example, in:

  rows.add(t.childText(text: "Hello World!"));

the string "Hello World!" will be run through the translation mechanism.

Per-Language Translation maps are defined in xxx_define_core.dart

Your xxx_define_core.dart file defines a map from your source translations to other languages with the primary.setTranslations call. You could easily move these calls into language-specific sub-files to support sending files out for translation.

For example, the file might contain:

  primary.setTranslations(AFUILocaleID.spanish, {
    ...
    "Hello World!": "¡Hola World!",
    ...
  });

You can formalize translations with AFTranslationID or AFWidgetID

If you want your app to use translations more formally, you can pass an AFTranslationID as the text value to the theme's child methods. The AFib Fixup Identifier(s) plug-in maintains XXXTranslationID values just as it does other ids.

For example, you might replace the code above with:

  rows.add(t.childText(text: XXXTranslationID.hello));

And the translation map with:

  primary.setTranslations(AFUILocaleID.spanish, {
    ...
    XXXTranslationID.hello: "¡Hola World!",
    ...
  });

Theme child... methods also allow you to omit the text parameter entirely, in which case AFib will use the AFWidgetID parameter as the translation source. You can specify an XXXWidgetID value in your setTranslations call in that case.

For example, you might replace the code above with:

  rows.add(t.childText(
    // note the wid parameter is specified here.
    wid: XXXWidgetID.textHello
    // and text: is omitted entirely.
  ));

And the translation map with:

  primary.setTranslations(AFUILocaleID.spanish, {
    ...
    XXXWidgetID.textHello: "¡Hola World!",
    ...
  });

You can explicitly declare values untranslated

If you are displaying a value that is not translated, like a name, you can use AFNotTranslated(name) to indicate that the value is intentionally not translated.

You can declare flexible translation templates

If you have text that contains inserted values, and those values must be inserted in different places in different languages, you can use AFTranslationTemplate, which is declared like this:

  rows.add(t.childText(
    text: AFTranslationTemplate(
      template: XXXTranslationID.templateDateFormat, 
      insertions: { 
        XXXTranslationID.insertDay: AFNotTranslated(dayValue),
        XXXTranslationID.insertMonth: AFNotTranslated(monthValue),
        XXXTranslationID.insertYear: AFNotTranslated(yearValue)
      }
    )
  ));

And then in your translations, you could define the template itself with differing insertion orders, like this:

  primary.setTranslations(AFUILocaleID.englishUS, {
    ...
    AFUITranslationID.templateDateFormat: "Month: ${XXXTranslationID.insertMonth} Day: ${XXXTranslationID.insertDay} Year: ${XXXTranslationID.insertYear}",
    ...
  });

  primary.setTranslations(AFUILocaleID.englishUK, {
    ...
    AFUITranslationID.templateDateFormat: "Year: ${XXXTranslationID.insertYear} Month: ${XXXTranslationID.insertMonth} Day: ${XXXTranslationID.insertDay}",
    ...
  });