Keyboard Shortcuts

j / kScroll down / up
ggScroll to top
GScroll to bottom
K / /Open search
?Show this help
EscClose search / help
n / NNext / previous section
hGo to landing
dGo to docs
:Command mode — type section name

Press ? or Esc to close

Deep Dives

Localization

Loaded once at startup, cached locally, refreshed from remote when available. UI always reads from context.l10n — it never knows where strings came from.

3-source priority: cache → remote → asset

StepSourceWhen used
1CacheAlways tried first — instant load, zero network wait
2RemoteCache miss or stale — fetches fresh strings (API / Firebase Remote Config)
3AssetFallback — bundled JSON, always available, never fails
lib/config/localization/sources/localization_sources.dart
Future<Map<String, String>> load(Locale locale) async {
  return await cache.load(locale)
      ?? await remote.load(locale)   // saves to cache on success
      ?? await asset.load(locale);   // always works
}

Asset format

assets/i18n/en.json
{
  "welcome": "Welcome, {name}!",
  "retry": "Try again",
  "commonError": "Something went wrong",
  "emptyStateTitle": "No data yet",
  "emptyStateDescription": "Pull down to refresh"
}

UI usage

lib/features/home/presentation/screens/home_screen.dart
Text(context.l10n.t('welcome', args: {'name': 'Amir'}))

// With TranslationKeys enum (type-safe)
Text(context.l10n.t(TranslationKeys.commonError))

Runtime flow

app start / locale change
LocalizationCubit.changeLocale()
LocalizationRepository.load()
cache? yes: use it
no: remote? yes: use + save cache
no: asset always works
AppLocalization emitted
MaterialApp rebuilds
all context.l10n calls updated
Constraints:
No static access (AppStrings.welcome — forbidden).
No code generation. No feature-owned translation files.
Formatting (plurals, dates) happens inside AppLocalization.t() only.
UI imports nothing from the localization layer directly.
sam's arch — A Pragmatic Flutter Architecture