Internationalization Basic Configuration
Installing Required Dependencies
# Core Library
npm install i18next react - i18next i18next - react - native - language - detector
# Optional: Support for Plural Forms and Interpolation
npm install i18next - plural - rules
Basic i18n Configuration
// i18n.js
import i18n from ' i18next ' ;
import { initReactI18next } from ' react-i18next ' ;
import LanguageDetector from ' i18next-react-native-language-detector ' ;
// Import Translation Resources
import en from ' ./locales/en.json ' ;
import zh from ' ./locales/zh.json ' ;
import ja from ' ./locales/ja.json ' ;
i18n
. use (LanguageDetector) // Use Language Detector
. use (initReactI18next) // Bind to React
. init ({
resources : {
en : { translation : en },
zh : { translation : zh },
ja : { translation : ja },
},
fallbackLng : ' en ' , // Default Language
debug : __DEV__, // Enable Debugging in Development Mode
interpolation : {
escapeValue : false , // React Handles XSS Protection
},
compatibilityJSON : ' v3 ' , // Resolve iOS 13+ Compatibility Issues
});
export default i18n;
Translation Resource File Example
// locales/en.json
{
" welcome " : " Welcome to our app " ,
" login " : {
" title " : " Login " ,
" username " : " Username " ,
" password " : " Password "
},
" errors " : {
" network " : " Network error, please try again "
}
}
// locales/zh.json
{
" welcome " : " Welcome to our app " ,
" login " : {
" title " : " Login " ,
" username " : " Username " ,
" password " : " Password "
},
" errors " : {
" network " : " Network error, please try again "
}
}
Using in React Components
Basic Text Translation
// LoginScreen.js
import React from ' react ' ;
import { View, Text } from ' react-native ' ;
import { useTranslation } from ' react-i18next ' ;
const LoginScreen = () => {
const { t } = useTranslation ();
return (
< View >
< Text > { t ( ' welcome ' ) } </ Text >
< Text > { t ( ' login.title ' ) } </ Text >
< Text > { t ( ' login.username ' ) } </ Text >
< Text > { t ( ' login.password ' ) } </ Text >
</ View >
);
};
export default LoginScreen;
Dynamic Parameter Interpolation
// ProductDetails.js
import React from ' react ' ;
import { Text } from ' react-native ' ;
import { useTranslation } from ' react-i18next ' ;
const ProductDetails = ({ price , discount }) => {
const { t } = useTranslation ();
return (
< Text >
{ t ( ' product.price ' , {
price : price. toFixed ( 2 ),
discount : discount > 0 ? `- ${ discount } %` : ''
}) }
</ Text >
);
};
// locales/en.json
{
" items " : " You have {{count}} item " ,
" items_plural " : " You have {{count}} items "
}
// Usage in Component
< Text > { t ( ' items ' , { count : itemCount }) } </ Text >
Language Switching Implementation
Language Selector Component
// LanguageSwitcher.js
import React from ' react ' ;
import { View, Picker } from ' react-native ' ;
import { useTranslation } from ' react-i18next ' ;
const LanguageSwitcher = () => {
const { i18n } = useTranslation ();
const changeLanguage = ( lng ) => {
i18n. changeLanguage (lng);
// Optional: Persist User Selection
AsyncStorage. setItem ( ' userLanguage ' , lng);
};
return (
< Picker
selectedValue ={ i18n.language }
onValueChange ={ changeLanguage }
>
< Picker.Item label = " English " value = " en " />
< Picker.Item label = " Chinese " value = " zh " />
< Picker.Item label = " Japanese " value = " ja " />
</ Picker >
);
};
Persisting User Language Preference
// Add to i18n Initialization
import AsyncStorage from ' @react-native-async-storage/async-storage ' ;
i18n
. use ({
type : ' languageDetector ' ,
async : true ,
detect : async ( callback ) => {
try {
const savedLanguage = await AsyncStorage. getItem ( ' userLanguage ' );
callback (savedLanguage || undefined ); // undefined Lets Detector Auto-Detect
} catch (err) {
callback ( undefined );
}
},
init : () => {},
cacheUserLanguage : async ( lng ) => {
await AsyncStorage. setItem ( ' userLanguage ' , lng);
},
})
. use (initReactI18next)
. init ({ /* ... */ });
Handling Plural Forms and Context
// locales/en.json
{
" apple " : " apple | apples " ,
" banana " : " no bananas | one banana | {{count}} bananas "
}
// Usage in Component
< Text > { t ( ' apple ' , { count : 5 }) } </ Text >
< Text > { t ( ' banana ' , { count : 0 }) } </ Text >
< Text > { t ( ' banana ' , { count : 1 }) } </ Text >
< Text > { t ( ' banana ' , { count : 10 }) } </ Text >
Context Translation
// locales/en.json
{
" read " : " read | read (present perfect) | read (past perfect) " ,
" read_context " : {
" present " : " read " ,
" presentPerfect " : " have read " ,
" pastPerfect " : " had read "
}
}
// Usage in Component
< Text > { t ( ' read ' , { context : ' present ' }) } </ Text >
< Text > { t ( ' read_context.presentPerfect ' ) } </ Text >
// utils/formatters.js
import { Platform } from ' react-native ' ;
export const formatDate = ( date ) => {
return new Intl. DateTimeFormat (i18n.language, {
year : ' numeric ' ,
month : ' long ' ,
day : ' numeric ' ,
}). format ( new Date (date));
};
export const formatCurrency = ( amount ) => {
return new Intl. NumberFormat (i18n.language, {
style : ' currency ' ,
currency : i18n.language === ' ja ' ? ' JPY ' : ' USD ' ,
}). format (amount);
};
// OrderSummary.js
import React from ' react ' ;
import { Text } from ' react-native ' ;
import { formatDate, formatCurrency } from ' ../utils/formatters ' ;
import { useTranslation } from ' react-i18next ' ;
const OrderSummary = ({ date , amount }) => {
const { t } = useTranslation ();
return (
< View >
< Text > { t ( ' order.date ' ) } : { formatDate (date) } </ Text >
< Text > { t ( ' order.total ' ) } : { formatCurrency (amount) } </ Text >
</ View >
);
};
Handling RTL (Right-to-Left) Layouts
Detecting and Setting RTL
// In App.js or Entry File
import { I18nManager } from ' react-native ' ;
import i18n from ' ./i18n ' ;
// Detect if Language Requires RTL Layout
const isRTL = [ ' ar ' , ' he ' , ' fa ' ]. includes (i18n.language);
I18nManager. forceRTL (isRTL);
I18nManager. allowRTL (isRTL);
// Note: Set as Early as Possible in App Startup
RTL Layout Adaptation Example
// styles.js
import { StyleSheet, I18nManager } from ' react-native ' ;
export default StyleSheet. create ({
container : {
flexDirection : I18nManager.isRTL ? ' row-reverse ' : ' row ' ,
justifyContent : ' space-between ' ,
},
text : {
writingDirection : I18nManager.isRTL ? ' rtl ' : ' ltr ' ,
},
});
Dynamic Import of Translation Resources (On-Demand Loading)
Code Splitting for Translation Resources
// i18n.js
import i18n from ' i18next ' ;
import { initReactI18next } from ' react-i18next ' ;
i18n
. use (initReactI18next)
. init ({
lng : ' en ' ,
fallbackLng : ' en ' ,
debug : __DEV__,
interpolation : { escapeValue : false },
react : { useSuspense : true }, // Enable Suspense
});
// Dynamically Load Language Resources
export const loadLocale = async ( locale ) => {
try {
const module = await import ( `./locales/ ${ locale } .json` );
i18n. addResourceBundle (locale, ' translation ' , module .default);
i18n. changeLanguage (locale);
} catch (error) {
console. error ( `Failed to load ${ locale } translations:` , error);
}
};
export default i18n;
Using Dynamic Loading in Components
// LanguageSwitcher.js
import React, { Suspense } from ' react ' ;
import { Button } from ' react-native ' ;
import { useTranslation } from ' react-i18next ' ;
import { loadLocale } from ' ../i18n ' ;
const LanguageSwitcher = () => {
const { i18n } = useTranslation ();
const changeLanguage = async ( lng ) => {
if (i18n.language !== lng) {
await loadLocale (lng);
}
};
return (
< Suspense fallback ={ < ActivityIndicator /> } >
< Button title = " English " onPress ={ () => changeLanguage ( ' en ' ) } />
< Button title = " Chinese " onPress ={ () => changeLanguage ( ' zh ' ) } />
</ Suspense >
);
};
Testing Internationalization Features
Jest Testing Example
// __tests__/i18n.test.js
import i18n from ' ../i18n ' ;
import { render, waitFor } from ' @testing-library/react-native ' ;
import LoginScreen from ' ../screens/LoginScreen ' ;
jest. mock ( ' ../i18n ' , () => ({
t : ( key ) => key, // Mock Translation Function
language : ' en ' ,
}));
describe ( ' LoginScreen i18n ' , () => {
it ( ' renders with English translations ' , () => {
const { getByText } = render (< LoginScreen />);
expect ( getByText ( ' welcome ' )). toBeTruthy ();
});
it ( ' switches to Chinese translations ' , async () => {
i18n.language = ' zh ' ;
const { getByText } = render (< LoginScreen />);
await waitFor (() => {
expect ( getByText ( ' login.title ' )). toBeTruthy ();
});
});
});
Detox E2E Testing Example
// e2e/i18n.spec.js
describe ( ' Internationalization ' , () => {
beforeAll ( async () => {
await device. launchApp ();
});
it ( ' should display English by default ' , async () => {
await expect ( element (by. text ( ' Welcome ' ))). toBeVisible ();
});
it ( ' should switch to Chinese ' , async () => {
await element (by. id ( ' language-switcher ' )). tap ();
await element (by. text ( ' Chinese ' )). tap ();
await expect ( element (by. text ( ' Login ' ))). toBeVisible ();
});
});