Chapter 2: Internationalization (i18n)
SmartCommon uses i18next for translations.
File structure
mobile/
├── public/
│ └── locales/
│ ├── fr/
│ │ └── translation.json
│ └── en/
│ └── translation.json
└── src/
└── i18n/
└── index.js
i18next configuration
// src/i18n/index.js
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import Backend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
fallbackLng: 'fr',
supportedLngs: ['fr', 'en'],
debug: import.meta.env.DEV,
backend: {
loadPath: '/locales/{{lng}}/translation.json'
},
interpolation: {
escapeValue: false
}
});
export default i18n;
Translation files
French
{
"common": {
"loading": "Chargement...",
"save": "Enregistrer",
"cancel": "Annuler",
"delete": "Supprimer",
"edit": "Modifier",
"close": "Fermer",
"confirm": "Confirmer",
"yes": "Oui",
"no": "Non"
},
"auth": {
"login": "Connexion",
"logout": "Déconnexion",
"email": "Email",
"password": "Mot de passe",
"loginButton": "Se connecter",
"loginError": "Identifiants incorrects"
},
"tasks": {
"title": "Mes tâches",
"new": "Nouvelle tâche",
"edit": "Modifier la tâche",
"label": "Titre",
"description": "Description",
"priority": "Priorité",
"status": {
"todo": "À faire",
"done": "Terminée"
},
"empty": "Aucune tâche",
"deleteConfirm": "Supprimer cette tâche ?"
},
"errors": {
"network": "Erreur de connexion",
"notFound": "Page non trouvée",
"server": "Erreur serveur"
}
}
English
{
"common": {
"loading": "Loading...",
"save": "Save",
"cancel": "Cancel",
"delete": "Delete",
"edit": "Edit",
"close": "Close",
"confirm": "Confirm",
"yes": "Yes",
"no": "No"
},
"auth": {
"login": "Login",
"logout": "Logout",
"email": "Email",
"password": "Password",
"loginButton": "Sign in",
"loginError": "Invalid credentials"
},
"tasks": {
"title": "My tasks",
"new": "New task",
"edit": "Edit task",
"label": "Title",
"description": "Description",
"priority": "Priority",
"status": {
"todo": "To do",
"done": "Done"
},
"empty": "No tasks",
"deleteConfirm": "Delete this task?"
},
"errors": {
"network": "Network error",
"notFound": "Page not found",
"server": "Server error"
}
}
Usage in components
With useTranslation
import { useTranslation } from 'react-i18next';
import { Page, Block, Button } from '@cap-rel/smartcommon';
export const TasksPage = () => {
const { t } = useTranslation();
return (
<Page title={t('tasks.title')}>
<Block>
<Button>{t('tasks.new')}</Button>
{tasks.length === 0 && (
<p>{t('tasks.empty')}</p>
)}
</Block>
</Page>
);
};
With parameters
{
"tasks": {
"count": "{{count}} tâche",
"count_plural": "{{count}} tâches",
"greeting": "Bonjour {{name}}"
}
}
const { t } = useTranslation();
// With a parameter
t('tasks.greeting', { name: 'Jean' }) // "Bonjour Jean"
// Plural
t('tasks.count', { count: 1 }) // "1 tâche"
t('tasks.count', { count: 5 }) // "5 tâches"
Switching language
import { useTranslation } from 'react-i18next';
import { useGlobalStates } from '@cap-rel/smartcommon';
import { Select } from '@cap-rel/smartcommon';
export const LanguageSelector = () => {
const { i18n } = useTranslation();
const gst = useGlobalStates();
const changeLanguage = (lng) => {
i18n.changeLanguage(lng);
gst.local.set('settings', { ...gst.get('settings'), lng });
};
return (
<Select
value={i18n.language}
onChange={(e) => changeLanguage(e.target.value)}
options={[
{ value: 'fr', label: 'Français' },
{ value: 'en', label: 'English' }
]}
/>
);
};
Formatting dates and numbers
Use useIntl from SmartCommon:
import { useIntl } from '@cap-rel/smartcommon';
function DateDisplay({ date }) {
const intl = useIntl();
// Uses the current locale
const formatted = intl.DateTimeFormat(date, undefined, {
year: 'numeric',
month: 'long',
day: 'numeric'
});
return <span>{formatted}</span>;
}
Key takeaways
- JSON files in public/locales/{lng}/
- useTranslation to access the translations
- t('key') to translate a string
- Parameters with {{ }} inside the translations
- i18n.changeLanguage() to switch language
Previous Chapter | Back to Module | Next Chapter: Other Features ->