Make the translation fallback locale configurable (currently hardcoded to `en`)
- Dominant language
- PHP
- Stars
- 6.7k
- Forks
- 883
- Avg merge
- 15h 16m
- Merged PRs (30d)
- 73
Description
### Background
Flarum's translation fallback chain is hardcoded to English. When a string is missing in the active locale, the Symfony translator falls back to `en`:
```php
// src/Locale/LocaleServiceProvider.php
$translator->setFallbackLocales(['en']);
```
This is the single source of fallback for both the backend (`Flarum\Locale\Translator::getCatalogue` walks the fallback catalogue) and the frontend (`Flarum\Frontend\AddTranslations` pre-flattens the chain into the locale JS bundle via `array_replace`). `LocaleManager` itself holds no fallback config — it delegates entirely to this Symfony translator.
### Problem
Forums whose primary language is not English get a degraded experience when a translation is incomplete: missing keys surface in **English** rather than in a language closer to their audience. For example, a German-language community using a regional/derived locale (or a partially-translated extension) would prefer to fall back to standard German before English, not jump straight to English.
There is already a precedent for richer fallback in core: `LocaleManager::getJsFiles()`/`getCssFiles()` strip the region suffix (e.g. `de-formal` → `de`) for **asset** files — but this one-level, assets-only fallback does *not* apply to translation strings, which always go straight to `en`.
### Proposal
Make the fallback locale configurable, with `en` as the default (no behavior change unless configured).
Open questions for discussion:
1. **Config surface** — a new admin setting (e.g. `fallback_locale`), an `extend.php` extender, or both?
2. **Chain vs. single locale** — support an ordered chain (`['de', 'en']`) or just a single configurable fallback that always terminates in `en`?
3. **Automatic region fallback** — should `de-formal` automatically fall back to `de` then `en` for translation *strings* (mirroring the existing asset behavior), independent of an explicit setting?
4. **Cache invalidation** — the fallback is baked into the compiled frontend locale assets, so changing the setting must trigger an asset recompile / locale cache clear.
### Affected code
- `src/Locale/LocaleServiceProvider.php` — `setFallbackLocales(['en'])`
- `src/Locale/LocaleManager.php` — region-stripping asset fallback
- `src/Frontend/AddTranslations.php` — server-side flattening of the chain
Contributor guide
Research direction
Start by reading src/Locale/LocaleServiceProvider.php, src/Locale/LocaleManager.php, and src/Frontend/AddTranslations.php to trace the backend and frontend fallback paths. Resolve the proposed configuration surface, fallback-chain behavior, region fallback, and cache invalidation before implementation. Done means the configured fallback is applied consistently to server translations and compiled locale assets, with tests covering the default and configured behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, php, symfony
- Domain
- backend, frontend, internationalization
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100