Multi Language
Singularity React leverages react-i18next
to enable support for multiple languages.
While multi-language support is not essential for most applications, we have opted not to include translations in every app. To see translations in action, visit the Mail app and switch languages using the Toolbar. This app is uniquely configured with translations for demonstration purposes. For a deeper understanding, you can examine the source code to see how translations are implemented.
Usage
To implement translations, create a translation file named i18n/en.ts
in the folder of the app where you want to apply them. For instance, to enable translations in the Mail app, place this file in the apps/mail
directory.
const locale = { APP_TITLE: 'Mailbox', COMPOSE: 'Compose', FOLDERS: 'Mailboxes', FILTERS: 'Filters', LABELS: 'Labels', NO_MESSAGES: 'There are no messages!', SEARCH_PLACEHOLDER: 'Search for an e-mail or task', INBOX: 'Inbox', SENT: 'Sent', DRAFTS: 'Drafts', SPAM: 'Spam', TRASH: 'Trash', STARRED: 'Starred', IMPORTANT: 'Important' }; export default locale;
Then, register the language file using i18next.addResourceBundle()
insrc/app/(control-panel)/apps/mailbox/i18n/index.ts
.
import i18n from '@i18n'; import ar from './ar'; import en from './en'; import tr from './tr'; i18n.addResourceBundle('en', 'mailboxApp', en); i18n.addResourceBundle('tr', 'mailboxApp', tr); i18n.addResourceBundle('ar', 'mailboxApp', ar);
In a component, utilize the useTranslation
hook as shown below:
import {useTranslation} from 'react-i18next'; const {t} = useTranslation('mailApp'); return ( <div className="p-6"> <Button variant="contained" color="primary" className="w-full" onClick={handleOpenDialog} > {t('COMPOSE')} </Button>
Default Language
To modify the default language in Singularity React, update the lng
setting in the file @i18n/i18n.ts
.
For example, you can change the "en" value to "ar" to test the change.
import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; /** * resources is an object that contains all the translations for the different languages. */ const resources = { en: { translation: { 'Enjoy the React': 'Enjoy the React and react-i18next' } } }; /** * i18n is initialized with the resources object and the language to use. * The keySeparator option is set to false because we do not use keys in form messages.welcome. * The interpolation option is set to false because we do not use interpolation in form messages.welcome. */ i18n.use(initReactI18next) // passes i18n down to react-i18next .init({ resources, lng: 'en', keySeparator: false, // we do not use keys in form messages.welcome interpolation: { escapeValue: false // react already safes from xss } }); export default i18n;
Changing Language
To dynamically switch languages, use the changeLanguage
function provided by the hook:
import useI18n from '@i18n/useI18n'; const { changeLanguage } = useI18n(); const handleLanguageChange = async (newLanguageId) => { await changeLanguage(newLanguageId); };
See an example implementation atapp/theme-layouts/components/LanguageSwitcher.tsx
.
I18n Provider
Singularity React employs a custom I18nProvider to handle language settings and provide language-related functionality across the application. The I18nProvider is defined in @i18n/I18nProvider.tsx
.
Core features of the I18nProvider include:
- Handling available languages
- Providing the current language and its direction
- Supplying a function to switch the current language
- Integrating with Singularity settings to adjust layout direction
The I18nProvider implementation is shown below:
'use client'; import React, { useState, useEffect, useMemo } from 'react'; import _ from 'lodash'; import useSingularitySettings from '@singularity/core/SingularitySettings/hooks/useSingularitySettings'; import i18n from './i18n'; import I18nContext from './I18nContext'; import { LanguageType } from './I18nContext'; type I18nProviderProps = { children: React.ReactNode; }; const languages: LanguageType[] = [ { id: 'en', title: 'English', flag: 'US' }, { id: 'es', title: 'Spanish', flag: 'ES' }, { id: 'hi', title: 'Hindi', flag: 'IN' }, { id: 'ar', title: 'Arabic', flag: 'SA' }, { id: 'fr', title: 'French', flag: 'FR' }, { id: 'ja', title: 'Japanese', flag: 'JP' } ]; export function I18nProvider(props: I18nProviderProps) { const { children } = props; const { data: settings, setSettings } = useSingularitySettings(); const settingsThemeDirection = useMemo(() => settings.direction, [settings]); const [languageId, setLanguageId] = useState(i18n.options.lng); const changeLanguage = async (languageId: string) => { setLanguageId(languageId); await i18n.changeLanguage(languageId); }; useEffect(() => { if (languageId !== i18n.options.lng) { i18n.changeLanguage(languageId); } const langDirection = i18n.dir(languageId); if (settingsThemeDirection !== langDirection) { setSettings({ direction: langDirection }); } }, [languageId, setSettings, settingsThemeDirection]); return ( <I18nContext value={useMemo( () => ({ language: _.find(languages, { id: languageId }), languageId, langDirection: i18n.dir(languageId), languages, changeLanguage }), [languageId] )} > {children} </I18nContext> ); }
To utilize the I18nProvider in your components, import and use the useI18n
hook as follows:
import useI18n from '@i18n/useI18n'; function MyComponent() { const { language, changeLanguage, langDirection } = useI18n(); return ( <div> <p>Current language: {language.title}</p> <p>Language direction: {langDirection}</p> <button onClick={() => changeLanguage('ar')}> Switch to Arabic </button> </div> ); }