| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- 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<void> => {
- try {
- await AsyncStorage.setItem(LANGUAGE_PREFERENCE_KEY, language);
- } catch (error) {
- console.error('Failed to save language preference:', error);
- }
- };
- // 获取保存的语言偏好
- export const getLanguagePreference = async (): Promise<Language | null> => {
- 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<boolean> => {
- 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;
|