fix(mobile): wire i18n reactivity, translate all screens, sync language with server

- Add LocaleProvider + useLocale() hook with AsyncStorage persistence to mobile i18n
- Replace all hardcoded English strings in every screen with t() calls
- Add missing profile.settings/language keys to all 5 translation files (en/de/es/fr/it)
- Wrap app root in LocaleProvider; apply server preferred_language on login in AuthGuard
- Tab labels and header titles now re-render on language switch
- ProfileScreen: use useLocale() context, sync language to server via POST /api/i18n/language
- Backend: add preferred_language field to GET /api/mobile/whoami response
- Mobile API: add preferred_language to WhoAmIResponse type + setServerLanguage() method
- Tests: add test_whoami_returns_preferred_language and test_whoami_no_profile_preferred_language_is_null
- Docs: update MobileApp.md with language sync priority and whoami response format

Language priority: server preference > AsyncStorage > device locale > English fallback

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-03-20 09:08:08 +00:00
parent 0e6a4c5084
commit 3b5ca04ebc
18 changed files with 392 additions and 184 deletions
+6
View File
@@ -26,6 +26,7 @@ export interface WhoAmIResponse {
email: string | null;
avatar_url: string | null;
is_admin: boolean;
preferred_language: string | null;
}
export interface GenerateTokenResponse {
@@ -209,6 +210,11 @@ class DocuElevateAPI {
return this.request<WhoAmIResponse>("GET", "/api/mobile/whoami");
}
/** Sync the user's preferred UI language to the server. */
async setServerLanguage(lang: string): Promise<void> {
await this.request("POST", "/api/i18n/language", { body: { language: lang } });
}
// -------------------------------------------------------------------------
// Push notifications
// -------------------------------------------------------------------------