i18n Implementation¶
KanjiIQ uses Flutter's built-in internationalization framework with ARB (Application Resource Bundle) files for UI localization and PostgreSQL JSONB for content localization.
UI Localization with ARB¶
Configuration¶
The localization system is configured in frontend/l10n.yaml:
ARB File Structure¶
Each language has an ARB file following ICU message format:
// lib/l10n/app_en.arb (template)
{
"@@locale": "en",
"appTitle": "KanjiIQ",
"studyButton": "Start Study",
"selectLanguage": "Select Language",
"selectLevel": "Select JLPT Level",
"cardCount": "{count} cards",
"@cardCount": {
"placeholders": {
"count": { "type": "int" }
}
},
"noConnection": "No internet connection. Using cached data.",
"showAllLanguages": "Show all 51 languages"
}
Code Generation¶
Running flutter gen-l10n generates:
app_localizations.dart— Abstract base class with all localized stringsapp_localizations_en.dart— English implementationapp_localizations_ja.dart— Japanese implementation- ... (51 generated files)
Usage in Flutter widgets:
// Access localized strings
Text(AppLocalizations.of(context)!.studyButton)
// With parameters
Text(AppLocalizations.of(context)!.cardCount(10))
Supported Locales Registration¶
Locales are registered in MaterialApp:
MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
locale: selectedLocale, // From LocalePreferences
)
Content Localization¶
Flashcard content (kanji meanings, vocabulary definitions) is stored as JSONB in PostgreSQL and served via the API:
graph LR
A[API Request<br/>?lang=pt] --> B[Backend]
B --> C[PostgreSQL<br/>JSONB lookup]
C --> D[Return meaning<br/>in Portuguese]
Translation Pipeline¶
New content is translated through the OpenAI API:
- Source content is authored in English
- Backend sends translation requests to OpenAI with context about JLPT level and usage
- Translations are stored in the JSONB column alongside existing translations
- Each language can be independently updated without affecting others
Self-hosted translation
The Kubernetes manifests include a LibreTranslate deployment (k8s/04-libretranslate-deployment.yaml) as an alternative to OpenAI. This provides fully self-hosted translation without external API dependencies, though quality varies by language pair.
UI vs Content Language¶
KanjiIQ allows the UI language and study language to differ:
- UI language: The language of buttons, labels, and navigation (e.g., French)
- Study language: The language for flashcard meanings (e.g., Portuguese)
A French-speaking user studying Japanese can have the interface in French while seeing flashcard meanings in Portuguese if they prefer.
Adding a New Language¶
To add a new (52nd) language:
- UI: Create
lib/l10n/app_XX.arbwith all translated strings - Content: Add translations to JSONB columns via the translation pipeline
- Locale config: Add the language code to relevant
locale_configsentries via the admin API - Build: Run
flutter gen-l10nto regenerate localization files
No schema migrations or backend code changes are required — the JSONB storage and ARB system are both designed for extensibility.