Slang: A Type-safe i18n Solution for Flutter and Dart

Published on by Flutter News Hub

Slang: A Type-safe i18n Solution for Flutter and Dart

Slang is a robust internationalization (i18n) library for Flutter and Dart applications. It offers type-safe translations, eliminating typos and runtime errors. This comprehensive guide will delve into its key features, usage, and best practices.

Features

  • Type-safe Translations: Slang leverages Dart's type system to ensure translations are correct during compilation, preventing common i18n errors.
// File: strings.i18n.json
{ "hello": "Hello $name" }
final t = Translations.of(context); // (1) import 'package:my_app/i18n/strings.g.dart'
String a = t.hello(name: 'Tom'); // (2) get translation
  • String Interpolation: Slang supports multiple string interpolation modes, including Dart, braces, and double braces.
// Config file: slang.yaml
string_interpolation: double_braces
// File: strings.i18n.json
{ "hello": "Hello {{name}}" }
String a = t.hello(name: 'Tom'); // "Hello Tom"
  • RichText: Slang allows you to include styling in your translations.
// File: strings.i18n.json
{ "myText(rich)": "Welcome $name. Please click $!" }
Text.rich(t.myText(   // Show name in blue color
  name: TextSpan(text: 'Tom', style: TextStyle(color: Colors.blue)),
  tapHere: (text) => TextSpan( // Turn 'here' into a link
    text: text,
    style: TextStyle(color: Colors.blue),
    recognizer: TapGestureRecognizer()..onTap=() { print('tap'); },
  ),
));
  • Lists and Maps: Slang supports accessing translations via keys.
// File: strings.i18n.json
{ "niceList": [ "hello", "nice", [ "first item in nested list", "second item in nested list" ], { "wow": "WOW!", "ok": "OK!" } ] }
String a = t.niceList[1]; // "nice"
String b = t.niceList[2][0]; // "first item in nested list"
String c = t.niceList[3].ok; // "OK!"
  • Dynamic Keys / Flat Map: A one-dimensional map allows you to access all translations conveniently.
String a = t['myPath.anotherPath'];
String b = t['myPath.anotherPath.3']; // with index for arrays
String c = t['myPath.anotherPath'](name: 'Tom'); // with arguments
  • Changing Locale: Slang provides built-in support for locale changes.
// For Flutter only
LocaleSettings.useDeviceLocale(); // listen to device locale
final t = Translations.of(context); // rebuilds widgets on locale change
  • Pluralization: Slang supports pluralization based on predefined rules.
// File: strings.i18n.json
{ "someKey": { "apple": { "one": "I have $n apple.", "other": "I have $n apples." } } }
String a = t.someKey.apple(n: 1); // "I have 1 apple."
String b = t.someKey.apple(n: 2); // "I have 2 apples."
  • Custom Contexts / Enums: You can define custom contexts to differentiate between translations.
// File: strings.i18n.json
{ "greet(context=GenderContext)": { "male": "Hello Mr $name", "female": "Hello Ms $name" } }
enum GenderContext { male, female, }
String a = t.greet(name: 'Maria', context: GenderContext.female); // "Hello Ms Maria"

Configuration

Customization is possible via a dedicated configuration file (e.g., slang.yaml):

base_locale: fr
fallback_strategy: base_locale_empty_string
input_directory: lib/i18n
input_file_pattern: .i18n.json
output_directory: lib/i18n
output_file_name: translations.g.dart
output_format: single_file
locale_handling: true
flutter_integration: true
namespaces: false
translate_var: t
enum_name: AppLocale
class_name: Translations
translation_class_visibility: private
key_case: snake
key_map_case: camel
param_case: pascal
string_interpolation: double_braces
flat_map: false
translation_overrides: false
timestamp: true
statistics: true
maps: - error.codes - category - iconNames
pluralization: auto: cardinal default_parameter: n cardinal: - someKey.apple ordinal: - someKey.place
contexts: gender_context: enum: - male - female paths: - my.path.to.greet

Tools

  • Main Command:
dart run slang
  • Analyze Translations:
dart run slang analyze [--split] [--full] [--outdir=assets/i18n]
  • Clean Translations:
dart run slang clean [--outdir=assets/i18n]
  • Apply Translations:
dart run slang apply [--locale=fr-FR] [--outdir=assets/i18n]
  • Edit Translations:
dart run slang edit <type> <params...>
  • Outdated Translations:
dart run slang edit outdated a.b.c

Usage

  • Create JSON Files:
lib/     └── i18n/     └── strings_en.i18n.json     └── strings_de.i18n.json
  • Add to Flutter App:
import 'package:my_app/i18n/strings.g.dart';
  • Wrap App with TranslationProvider:
TranslationProvider(child: MyApp()),
  • Access Translations:
final t = Translations.of(context);
String a = t.hello;

Additional Resources

Flutter News Hub