l10n_flow

English | 中文文档

Collaborative localization for Flutter. Sync a published Google Sheet to JSON, validate translation quality, and consume the resources through a lightweight runtime manager.

Features

  • Public Google Sheets TSV source; no service account required
  • sync, validate, and watch CLI commands
  • JSON output with safe stale-file cleanup
  • Duplicate-key, empty-value, and placeholder validation
  • Runtime locale switching and locale resolution
  • Named and ordered interpolation
  • Remote translation patches and global placeholders
  • Missing-key stream, .tr extensions, L10nBuilder, and TextTr

Install

dependencies:
  flutter_localizations:
    sdk: flutter
  l10n_flow: ^0.1.0

Configure

Publish a Google Sheet as TSV. A typical sheet looks like:

Key English Simplified Chinese Notes
app.title My app 我的应用 App title
welcome Hello {name} 你好,{name} Greeting

The published URL must use output=tsv. CSV URLs such as output=csv are not supported by the current Google Sheets source.

Add a root-level section to your app's pubspec.yaml:

l10n_flow:
  source:
    type: google_sheets_tsv
    url: https://docs.google.com/spreadsheets/d/e/YOUR_ID/pub?output=tsv
  # Generated JSON directory, relative to the directory where the command runs.
  output: assets/l10n
  # 1-based row containing Key and language column headers.
  # Use 2 when row 1 is a document title and row 2 contains the headers.
  header_row: 1
  # Exact column header containing translation keys.
  key_header: Key
  # Non-language columns that should not generate locale files.
  exclude_columns:
    - Notes
  # Sheet column header -> generated JSON filename (without .json).
  languages:
    English: en
    Simplified Chinese: zh_cn
    Vietnamese: vi

The keys under languages must exactly match the language column headers in the sheet. English header names are recommended for shared demo projects.

Register the generated directory as a Flutter asset:

flutter:
  assets:
    - assets/l10n/

CLI

dart run l10n_flow sync
dart run l10n_flow validate
dart run l10n_flow watch

Use another project configuration file when needed:

dart run l10n_flow sync --config path/to/pubspec.yaml

sync returns exit code 2 when quality warnings are found, making it suitable for CI checks.

Flutter runtime

const english = AppLocale(
  value: Locale('en'),
  assetPath: 'assets/l10n/en.json',
);
const chinese = AppLocale(
  value: Locale('zh', 'CN'),
  assetPath: 'assets/l10n/zh_cn.json',
);

await L10nManager().init(
  defaultLocale: english,
  locales: const [english, chinese],
  placeholders: const {'{brand}': 'Acme'},
);

Read translations:

Text('app.title'.tr);
Text('welcome'.trMap({'name': 'Aiwen'}));
Text('score'.trValues([2, 1]));

Rebuild automatically after a locale change:

L10nBuilder(
  builder: (context, l10n) => MaterialApp(
    locale: l10n.locale.value,
    supportedLocales: L10nManager().supportedLocales,
    localizationsDelegates: GlobalMaterialLocalizations.delegates,
    home: const HomePage(),
  ),
);

Import GlobalMaterialLocalizations from package:flutter_localizations/flutter_localizations.dart. Wrapping the root MaterialApp lets both application translations and Flutter's Material and Cupertino widgets react to locale changes.

Convenience widgets and rich text:

TextTr('welcome', named: {'name': 'Aiwen'});

'demo.rich_message'.rich(
  defaultStyle: const TextStyle(color: Colors.black),
  named: {
    'terms': 'Terms of Service',
    'privacy': 'Privacy Policy',
  },
  styleMap: {
    'terms': const TextStyle(color: Colors.blue),
    'privacy': const TextStyle(color: Colors.blue),
  },
);

Switch locales:

await L10nManager().change(chinese);

Apply server-side patches without replacing bundled JSON:

await L10nManager().merge({
  chinese: {'campaign.title': '限时活动'},
});

Listen for missing keys:

L10nManager().missingKeyStream.listen(logMissingTranslation);

Runnable example

The example/ directory is a complete Flutter application for Android, iOS, web, macOS, Linux, and Windows. It demonstrates English, Simplified Chinese, and Vietnamese locale switching against a published demo Google Sheet.

cd example
flutter pub get
dart run l10n_flow sync
flutter run

Configuration reference

Field Required Description
source.url Yes Published TSV URL
output Yes JSON output directory, resolved relative to the command's working directory
languages Yes Exact sheet language header to JSON filename mapping; values omit .json
header_row No 1-based row containing the Key and language headers, not the first translation row; defaults to 1
key_header No Exact Key column header; auto-detects Key or ID when omitted
exclude_columns No Exact non-language column headers to ignore
pretty_json No Pretty-print JSON; defaults to true
delete_stale_json No Delete obsolete JSON locale files; defaults to true
watch_interval_seconds No Watch polling interval; defaults to 5

For example, given this sheet:

Row 1: L10n Flow Demo
Row 2: Key | English | Simplified Chinese | Vietnamese
Row 3: app.title | L10n Flow Demo | L10n Flow 示例 | Demo L10n Flow

set header_row: 2, because row 2 contains the column headers. Translation data starts on the following row.

License

MIT

Libraries

l10n_flow