import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; import * as Localization from 'expo-localization'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { resources } from './locales'; import { Language, SUPPORTED_LANGUAGES, defaultNS, Locale } from './types'; // AsyncStorage 键名 const LANGUAGE_PREFERENCE_KEY = '@app_language_preference'; // 获取设备区域设置信息 export const getDeviceLocale = (): Locale => { const locale = Localization.getLocales()[0]; return { languageCode: (locale.languageCode || 'zh-TW') as Language, languageTag: locale.languageTag || 'zh-TW', regionCode: locale.regionCode || undefined, // currencyCode: Localization.currency, // currencySymbol: Localization.currency || '$', // decimalSeparator: Localization.decimalSeparator || '.', // digitGroupingSeparator: Localization.digitGroupingSeparator || ',', textDirection: locale.textDirection || (locale.languageTag?.toLowerCase().includes('ar') ? 'rtl' : 'ltr'), measurementSystem: locale.regionCode ? 'metric' : 'us', temperatureUnit: locale.regionCode === 'US' ? 'fahrenheit' : 'celsius', }; }; // 获取设备语言 export const getDeviceLanguage = (): Language => { const deviceLocale = getDeviceLocale(); const deviceLanguage = deviceLocale.languageCode; // 检查是否支持设备语言 const supportedLanguageCodes = SUPPORTED_LANGUAGES.map(lang => lang.code); const isSupported = supportedLanguageCodes.includes(deviceLanguage); return isSupported ? deviceLanguage : 'zh-TW'; }; // 保存语言偏好 export const saveLanguagePreference = async (language: Language): Promise => { try { await AsyncStorage.setItem(LANGUAGE_PREFERENCE_KEY, language); } catch (error) { console.error('Failed to save language preference:', error); } }; // 获取保存的语言偏好 export const getLanguagePreference = async (): Promise => { try { return await AsyncStorage.getItem(LANGUAGE_PREFERENCE_KEY) as Language | null; } catch (error) { console.error('Failed to get language preference:', error); return null; } }; // 自定义语言检测器(适配 Expo) const languageDetector = { type: 'languageDetector' as const, async: true, init: () => {}, detect: async (callback: (lang: Language) => void) => { try { // 1. 先尝试获取保存的语言偏好 const savedLanguage = await getLanguagePreference(); if (savedLanguage) { callback(savedLanguage); return; } // 2. 使用设备语言 const deviceLanguage = getDeviceLanguage(); callback(deviceLanguage); } catch (error) { console.error('Language detection failed:', error); callback('zh-TW'); // 默认回退到繁体中文 } }, cacheUserLanguage: async (language: Language) => { await saveLanguagePreference(language); }, }; // i18n 初始化配置 export const initI18n = async () => { await i18n .use(languageDetector) .use(initReactI18next) .init({ // compatibilityJSON: 'v3', // 重要:解决 React Native 中的复数问题 resources, fallbackLng: 'zh-TW', defaultNS, // 调试配置 debug: __DEV__, // 插值配置 interpolation: { escapeValue: false, // React 已经处理了转义 }, // React 配置 react: { useSuspense: false, // Expo/React Native 中建议关闭 }, // 语言检测配置 detection: { order: ['localStorage', 'navigator'], caches: ['localStorage'], }, // 支持的语言 supportedLngs: SUPPORTED_LANGUAGES.map(lang => lang.code), // 不加载所有语言,按需加载 partialBundledLanguages: true, ns: [defaultNS], }); return i18n; }; // 语言切换函数 export const changeLanguage = async (language: Language): Promise => { try { await i18n.changeLanguage(language); await saveLanguagePreference(language); return true; } catch (error) { console.error('Language change failed:', error); return true; } }; // 获取当前语言 export const getCurrentLanguage = (): Language => { return (i18n.language || 'zh-TW') as Language; }; // 获取当前区域设置信息 export const getCurrentLocale = (): Locale => { return getDeviceLocale(); }; // 监听语言变化 export const onLanguageChanged = (callback: (language: Language) => void) => { i18n.on('languageChanged', callback); return () => i18n.off('languageChanged', callback); }; // 初始化 i18n initI18n(); export default i18n;