feat(i18n): add Asturian (asturianu) as a language
Adds Asturianu, translated in full (345 strings), plus the wiring to make a minority language work end to end — the OS language picker is an unreliable way to reach it, so the in-app choice must be explicit and remembered. - Model Asturian as the real `ast` locale (honest, international-by-design), not a fake `es-AST` region — slang rejects a 3-letter region anyway. - Flutter ships no Material/Cupertino/intl localizations for `ast`, so map the framework chrome to Spanish (`materialLocaleFor`); the app's own text stays Asturian via slang. Fixes an "Invalid locale ast" crash when the auto-backup date was formatted with intl. - Persist the picked language in the keystore (LocaleStore) and restore it at startup so it survives restarts and wins over the device locale. - Settings: add the Asturianu tile; compare the full AppLocale so `es` and `ast` aren't both marked selected. Tests: LocaleStore round-trip, locale switch + Spanish-chrome fallback, and a regression for the intl date crash under Asturian.
This commit is contained in:
parent
beb29915d8
commit
9bf5c5cfbc
10 changed files with 695 additions and 15 deletions
45
apps/app_seeds/lib/services/locale_store.dart
Normal file
45
apps/app_seeds/lib/services/locale_store.dart
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import '../i18n/strings.g.dart';
|
||||
import '../security/secret_store.dart';
|
||||
|
||||
/// Remembers the language the user picked in Settings so it survives restarts.
|
||||
/// An empty/absent value means "follow the device language". Backed by the OS
|
||||
/// keystore (via [SecretStore]), like the rest of the app's small preferences —
|
||||
/// honouring "no plaintext at rest".
|
||||
///
|
||||
/// Why persist at all: the device language picker is an unreliable way to reach
|
||||
/// minority languages (Android often doesn't offer Asturian, and slang would
|
||||
/// fall back to the device default on every launch), so the choice made in-app
|
||||
/// must be remembered explicitly. Asturian itself is modelled as the `es-AST`
|
||||
/// locale (Spanish language + `AST` region), not `ast`, so Flutter's
|
||||
/// Material/Cupertino localizations — which don't ship `ast` — resolve it
|
||||
/// through Spanish instead of throwing. See [SettingsScreen] for the picker.
|
||||
class LocaleStore {
|
||||
LocaleStore(this._store);
|
||||
|
||||
final SecretStore _store;
|
||||
|
||||
static const _key = 'tane.locale';
|
||||
|
||||
/// The saved locale, or null when the user follows the device language.
|
||||
/// Unknown tags (e.g. a locale removed in a later build) also read as null.
|
||||
Future<AppLocale?> saved() async {
|
||||
final raw = await _store.read(_key);
|
||||
if (raw == null || raw.isEmpty) return null;
|
||||
for (final locale in AppLocale.values) {
|
||||
if (locale.name == raw) return locale;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Persists [locale] and applies it immediately.
|
||||
Future<void> setLocale(AppLocale locale) async {
|
||||
await _store.write(_key, locale.name);
|
||||
await LocaleSettings.setLocale(locale);
|
||||
}
|
||||
|
||||
/// Forgets the explicit choice and follows the device language from now on.
|
||||
Future<void> useDeviceLocale() async {
|
||||
await _store.write(_key, '');
|
||||
await LocaleSettings.useDeviceLocale();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue