Bug: User mit iOS-Sprache=Arabisch sah App auf Englisch wenn Localization.getLocales() auf seinem Setup nicht zuverlässig 'ar' zurückgab (iOS-Region≠Sprache, App-Override etc). Fix: bei sign-in (init() initial-getSession + onAuthStateChange für SIGNED_IN events) wird session.user.user_metadata.locale gelesen. Wenn AsyncStorage @rebreak/language NOCH NICHT gesetzt ist (User hat keine explicit Choice gemacht) → silent apply der server-locale (inkl. RTL-flip, KEIN Restart-Alert). Respektiert User-Choice: wenn AsyncStorage gefüllt ist (z.B. User hat manuell in Settings gewechselt), bleibt das gewinnen.
93 lines
2.8 KiB
TypeScript
93 lines
2.8 KiB
TypeScript
import { Alert } from 'react-native';
|
|
import { I18nManager } from 'react-native';
|
|
import { create } from 'zustand';
|
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
import i18n from '../lib/i18n';
|
|
|
|
export type AppLanguage = 'de' | 'en' | 'fr' | 'ar';
|
|
|
|
const STORAGE_KEY = '@rebreak/language';
|
|
|
|
type LanguageState = {
|
|
language: AppLanguage;
|
|
setLanguage: (lang: AppLanguage) => Promise<void>;
|
|
init: () => Promise<void>;
|
|
};
|
|
|
|
function applyRTL(lang: AppLanguage) {
|
|
const isRTL = lang === 'ar';
|
|
if (I18nManager.isRTL !== isRTL) {
|
|
I18nManager.forceRTL(isRTL);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
export const useLanguageStore = create<LanguageState>((set) => ({
|
|
language: 'en',
|
|
|
|
init: async () => {
|
|
const stored = await AsyncStorage.getItem(STORAGE_KEY);
|
|
if (stored === 'de' || stored === 'en' || stored === 'fr' || stored === 'ar') {
|
|
applyRTL(stored);
|
|
await i18n.changeLanguage(stored);
|
|
set({ language: stored });
|
|
} else {
|
|
// Kein expliziter Wert gespeichert — i18n.ts hat bereits via deviceLocale
|
|
// initialisiert (Localization.getLocales()). NICHT auf 'en' overriden.
|
|
const detected =
|
|
i18n.language === 'de'
|
|
? 'de'
|
|
: i18n.language === 'fr'
|
|
? 'fr'
|
|
: i18n.language === 'ar'
|
|
? 'ar'
|
|
: 'en';
|
|
applyRTL(detected as AppLanguage);
|
|
set({ language: detected as AppLanguage });
|
|
}
|
|
},
|
|
|
|
setLanguage: async (lang) => {
|
|
await AsyncStorage.setItem(STORAGE_KEY, lang);
|
|
await i18n.changeLanguage(lang);
|
|
set({ language: lang });
|
|
const needsReload = applyRTL(lang);
|
|
if (needsReload) {
|
|
Alert.alert(
|
|
i18n.t('settings.rtl_restart_title'),
|
|
i18n.t('settings.rtl_restart_body'),
|
|
);
|
|
}
|
|
},
|
|
}));
|
|
|
|
// Auto-sync language from session.user.user_metadata.locale beim Sign-In.
|
|
// Wenn AsyncStorage @rebreak/language LEER ist (kein explicit user-choice)
|
|
// und Server-side metadata.locale gesetzt — silent apply (kein Restart-Alert).
|
|
// Respektiert User-Choice: AsyncStorage gewinnt immer wenn gesetzt.
|
|
export async function syncLanguageFromUserMetadata(
|
|
user: { user_metadata?: { locale?: string | null } | null } | null,
|
|
): Promise<void> {
|
|
if (!user) return;
|
|
const raw = user.user_metadata?.locale;
|
|
if (!raw) return;
|
|
const short = String(raw).split('-')[0].toLowerCase();
|
|
const valid: AppLanguage[] = ['de', 'en', 'fr', 'ar'];
|
|
if (!(valid as readonly string[]).includes(short)) return;
|
|
const lang = short as AppLanguage;
|
|
|
|
const stored = await AsyncStorage.getItem(STORAGE_KEY);
|
|
if (stored) return; // explicit user-choice wins
|
|
|
|
if (i18n.language === lang) {
|
|
await AsyncStorage.setItem(STORAGE_KEY, lang);
|
|
return;
|
|
}
|
|
|
|
await AsyncStorage.setItem(STORAGE_KEY, lang);
|
|
await i18n.changeLanguage(lang);
|
|
applyRTL(lang);
|
|
useLanguageStore.setState({ language: lang });
|
|
}
|