Internationalization (i18n)
Audience: End users and non-technical stakeholders Last Updated: 2026-04-05 Version: 2.0.0
Overview
Llamafin is available in 18 languages, making your music library accessible to users around the world. The application supports runtime language switching, meaning you can change the language without restarting the app. Every label, message, button, and interface element is translated, providing a fully localized experience.
The translation system is designed to be smart and respectful of your preferences: it remembers your language choice, detects your browser language on first run, and loads translations efficiently in the background.
Key Concepts
1. Supported Languages
Llamafin supports the following languages:
| Code | Language | Code | Language |
|---|---|---|---|
en | English | pt | Português |
de | Deutsch | pl | Polski |
es | Español | sv | Svenska |
fr | Français | no | Norsk |
it | Italiano | da | Dansk |
ru | Русский | fi | Suomi |
zh | 中文 | is | Íslenska |
ja | 日本語 | tr | Türkçe |
nl | Nederlands | af | Afrikaans |
zu | isiZulu |
2. Translation Domains
The application's text content is organised into 29 translation domains, each covering a specific area of the app:
| Domain | Covers |
|---|---|
| App | Application-level strings, loading messages |
| Common | Shared strings used across multiple screens |
| Login | Login page labels, instructions, errors |
| Library | Album, artist, song, playlist, genre, folder browsing |
| Player | Playback controls, queue, player views |
| Settings | All settings labels and descriptions |
| Downloads | Download management strings |
| Audio | Audio engine and equalizer labels |
| Errors | Error messages and descriptions |
| Network | Network status messages |
| Search | Search page labels and results |
| Home | Home page sections and labels |
| Notifications | Push notification text |
| DJ | DJ mode and auto-play strings |
| Connect | Device pairing and P2P strings |
| Car UI | Android Auto / CarPlay interface |
| Visualiser | Audio visualizer labels |
| Lyrics | Lyrics display strings |
| And more | Auth, sessions, sleep timer, offline mode, etc. |
3. Language Detection
When you first open Llamafin, the app determines your preferred language using a priority system:
| Priority | Method | Behaviour |
|---|---|---|
| 1 | Your stored preference | If you previously selected a language, it is used |
| 2 | Browser language | If no stored preference, the app detects your browser's language and uses it (if supported) |
| 3 | English (default) | If your browser language is not supported, English is used |
One-time detection: Browser language detection happens only once. After the first run, your choice is saved and respected on all future launches.
4. Runtime Language Switching
You can change the language at any time from Settings > Language. When you select a new language:
- Translations for the new language are loaded immediately
- The entire interface updates without requiring an app restart
- Your choice is saved automatically for future sessions
5. Translation Files
Translation content is stored as JSON files organised by language and domain. Each language has 29 JSON files, one per domain. These files are loaded from the app's assets when you switch languages.
6. Interpolation
Some translated strings include placeholders that are filled in dynamically:
"Are you sure you want to delete {{itemName}} from your server?"--{{itemName}}is replaced with the actual item name"{{trackName}} is already playing."--{{trackName}}is replaced with the current track
This allows translations to include dynamic content while maintaining correct grammar and word order in every language.
7. Missing Translation Handling
If a translation key is missing in your selected language, the app displays the key name itself (e.g., login.TITLE). This is a safety measure to ensure the interface never shows blank text.
8. Translation Management
The project uses a sophisticated translation pipeline that supports multiple translation providers:
| Provider | Description |
|---|---|
| Local LLM | AI-powered translation using a local language model (default) |
| Google Translate | Google Cloud Translation API (optional) |
| DeepL | DeepL API (optional) |
This pipeline includes validation, manual edit tracking, and progress tracking to ensure translation quality.
Configuration
Language Settings
| Setting | Location | Description |
|---|---|---|
| Language | Settings > Language | Select your preferred language from the list of 18 supported languages |
Language Picker
The language selection page shows:
- Your current language at the top of the list
- All available languages sorted alphabetically (after your current language)
- Native language names (e.g., "Deutsch" not "German")
- Country flag icons for visual identification
When you tap a language, the interface switches immediately.
How It Works
Startup Language Selection
1. App launches
↓
2. Loads your saved settings from storage
↓
3. Checks: Do you have a stored language preference?
↓
├── Yes ──→ Use your stored language
│
└── No ──→ Detect browser language
↓
├── Supported? ──→ Use it and save to settings
│
└── Not supported? ──→ Use English and save to settings
↓
4. Loads all 29 translation files for the selected language (in parallel)
↓
5. Interface fully translated and ready to use
Language Switching
1. You select a new language in Settings > Language
↓
2. App immediately calls translate.use(newLanguage)
↓
3. 29 translation files loaded in parallel from assets
↓
4. Every translated element in the UI updates instantly
↓
5. Your language choice is saved to settings (debounced by 1 second)
↓
6. Next time you open the app, your choice is restored
Translation Loading
You switch to Spanish (es)
↓
App requests 29 translation files in parallel:
├── /assets/i18n/es/app.json
├── /assets/i18n/es/auth.json
├── /assets/i18n/es/login.json
├── /assets/i18n/es/library.json
├── ... (all 29 domains)
↓
All responses merged into a single translation object
↓
UI updates with Spanish text
Integration with Other Features
| Feature | i18n Integration | Description |
|---|---|---|
| Settings | Language preference storage | Your language choice saved in settings state |
| Alerts | Network alerts, confirmations | All alert banners and confirmation dialogues translated |
| Toast Messages | Success, error, info messages | All notification toasts translated |
| Login | Login page labels, errors | Authentication UI fully localized |
| Library | Album, artist, genre labels | All library browsing strings translated |
| Player | Queue, controls, views | Player interface strings translated |
| Downloads | Download status, progress | Download management strings translated |
| Media Session | Lock screen, Car UI | Media session metadata translated (artist, album names use original values) |
Error Handling & Reliability
Translation Load Failures
| Scenario | Behaviour |
|---|---|
| Translation file missing (404) | Key name displayed instead of translation |
| Malformed JSON file | Translation file skipped; other domains still load |
| Network unavailable during switch | Current language retained; no change applied |
Language Detection Issues
| Scenario | Behaviour |
|---|---|
| Browser language not supported | English used as fallback and saved to settings |
| Browser language detection fails | English used as default and saved to settings |
Missing Translation Keys
| Scenario | Behaviour |
|---|---|
| Key exists in English but not in your language | Key name displayed (e.g., settings.ABOUT_SECTION) |
| Key has typo in translation file | Typo displayed as-is |
Translation Validation
The project includes automated validation scripts that:
- Check for missing keys compared to the English source
- Detect extra keys that don't exist in the source
- Validate JSON structure
- Track manually edited keys that should not be auto-overwritten
Technical Specifications
| Specification | Value | Description |
|---|---|---|
| Supported Languages | 18 | Full language coverage |
| Translation Domains | 29 | Separate JSON files per language |
| Translation Engine | @ngx-translate/core | Runtime translation library |
| Loading Strategy | Parallel HTTP requests | All 29 files load simultaneously |
| Default Language | English | Fallback when no preference detected |
| Language Persistence | IndexedDB (via Settings) | Survives app restarts |
| Language Switch | Runtime (no reload) | Instant language change |
| Interpolation | {{param}} syntax | Dynamic content in translations |
| Missing Key Behaviour | Displays key string | Safety fallback for missing translations |
| Browser Detection | One-time only | Detected language saved to settings |
| Settings Save Debounce | 1 second | Batches rapid setting changes |
| Translation Scripts | LLM, Google, DeepL | Multiple translation providers available |
| Translation Validation | Automated CLI scripts | Key comparison, JSON validation, progress tracking |
Known Limitations
Right-to-Left (RTL) Languages
- No RTL support: The app does not support right-to-left languages such as Arabic or Hebrew. The interface layout is always left-to-right.
- RTL languages not in supported list: Arabic (
ar) and Hebrew (he) are not among the 18 supported languages.
Date, Number, and Currency Formatting
- No locale-specific formatting: The app relies on the browser's built-in
IntlAPIs for date, number, and currency formatting. These are not integrated with the i18n system. - Custom pipes: The app provides custom pipes for specific formatting (truncate, ticks-to-time, bytes, short numbers) but these are not locale-aware.
Pluralization
- Simple interpolation only: The translation system uses
{{param}}placeholders but does not support ICU message format or language-specific pluralization rules. - Manual handling: Plural forms (e.g., "1 song" vs "2 songs") must be handled manually in the application code, not through translation keys.
Translation Caching
- Browser cache only: Translation files are cached by the browser's HTTP cache but there is no specific service worker caching strategy for translations.
- No preloading: Translations are only loaded when you switch languages. There is no preloading of other languages in the background.
Compile-Time i18n
- Runtime only: The app uses runtime translation loading, not Angular's compile-time i18n. This means:
- A single build works for all languages
- No tree-shaking of unused languages (all translation files are included in the app)
- Translation files are fetched over HTTP at runtime
Related Documentation
- Settings System -- Language preference configuration
- Architecture Overview -- Overall application architecture
- Downloads System -- Offline content in different languages
- Offline Support -- Offline behaviour with language settings