5月28日 05:25

How to implement internationalization (i18n) in Expo apps? What are recommended libraries?

Internationalization (i18n) of Expo apps is an important feature for serving global users. Expo supports multiple internationalization solutions, enabling developers to easily implement multi-language support.

Internationalization Library Selection:

  1. i18next

The most popular internationalization library, powerful and easy to use.

Installation:

bash
npm install i18next react-i18next expo-localization

Configure i18next:

typescript
// i18n.ts import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; import { getLocales } from 'expo-localization'; const resources = { en: { translation: { welcome: 'Welcome', login: 'Login', logout: 'Logout', 'hello.name': 'Hello, {{name}}!', }, }, zh: { translation: { welcome: '欢迎', login: '登录', logout: '退出', 'hello.name': '你好,{{name}}!', }, }, }; i18n .use(initReactI18next) .init({ resources, lng: getLocales()[0]?.languageCode || 'en', fallbackLng: 'en', interpolation: { escapeValue: false, }, }); export default i18n;

Use i18next:

typescript
import { useTranslation } from 'react-i18next'; function WelcomeScreen() { const { t, i18n } = useTranslation(); const changeLanguage = (lang: string) => { i18n.changeLanguage(lang); }; return ( <View> <Text>{t('welcome')}</Text> <Text>{t('hello.name', { name: 'John' })}</Text> <Button title="English" onPress={() => changeLanguage('en')} /> <Button title="中文" onPress={() => changeLanguage('zh')} /> </View> ); }
  1. expo-localization

Expo's official localization library for getting device language settings.

Use expo-localization:

typescript
import * as Localization from 'expo-localization'; function getDeviceLanguage() { const locale = Localization.locale; const languageCode = Localization.locale.split('-')[0]; console.log('Locale:', locale); console.log('Language:', languageCode); return languageCode; }

Get Localization Info:

typescript
function getLocalizationInfo() { const locale = Localization.locale; const timezone = Localization.timezone; const isoCurrencyCodes = Localization.isoCurrencyCodes; return { locale, timezone, currency: isoCurrencyCodes[0], }; }
  1. React Native Localization

Lightweight internationalization solution.

Installation:

bash
npm install react-native-localize

Configuration:

typescript
import * as RNLocalize from 'react-native-localize'; const translations = { en: require('./en.json'), zh: require('./zh.json'), }; const fallback = { languageTag: 'en', isRTL: false }; const { languageTag } = RNLocalize.findBestAvailableLanguage(Object.keys(translations)) || fallback; i18n.init({ resources: { [languageTag]: translations[languageTag], }, lng: languageTag, fallbackLng: 'en', });

Multi-language Resource Management:

  1. JSON File Structure
json
// locales/en.json { "common": { "ok": "OK", "cancel": "Cancel", "save": "Save" }, "auth": { "login": "Login", "logout": "Logout", "register": "Register", "forgotPassword": "Forgot Password?" }, "home": { "title": "Home", "welcome": "Welcome back!", "recentActivity": "Recent Activity" } }
json
// locales/zh.json { "common": { "ok": "确定", "cancel": "取消", "save": "保存" }, "auth": { "login": "登录", "logout": "退出", "register": "注册", "forgotPassword": "忘记密码?" }, "home": { "title": "首页", "welcome": "欢迎回来!", "recentActivity": "最近活动" } }
  1. Namespace Organization
typescript
// Use namespaces i18n.init({ resources: { en: { common: require('./locales/en/common.json'), auth: require('./locales/en/auth.json'), home: require('./locales/en/home.json'), }, zh: { common: require('./locales/zh/common.json'), auth: require('./locales/zh/auth.json'), home: require('./locales/zh/home.json'), }, }, }); // Use namespace const { t } = useTranslation('common'); <Text>{t('ok')}</Text> // Cross namespace <Text>{t('auth:login')}</Text>

Date and Time Localization:

typescript
import { format } from 'date-fns'; import { zhCN, enUS } from 'date-fns/locale'; function formatDate(date: Date, locale: string) { const localeMap = { en: enUS, zh: zhCN, }; return format(date, 'PPP', { locale: localeMap[locale] || enUS, }); } function formatDateTime(date: Date, locale: string) { return format(date, 'PPPppp', { locale: locale === 'zh' ? zhCN : enUS, }); }

Number and Currency Localization:

typescript
function formatCurrency(amount: number, locale: string) { return new Intl.NumberFormat(locale, { style: 'currency', currency: locale === 'zh' ? 'CNY' : 'USD', }).format(amount); } function formatNumber(number: number, locale: string) { return new Intl.NumberFormat(locale).format(number); } function formatPercent(value: number, locale: string) { return new Intl.NumberFormat(locale, { style: 'percent', minimumFractionDigits: 2, }).format(value); }

RTL (Right-to-Left) Support:

typescript
import { I18nManager } from 'react-native'; function setupRTL(locale: string) { const isRTL = locale === 'ar' || locale === 'he'; if (I18nManager.isRTL !== isRTL) { I18nManager.allowRTL(isRTL); I18nManager.forceRTL(isRTL); // Need to restart app Updates.reloadAsync(); } }

Dynamic Language Switching:

typescript
function LanguageSwitcher() { const { i18n } = useTranslation(); const [currentLang, setCurrentLang] = useState(i18n.language); const changeLanguage = async (lang: string) => { await i18n.changeLanguage(lang); setCurrentLang(lang); // Save user preference await AsyncStorage.setItem('userLanguage', lang); // If RTL support needed setupRTL(lang); }; const languages = [ { code: 'en', name: 'English' }, { code: 'zh', name: '中文' }, { code: 'es', name: 'Español' }, ]; return ( <View> {languages.map((lang) => ( <Button key={lang.code} title={lang.name} onPress={() => changeLanguage(lang.code)} disabled={currentLang === lang.code} /> ))} </View> ); }

Best Practices:

  1. Resource File Organization

    • Organize translation files by feature modules
    • Use namespaces to avoid conflicts
    • Keep translation file structure consistent
  2. Translation Quality

    • Use professional translation tools
    • Consider cultural differences and habits
    • Regularly review and update translations
  3. Performance Optimization

    • Load language packages on demand
    • Cache translation results
    • Avoid frequent language switching
  4. User Experience

    • Auto-detect device language
    • Provide language switching options
    • Save user language preferences
  5. Test Coverage

    • Test display in all languages
    • Check for text overflow issues
    • Verify RTL layouts

Common Issues:

  1. Missing Translations

    • Set fallback language
    • Use translation management tools
    • Regularly check translation completeness
  2. Text Overflow

    • Use flex layout
    • Provide text truncation options
    • Adjust layout for different languages
  3. Dynamic Loading

    • Use code splitting
    • Lazy load language packages
    • Preload common languages

Through comprehensive internationalization implementation, Expo apps can better serve global users and improve user experience and market competitiveness.

标签:Expo