locale_chain 0.1.0 copy "locale_chain: ^0.1.0" to clipboard
locale_chain: ^0.1.0 copied to clipboard

Smart locale fallback chains for Flutter. Your pt-BR users deserve pt-PT, not English.

LocaleChain for Flutter #

Smart locale fallback chains for Flutter — because pt-BR users deserve pt-PT, not English.

The Problem #

Flutter's i18n ecosystem has zero support for configurable locale fallback chains. Every major package — easy_localization, gen-l10n, slang, flutter_i18n — only supports a single fallback locale.

When pt-BR translations are missing a key, the system jumps straight to English. Your users see English when a perfectly good Portuguese translation exists in pt-PT.

The Solution #

One line change. Zero migration. Your existing context.tr('key') calls just work.

LocaleChain intercepts at the asset-loading layer and deep-merges translations from a configurable fallback chain. When a key is missing in pt-BR, it checks pt-PT, then pt, then en — before giving up.

Installation #

dependencies:
  locale_chain: ^0.1.0

Quick Start #

import 'package:locale_chain/locale_chain.dart';
import 'package:locale_chain/easy_localization.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await EasyLocalization.ensureInitialized();
  LocaleChain.configure();  // 1. Configure chains

  runApp(
    EasyLocalization(
      supportedLocales: [Locale('en'), Locale('pt', 'BR'), Locale('pt', 'PT')],
      path: 'assets/translations',
      assetLoader: LocaleChainAssetLoader(  // 2. Swap asset loader
        baseLoader: RootBundleAssetLoader(),
      ),
      fallbackLocale: Locale('en'),
      child: MyApp(),
    ),
  );
}

// In widgets — unchanged
Text(context.tr('greeting'))

That's it. A pt-BR user will now see pt-PT translations when pt-BR is missing a key.

Custom Configuration #

Default (zero config) #

LocaleChain.configure();

Uses all built-in fallback chains. Covers Portuguese, Spanish, French, German, Italian, Dutch, Norwegian, and Malay regional variants.

With overrides (merge with defaults) #

LocaleChain.configure(
  fallbacks: {'pt-BR': ['pt-PT', 'pt']},
);

Your overrides replace matching keys in the default map. All other defaults remain.

Full custom (replace defaults) #

LocaleChain.configure(
  fallbacks: {
    'pt-BR': ['pt-PT', 'pt'],
    'es-MX': ['es-419', 'es'],
  },
  mergeDefaults: false,
);

Only the chains you specify will be active. No defaults.

Standalone Usage #

Don't use easy_localization? Use mergedMessages() directly with any Map-based i18n system:

LocaleChain.configure();

final messages = await LocaleChain.mergedMessages(
  locale: Locale('pt', 'BR'),
  loader: (locale) async {
    final tag = localeToTag(locale);
    final json = await rootBundle.loadString('assets/i18n/$tag.json');
    return jsonDecode(json);
  },
);

Default Fallback Map #

Portuguese #

Locale Fallback Chain
pt-BR pt-PT -> pt -> (default)
pt-PT pt -> (default)

Spanish #

Locale Fallback Chain
es-419 es -> (default)
es-MX es-419 -> es -> (default)
es-AR es-419 -> es -> (default)
es-CO es-419 -> es -> (default)
es-CL es-419 -> es -> (default)
es-PE es-419 -> es -> (default)
es-VE es-419 -> es -> (default)
es-EC es-419 -> es -> (default)
es-GT es-419 -> es -> (default)
es-CU es-419 -> es -> (default)
es-BO es-419 -> es -> (default)
es-DO es-419 -> es -> (default)
es-HN es-419 -> es -> (default)
es-PY es-419 -> es -> (default)
es-SV es-419 -> es -> (default)
es-NI es-419 -> es -> (default)
es-CR es-419 -> es -> (default)
es-PA es-419 -> es -> (default)
es-UY es-419 -> es -> (default)
es-PR es-419 -> es -> (default)

French #

Locale Fallback Chain
fr-CA fr -> (default)
fr-BE fr -> (default)
fr-CH fr -> (default)
fr-LU fr -> (default)
fr-MC fr -> (default)
fr-SN fr -> (default)
fr-CI fr -> (default)
fr-ML fr -> (default)
fr-CM fr -> (default)
fr-MG fr -> (default)
fr-CD fr -> (default)

German #

Locale Fallback Chain
de-AT de -> (default)
de-CH de -> (default)
de-LU de -> (default)
de-LI de -> (default)

Italian #

Locale Fallback Chain
it-CH it -> (default)

Dutch #

Locale Fallback Chain
nl-BE nl -> (default)

Norwegian #

Locale Fallback Chain
nb no -> (default)
nn nb -> no -> (default)

Malay #

Locale Fallback Chain
ms-MY ms -> (default)
ms-SG ms -> (default)
ms-BN ms -> (default)

How It Works #

  1. configure() stores the fallback chain configuration in memory.
  2. LocaleChainAssetLoader wraps your existing AssetLoader (e.g., RootBundleAssetLoader).
  3. When easy_localization requests translations for a locale, the adapter loads translations for every locale in the chain.
  4. Translations are deep-merged from least specific (default) to most specific (current locale). Missing keys are filled from the next locale in the chain.
  5. easy_localization receives a complete Map with no missing keys — chain fallback is invisible to the rest of your app.

FAQ #

Is this safe for production? Yes. The adapter wraps easy_localization's AssetLoader interface — a stable, public API. No monkey-patching or reflection.

Performance impact? Negligible. Merged translations are cached per locale. The chain loading only happens once per locale (on first access or locale change).

Does it work with nested translation keys? Yes. The deep merge is recursive — nested Maps are merged at every level.

Can I use a non-English default locale? Yes. Pass defaultLocale to configure():

LocaleChain.configure(defaultLocale: 'es');

Can I deactivate it? Yes. Call LocaleChain.reset() to clear configuration. The LocaleChainAssetLoader will pass through to the base loader without chain merging.

Minimum Flutter version? Flutter 3.10+ (Dart 3.0+).

Contributing #

  • Open issues for bugs or feature requests.
  • PRs welcome, especially for adding new locale fallback chains.
  • Run flutter test for unit tests.
  • Run flutter analyze for static analysis.

License #

MIT License - see LICENSE file.

Built by i18nagent.ai

0
likes
160
points
0
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Smart locale fallback chains for Flutter. Your pt-BR users deserve pt-PT, not English.

Repository (GitHub)
View/report issues

Topics

#i18n #localization #locale #fallback #easy-localization

License

MIT (license)

Dependencies

easy_localization, flutter

More

Packages that depend on locale_chain