The client-side i18n library subpackage of sheet-i18n.
This package provides tools to handle translations in React applications using context and hooks. It simplifies internationalization workflows by offering functions and components to manage, access, and use locale-specific translation data.
-
I18nStore
: Core Store Creation Class for managing translation data. -
createI18nContext
: React Context to generate providers and hooks for translation. -
IntlProvider
: React Translation Provider for managing current locale. -
useTranslation
: Client Side Translation Hook for easy access to translation messages on the client side. -
getTranslation
: Static Translation Function for easy access to translation messages on Static module files.
⚡ Strongly recommended to use the init CLI for setup 👉 Please follow the Init CLI section
If you don't want to use the CLI, you can follow the
Manual Setup
below.
Prepare locale JSON files:
// en.json
{
"header": {
"login": "Login",
"logout": "Logout"
}
}
// ko.json
{
"header": {
"login": "로그인",
"logout": "로그아웃"
}
}
this store will be used as a core translations module.
import en from './en.json';
import ko from './ko.json';
import { I18nStore } from '@sheet-i18n/react';
export const i18nStore = new I18nStore({
supportedLocales: ['ko', 'en'],
defaultLocale: 'ko',
/** if you want to load translation data statically */
localeSet: {
ko,
en,
},
/** if you want to load translation data dynamically */
// dynamicLoaders: {
// ko: () => import('./ko.json'),
// en: () => import('./en.json'),
// jp: () => import('./jp.json'),
// cn: () => import('./cn.json'),
// },
});
import { i18nStore } from './file-path-of-i18nStore-initiated';
import { createI18nContext } from '@sheet-i18n/react';
export const { IntlProvider, useTranslation, getTranslation } =
createI18nContext(i18nStore);
import React from 'react';
import { IntlProvider } from './i18nContext';
const App = () => {
const [locale, setLocale] = useState('en');
return (
<IntlProvider currentLocale={locale}>
<YourComponent />
</IntlProvider>
);
};
import React from 'react';
import { useTranslation } from './i18nContext';
const YourComponent = () => {
const { t } = useTranslation('header');
return (
<div>
<button>{t('login')}</button>
<button>{t('logout')}</button>
</div>
);
};
The I18nStore
manages translation states, ensuring consistency across locales.
Option | Type | Required | Description |
---|---|---|---|
supportedLocales |
string[] | ✅ | List of supported locale codes. |
defaultLocale |
string | ✅ | Default locale to use when no match is found. Must be included in supportedLocales . |
localeSet | Record<string, object> |
(Static Loading Option) Preload all translation data for each locale in memory. Keys must match supportedLocales . |
|
dynamicLoaders | Record<string, () => Promise> | (Recommended for large locale sets) Dynamically load translation data on demand, reducing initial bundle size. | |
typeSafe | boolean | Enable strict key checking and autocompletion (default: false ). |
|
💡 typeSafe?
I18nStore doesn't enforce adherence to your locale JSON definitions by default. This means that you can add translation data even if it isn’t pre-defined in your locale JSON files. However, if you prefer to enforce strict type-safety, you can manually enable the typeSafe option which allows you to notice the auto-completed list in translation data.But to enable correct type checking,
the full localeSet must be defined according to the supportedLocales in i18nStore
As a result, type auto-completion relies on having the complete localeSet defined at initialization. This means that using dynamicLoaders to fetch locales conditionally at runtime can be limiting when strict type-safety is enabled.
// typeSafe: true const YourComponent = () => { // "useTranslation" shows the autocompletion suggestions const { t } = useTranslation('header'); return ( <div> {/* "t" function shows the autocompletion suggestions */} <button>{t('login')}</button> </div> ); };
⚠️ Caveats:
supportedLocales
must be an array of locale strings.defaultLocale
must exist insupportedLocales
.
You can configure how translations are loaded:
-
Static (
localeSet
)
Load all translations at once. Ideal for small projects or limited locale sets. -
Dynamic (
dynamicLoaders
) ✅ Recommended
Load only the locale needed, reducing the bundle size dramatically.
Useful when supporting many languages or large translation files.
export const i18nStore = new I18nStore({
supportedLocales: ['en', 'fr', 'ko'],
defaultLocale: 'en',
dynamicLoaders: {
en: () => import('./en.json'),
fr: () => import('./fr.json'),
ko: () => import('./ko.json'),
},
});
💡 When both localeSet
and dynamicLoaders
are defined, sheet-i18n automatically merges both sources — static data loads immediately, while dynamic data supplements on-demand.
For projects with many locale datasets, it's often preferable to load translation data on demand rather than all at once. It is better using dynamicLoaders
to enable this conditional loading strategy.
- ✅ Reduces the initial JavaScript bundle size.
- ✅ Keeps only required locales in memory.
- ✅ Works well with code-splitting and SSR/CSR.
- ✅ Enables lazy-loading for translations.
export const i18nStore = new I18nStore({
supportedLocales: ['ko', 'en'],
defaultLocale: 'ko',
/** if you want to load translation data statically */
localeSet: {
ko,
en,
},
/** if you want to load translation data dynamically */
// dynamicLoaders: {
// ko: () => import('./ko.json'),
// en: () => import('./en.json'),
// jp: () => import('./jp.json'),
// cn: () => import('./cn.json'),
// },
});
Generates React context, including the IntlProvider
and useTranslation
.
-
i18nStore
: Instance ofI18nStore
.
⚠️ Caveats:
i18nStore
passed to createI18nContext must be an instance of I18nStore.- custom object is not allowed to be passed to createI18nContext.
const { IntlProvider, useTranslation } = createI18nContext(i18nStore);
A Context provider to provide translations to child components.
-
currentLocale
(optional):- A key representing the current locale to use for translations.
- If not provided, the user's preferred language is automatically detected based on the browser setting.
- The fallback is the default locale in i18nStore if the detected user-preferred language is not unsupported in the
supportedLocales
.
-
children
: React children.
// Add currentLocale if you want to manually handle the locale
// This example is Next.js app routing
interface LayoutProps {
params: {
locale: Locale;
};
}
export default function Layout({
children,
params,
}: PropsWithChildren<PageProps>) {
return <IntlProvider currentLocale={params.locale}>{children}</IntlProvider>;
}
A hook to access translations in your components.
-
sheetTitle
: The sheet title of the translation group.
const { t } = useTranslation('header');
const translatedMessage = t('login');
A function to access translations in the environment where cannot use react context and hooks.
-
sheetTitle
: The sheet title of the translation group.
The t function is used to retrieve a translation string based on a key and optionally interpolate variables. It provides flexibility to include dynamic values, such as plain strings or React components, for enhanced localization capabilities.
- key (string): The translation key to retrieve the localized string.
const translatedMessage = t('login'); // login is key
- values (object, optional): An object containing key-value pairs to interpolate into the translation string.
// John Doe shown
const translatedMessage = t('{username} shown', { username: 'John Doe' });
💡 Note: The values object can contain any type of data, including React components.
// <Username /> shown
const translatedMessage = t('{username} shown', { username: <Username /> });
A robust and flexible translation library designed for efficient handling of translations in React applications.
- Client-Side Translation (Explicit Strings): Translate explicit string keys directly in your components.
- Client-Side Translation (Dynamic Strings): Dynamically match translations from JSON for unknown variables.
- Module Translation: Use translations in the place where the react context or hooks cannot be used.
Retrieve translations for explicit keys in your React components using useTranslation
.
import React from 'react';
import { useTranslation } from './i18nContext';
const YourComponent = () => {
const { t } = useTranslation('header');
return (
<div>
<button>{t('login')}</button>
<button>{t('logout')}</button>
</div>
);
};
For scenarios where the string key is not explicitly known (e.g., coming from a server), use t.dynamic
. Ensure that your translation JSON and sheet are updated to include the variable values.
The t.dynamic function will automatically match the values from the JSON with the provided arguments and display the result.
// App.tsx
import { useTranslation } from './i18nContext';
const { t } = useTranslation('header');
const { data } = useQuery(...queryOptions);
const deviceName = data?.device?.name;
return <div>{t.dynamic(deviceName)}</div>;
The getTranslation
function allows you to use translations outside of React components, such as in static configuration files, constants, or utility modules.
It provide two possible supports
-
t
(Synchronous Translation) – Use when translation values are available at runtime. -
t.promise
(Asynchronous Translation) – Use when the module’s evaluation order is uncertain.
- For the common example, t call expression in a function module
- This behaves the same as
useTranslation
'st
function.
// module.ts
import { getTranslation } from './i18nContext';
const { t } = getTranslation('header');
export function getStatusCategory {
return [t('Total Energy Usage'), t('Total Waste Usage')];
};
// App.tsx
// the "t" call expression is evaluated at function call timing
import { getStatusCategory } from './module';
export default function App() {
return getStatusCategory().map((item) => <div>{item}</div>);
}
Result: The translation is resolved immediately during runtime.
- If the module is imported dynamically in a client-side component, the evaluation order of
getTranslation
andt
call expression may not be guaranteed. - Since JavaScript evaluates modules at import time, it may attempt to access translation values before
IntlProvider
has fully initialized the locale. - In this case, use
t.promise
to ensure the translation resolves asynchronously.
// module.ts
// The "t" result in the array will be resolved asynchronously
import { getTranslation } from './i18nContext';
const { t } = getTranslation('header');
export const STATUS_CATEGORY = [
t.promise('Total Energy Usage'),
t.promise('Total Waste Usage'),
];
// App.tsx
// So, t.promise ensure the current client-side locale data
// is fully initialized before the translations are resolved
import { STATUS_CATEGORY } from './module.ts';
export default function App() {
return (
<div>
{STATUS_CATEGORY.map((item, index) => {
return <div key={index}>{item}</div>;
})}
</div>
);
}
This project is licensed under the ISC License. See the LICENSE file for details.
Created by devAnderson.