Internationalization (i18n)
This project uses the i18next library for internationalization. It's a powerful and flexible solution for adding multilingual support to React applications. i18next makes it easy to manage translations, switch languages, and handle pluralization and formatting with minimal effort.
Translation File Structure
In SOKit UI projects, translation files are stored under the src/i18n/ directory. Each language has its own .json
file containing all the necessary key-value translation pairs.
For this use case, we will support two languages: English and French. Remove any other language JSON files from the folder if they exist.
English Translations
Create or update the file src/i18n/translation_en.json with the following content:
{
"bc.company": "Company",
"bc.search": "Search",
"bc.form": "Form",
"submit": "Submit",
"approve": "Approve",
"reject": "Reject",
"view": "View",
"review": "Review",
"company.success.title.submit": "Submission Successful",
"company.success.message.submit": "Your request has been submitted successfully.",
"company.success.title.approve": "Approval Successful",
"company.success.message.approve": "Your request has been approved successfully.",
"company.success.title.reject": "Rejection Successful",
"company.success.message.reject": "Your request has been rejected successfully.",
"Delete Confirmation": "Delete Confirmation",
"filter.apply": "Apply",
"filter.title": "Filters",
"footer-help": "Help",
"home": "Home",
"metadata.current.state": "Status",
"modal.cancel": "Cancel",
"profile-logout": "Logout",
"companies": "Companies",
"company-search": "Search",
"company-new": "New Company",
"refresh.table": "Refresh",
"reset.table.filtering": "Reset Filters",
"reset.table.sorting": "Reset Sorting",
"company.btn.review": "Review",
"company.General": "General",
"company.Shareholders": "Shareholders",
"company.Registration": "Registration",
"company.title.general.info": "General Information",
"company.title.general.address": "Address",
"company.title.general.contact": "Contacts",
"title.sh.info": "Shareholder Information",
"company.btn.sh.new": "New",
"company.btn.sh.clone": "Clone",
"company.btn.sh.delete": "Delete",
"company.empty.shareholders": "No Shareholders to display",
"company.firstName": "First Name",
"company.lastName": "Last Name",
"company.shares": "Shares",
"company.percentage": "Percentage",
"company.companyName": "Name",
"company.legalForm": "Legal Form",
"company.establishedDate": "Established Date",
"company.capital": "Capital",
"company.employees": "Employees number",
"company.type": "Type",
"company.address.street": "Street",
"company.address.city": "City",
"company.address.state": "State",
"company.address.zip": "Zip Code",
"company.website": "Website",
"company.phone": "Phone",
"company.email": "Email",
"btn.sh.new": "New",
"btn.sh.clone": "Clone",
"btn.sh.delete": "Delete",
"empty.shareholders": "No Shareholders to display",
"company.title.registration": "Registration",
"company.vatNumber": "VAT Number",
"company.remark": "Remark"
}
French Translations
Create or update the file src/i18n/translation_fr.json with the following content:
{
"bc.company": "Entreprise",
"bc.search": "Recherche",
"bc.form": "Formulaire",
"submit": "Soumettre",
"approve": "Approuver",
"reject": "Rejeter",
"view": "Voir",
"review": "Révision",
"company.success.title.submit": "Soumission réussie",
"company.success.message.submit": "Votre demande a été soumise avec succès.",
"company.success.title.approve": "Approbation réussie",
"company.success.message.approve": "Votre demande a été approuvée avec succès.",
"company.success.title.reject": "Rejet réussi",
"company.success.message.reject": "Votre demande a été rejetée avec succès.",
"Delete Confirmation": "Confirmation de suppression",
"filter.apply": "Appliquer",
"filter.title": "Filtres",
"footer-help": "Aide",
"home": "Accueil",
"metadata.current.state": "Statut",
"modal.cancel": "Annuler",
"profile-logout": "Déconnexion",
"companies": "Entreprises",
"company-search": "Recherche",
"company-new": "Nouvelle entreprise",
"refresh.table": "Rafraîchir",
"reset.table.filtering": "Réinitialiser les filtres",
"reset.table.sorting": "Réinitialiser le tri",
"company.btn.review": "Révision",
"company.General": "Général",
"company.Shareholders": "Actionnaires",
"company.Registration": "Enregistrement",
"company.title.general.info": "Informations générales",
"company.title.general.address": "Adresse",
"company.title.general.contact": "Contacts",
"title.sh.info": "Informations sur les actionnaires",
"company.btn.sh.new": "Nouveau",
"company.btn.sh.clone": "Cloner",
"company.btn.sh.delete": "Supprimer",
"company.empty.shareholders": "Aucun actionnaire à afficher",
"company.firstName": "Prénom",
"company.lastName": "Nom",
"company.shares": "Parts",
"company.percentage": "Pourcentage",
"company.companyName": "Nom",
"company.legalForm": "Forme juridique",
"company.establishedDate": "Date de création",
"company.capital": "Capital",
"company.employees": "Nombre d’employés",
"company.type": "Type",
"company.address.street": "Rue",
"company.address.city": "Ville",
"company.address.state": "Région",
"company.address.zip": "Code postal",
"company.website": "Site web",
"company.phone": "Téléphone",
"company.email": "Email",
"btn.sh.new": "Nouveau",
"btn.sh.clone": "Cloner",
"btn.sh.delete": "Supprimer",
"empty.shareholders": "Aucun actionnaire à afficher",
"company.title.registration": "Enregistrement",
"company.vatNumber": "Numéro de TVA",
"company.remark": "Remarque"
}
i18n Index File
In the same src/i18n/ folder, you’ll find an index.js file. This file imports and registers each language and
exports them in a unified format for the app.
Your index.js should look like this:
import enTranslations from './translation_en.json';
import frTranslations from './translation_fr.json';
const index = {
en: {
translation: enTranslations,
},
fr: {
translation: frTranslations,
}
};
export default index;
Configure Languages in app-config.jsx
Now open your app-config.jsx file and ensure the i18n.languages array includes only the supported languages:
const AppConfig = {
...
i18n: {
languages: [
{
code: 'en',
emoji: '🇺🇸',
name: 'English',
},
{
code: 'fr',
emoji: '🇫🇷',
name: 'Français',
},
]
}
...
};
Once this is done, a language toggle should appear in the navbar, allowing users to switch between English and French.
Key Mapping & Usage
Translation JSON files use a key-value structure. The key is what you’ll use in your components to reference a particular translation.
SOKit UI components like SearchPage and DocumentPage use a scope
parameter—e.g., "company"—to automatically prefix translation keys. For example, a key like company.firstName means:
"company"is the scope"firstName"is the identifier
This results in clean and consistent translation key naming.
Hooking It All Together
The translations are passed to the application in app.jsx via the SOApplication component from SOKit UI. Here's how
it's typically wired:
import './styles/index.css';
import {Outlet} from 'react-router';
import {SOApplication} from 'so-kit-ui';
import config from './app-config.jsx';
import locales from './i18n/index.js';
import {library} from './library.jsx';
export const App = () => {
return (
<SOApplication
appNamespace='Company'
appNamespaceAsI18nScope={false}
debugTranslations={true}
locales={locales}
library={library}
config={config}
>
<Outlet/>
</SOApplication>
);
};
This configuration ensures your translations are injected and available throughout the app.
With this setup, your app is now ready to support internationalization. You can easily scale by adding more JSON files for new languages and updating the config and index files accordingly.