Quốc tế hóa (i18n) là bước không thể bỏ qua khi sản phẩm cần phục vụ người dùng đa ngôn ngữ. Dưới đây là quy trình thực tế để tích hợp i18next vào cả React (web) và React Native (mobile) trong một codebase chung, giúp duy trì nhất quán và dễ mở rộng. ### 1. Cài đặt các gói cần thiết - `i18next` – core library. - `react-i18next` – binding cho React. - `i18next-http-backend` (web) hoặc `i18next-react-native-language-detector` (mobile) để tải file ngôn ngữ. - `i18next-localstorage-cache` (tuỳ chọn) để cache bản dịch trên trình duyệt. ### 2. Cấu trúc thư mục ngôn ngữ ``` src/ locales/ en/ common.json auth.json vi/ common.json auth.json ja/ common.json auth.json ``` Mỗi namespace (common, auth, …) tách riêng để tải theo nhu cầu (lazy‑load). ### 3. Khởi tạo i18next (shared config) Tạo file `i18n.ts` dùng chung cho cả hai nền tảng: ```ts import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; import LanguageDetector from 'i18next-browser-languagedetector'; // web import RNLanguageDetector from 'i18next-react-native-language-detector'; // mobile const isWeb = typeof window !== 'undefined'; i18n .use(initReactI18next) .use(isWeb ? LanguageDetector : RNLanguageDetector) .init({ fallbackLng: 'en', ns: ['common', 'auth'], defaultNS: 'common', interpolation: { escapeValue: false }, react: { useSuspense: false }, }); export default i18n; ``` ### 4. Tải bản dịch động (lazy‑load) Sử dụng `i18next-http-backend` trên web và `react-native-fs`/`expo-file-system` trên mobile để fetch file JSON chỉ khi namespace được yêu cầu. Điều này giảm bundle size ban đầu. ### 5. Sử dụng trong component ```tsx import { useTranslation } from 'react-i18next'; export function LoginScreen() { const { t, i18n } = useTranslation('auth'); const changeLang = (lng: string) => i18n.changeLanguage(lng); return ( <View> <Text>{t('welcome')}</Text> <Button title="VN" onPress={() => changeLang('vi')} /> <Button title="EN" onPress={() => changeLang('en')} /> </View> ); } ``` ### 6. Xử lý số nhiều (plural) và biến nội suy i18next hỗ trợ cú pháp `{{count}}` và quy tắc plural cho từng ngôn ngữ. Ví dụ trong `common.json`: ```json { "itemCount": "{{count}} mục", "itemCount_plural": "{{count}} items" } ``` Gọi `t('itemCount', { count: 5 })` sẽ tự chọn dạng phù hợp. ### 7. Kiểm thử và CI - Viết test unit cho các key dịch quan trọng (snapshot). - Thêm script `i18n:check` dùng `i18next-scanner` để phát hiện key thiếu trước khi merge. ### 8. Mẹo thực chiến - **Namespace nhỏ**: tách theo feature để load on‑demand. - **Cache**: bật `localStorage` trên web, `AsyncStorage` trên mobile. - **Fallback**: luôn cung cấp `en` làm ngôn ngữ dự phòng. - **TypeScript**: sinh type từ file JSON với `i18next-typescript` để có autocomplete. Với cách tiếp cận này, đội ngũ có thể thêm ngôn ngữ mới chỉ bằng cách drop thêm thư mục dưới `locales/` mà không chạm vào logic ứng dụng. Hệ thống i18n trở nên mô-đun, hiệu năng và dễ bảo trì cho cả React web lẫn React Native.