@liberfi.io/i18n
v0.1.94
Published
Internationalization for Liberfi React SDK
Downloads
10,104
Readme
@liberfi.io/i18n
Internationalization and CLI tools for Liberfi React SDK. Built on the i18next ecosystem, this package provides locale management, language detection, async resource loading, and CLI tools for translation workflows. Consumed by @liberfi.io/react-app and downstream apps.
Design Philosophy
- Inversion of Control — Side effects (e.g. language-change callbacks, resource loading URLs) are injected via props/options rather than hardcoded. The
Backendclass receives its i18n instance via constructor injection for testability. - Provider-optional — The package exports a singleton
i18ninstance with sensible defaults (English fallback). Components work withoutLocaleProvider; the provider adds resource loading, language switching callbacks, and context-based configuration. - Separation of concerns — Pure utility functions (
parseI18nLang,removeLangPrefix, etc.) live inutils/with no dependencies on React or i18n state, making them usable in both client and server contexts. - Single source of truth — All locale types, enums, and default language data are defined once in
types.tsandconstant.ts, shared across client and server entry points.
Installation
pnpm add @liberfi.io/i18nPeer dependencies: react >= 18, react-dom >= 18.
API Reference
Components
| Component | Props | Description |
| ---------------- | --------------------- | -------------------------------------------------------------------------------------------------------------- |
| LocaleProvider | LocaleProviderProps | Wraps the app with i18next context, manages resource loading, language detection, and exposes LocaleContext. |
LocaleProviderProps:
| Prop | Type | Description |
| ------------------------- | ------------------------------------- | ------------------------------------------------------------ |
| locale | LocaleCode | Current locale to force. |
| resource | Record<string, string> | Resource bundle for the current locale. |
| resources | Resources | All synchronously loaded resources keyed by locale. |
| supportedLanguages | LocaleCode[] | Subset of defaultLanguages to expose. |
| convertDetectedLanguage | (lang: string) => LocaleCode | Custom conversion for the detected browser language. |
| backend | BackendOptions | Options for async resource loading via HTTP (loadPath). |
| languages | Language[] | Fully custom language list (overrides supportedLanguages). |
| beforeLanguageChange | (lang: LocaleCode) => Promise<void> | Called before language switch (e.g. load resources). |
| afterLanguageChange | (lang: LocaleCode) => Promise<void> | Called after language switch (e.g. update cookie/URL). |
Hooks
| Hook | Return | Description |
| ------------------------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| useTranslation(ns?, options?) | UseTranslationResponse | Wraps react-i18next's useTranslation, auto-falls back to the singleton i18n instance when used outside I18nextProvider. |
| useLocale() | LocaleCode | Returns the current locale code and re-renders on language change. |
| useChangeLocale() | (locale: LocaleCode) => Promise<void> | Returns a function that triggers beforeLanguageChange → i18n.changeLanguage → afterLanguageChange. |
| useLocaleContext() | LocaleContextState | Access languages, beforeLanguageChange, afterLanguageChange from context. |
Utilities
| Function | Signature | Description |
| --------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| parseI18nLang | (lang: string, localeCodes?: LocaleCode[], defaultLang?: LocaleCode) => string | Normalize a browser language string (e.g. en-US) to a supported locale code. |
| getLocalePathFromPathname | (pathname: string, localeCodes?: string[]) => string \| null | Extract the locale segment from a URL pathname (e.g. /en/markets → "en"). |
| removeLangPrefix | (pathname: string, localeCodes?: string[]) => string | Strip the locale prefix from a pathname. |
| generatePath | (params: { path: string; locale?: string; search?: string }) => string | Build a localized URL path with locale prefix and search params. |
Types & Enums
| Export | Description |
| ---------------------- | --------------------------------------------------------------------------------- |
| LocaleEnum | Enum of all 16 supported locale codes. |
| LocaleCode | keyof typeof LocaleEnum \| (string & {}) — locale code type allowing extension. |
| Language | { localCode: LocaleCode; displayName: string } |
| Resources<T> | Map of LocaleCode → partial locale messages, optionally extended with T. |
| LocaleMessages | Full English message type merged with ExtendLocaleMessages. |
| ExtendLocaleMessages | Record<"extend.${string}", string> — type for custom extension keys. |
| BackendOptions | { loadPath: (lang, ns) => string \| string[] } |
| LocaleContextState | Context shape: languages, beforeLanguageChange, afterLanguageChange. |
Constants
| Export | Value | Description |
| --------------------- | ------------------------ | ---------------------------------------------- |
| defaultLanguages | Language[] | All 16 supported languages with display names. |
| defaultLng | "en" | Default fallback language. |
| defaultNS | "translation" | Default i18next namespace. |
| i18nLocalStorageKey | "liberfi_i18nLng" | localStorage key for persisted language. |
| i18nCookieKey | "liberfi_i18nLng" | Cookie key for persisted language. |
| en | Record<string, string> | Built-in English translations. |
Integration Guide
Follow these steps to integrate localization support in your app using Liberfi React SDK:
1. Wrap Your App with LocaleProvider
The LocaleProvider is the core component that supplies localized resources to your application. Make sure to wrap your app’s root component with LocaleProvider.
import { LocaleProvider } from "@liberfi.io/i18n";
<LocaleProvider>
<YourApp />
</LocaleProvider>;2. Provide Locale Data
Default Language
- English (
en) is included by default.
Supported Locales
We currently support 16 locales
| Locale Code | Language |
| ----------- | ---------- |
| en | English |
| zh | Chinese |
| ja | Japanese |
| es | Spanish |
| ko | Korean |
| vi | Vietnamese |
| de | German |
| fr | French |
| ru | Russian |
| id | Indonesian |
| tr | Turkish |
| it | Italian |
| pt | Portuguese |
| uk | Ukrainian |
| pl | Polish |
| nl | Dutch |
CSV for Easy Translation
- Each release generates a
dist/locale.csvfile to simplify translation workflows. - We provide a CLI tool to convert between CSV and JSON formats.
3. Extending Locale Files
You can localize both the SDK UI and your own custom components.
- When adding custom keys, prefix them with
extend.to avoid conflicts with default keys.
{
"extend.custom.button.label": "My Custom Button"
}Example
Here's a complete example of how to set up the i18n integration:
Async load locale files
import { FC, ReactNode } from "react";
import { WalletConnectorProvider } from "@liberfi.io/wallet-connector";
import { LiberfiAppProvider } from "@liberfi.io/react-app";
import { LocaleProvider, LocaleEnum, LocaleCode } from "@liberfi.io/i18n";
const LiberfiProvider: FC<{ children: ReactNode }> = (props) => {
const onLanguageChanged = async (lang: LocaleCode) => {};
// please copy build-in locale files (@liberfi.io/i18n/locales) to you public/locales
// and copy you extend locale files to public/locales/extend
const loadPath = (lang: LocaleCode) => {
if (lang === LocaleEnum.en) {
// because en is built-in, we need to load the en extend only
return `/locales/extend/${lang}.json`;
}
return [`/locales/${lang}.json`, `/locales/extend/${lang}.json`];
};
return (
<LocaleProvider
onLanguageChanged={onLanguageChanged}
backend={{ loadPath }}
>
<WalletConnectorProvider>
<LiberfiAppProvider
brokerId="liberfi"
brokerName="Liberfi"
networkId="testnet"
>
{props.children}
</LiberfiAppProvider>
</WalletConnectorProvider>
</LocaleProvider>
);
};Sync Load locale data
import { FC, ReactNode } from "react";
import { WalletConnectorProvider } from "@liberfi.io/wallet-connector";
import { LiberfiAppProvider } from "@liberfi.io/react-app";
import { LocaleProvider, LocaleCode, Resources } from "@liberfi.io/i18n";
import zh from "@liberfi.io/i18n/locales/zh.json";
import ja from "@liberfi.io/i18n/locales/ja.json";
import ko from "@liberfi.io/i18n/locales/ko.json";
// extend or overrides English translations
const extendEn = {
"extend.trading": "Trading",
};
// extend or overrides chinese translations
const extendZh = {
"extend.trading": "交易",
};
// extend or overrides japanese translations
const extendJa = {
"extend.trading": "取引",
};
// extend or overrides korean translations
const extendKo = {
"extend.trading": "거래",
};
// define language resources
const resources: Resources = {
en: extendEn,
zh: {
...zh,
...extendZh,
},
ja: {
...ja,
...extendJa,
},
ko: {
...ko,
...extendKo,
},
};
const LiberfiProvider: FC<{ children: ReactNode }> = (props) => {
const onLanguageChanged = (locale: LocaleCode) => {};
return (
<LocaleProvider resources={resources} onLanguageChanged={onLocaleChange}>
<WalletConnectorProvider>
<LiberfiAppProvider
brokerId="liberfi"
brokerName="Liberfi"
networkId="testnet"
>
{props.children}
</LiberfiAppProvider>
</WalletConnectorProvider>
</LocaleProvider>
);
};Add custom languages
We also support adding more custom languages
import { FC, ReactNode } from "react";
import { WalletConnectorProvider } from "@liberfi.io/wallet-connector";
import { LiberfiAppProvider } from "@liberfi.io/react-app";
import {
LocaleProvider,
Resources,
LocaleEnum,
LocaleCode,
Language,
} from "@liberfi.io/i18n";
// japanese locale
const ja = {
"extend.ja": "日本語",
};
// korean locale
const ko = {
"extend.ko": "한국어",
};
// define language resources
const resources: Resources = {
ja,
ko,
};
// custom languages
const languages: Language[] = [
{ localCode: LocaleEnum.en, displayName: "English" },
{ localCode: LocaleEnum.ja, displayName: "日本語" },
{ localCode: LocaleEnum.ko, displayName: "한국어" },
];
const LiberfiProvider: FC<{ children: ReactNode }> = (props) => {
const onLanguageChanged = (locale: LocaleCode) => {};
return (
<LocaleProvider
resources={resources}
languages={languages}
onLanguageChanged={onLanguageChanged}
>
<WalletConnectorProvider>
<LiberfiAppProvider
brokerId="liberfi"
brokerName="Liberfi"
networkId="testnet"
>
{props.children}
</LiberfiAppProvider>
</WalletConnectorProvider>
</LocaleProvider>
);
};CLI
Usage
The package provides a CLI tool for managing Internationalization files.
npx @liberfi.io/i18n <command> [options]Commands
csv2json
Convert a locale CSV file to multiple locale JSON files.
npx @liberfi.io/i18n csv2json <input> <outputDir>Example:
npx @liberfi.io/i18n csv2json ./dist/locale.csv ./dist/localesjson2csv
Convert multiple locale JSON files to a single locale CSV file.
npx @liberfi.io/i18n json2csv <inputDir> <output>Example:
npx @liberfi.io/i18n json2csv ./locales ./dist/locale.csvdiffcsv
Compare two locale CSV files to find differences.
npx @liberfi.io/i18n diffcsv <oldFile> <newFile>Example:
npx @liberfi.io/i18n diffcsv ./dist/locale1.csv ./dist/locale2.csvfillJson
Fill values from an input locale JSON file and generate a new locale JSON file.
npx @liberfi.io/i18n fillJson <input> <output>Example:
npx @liberfi.io/i18n fillJson ./src/locale/zh.json ./dist/locale/zh.jsonseparateJson
Separate JSON files into default and extend key values based on a specified key.
npx @liberfi.io/i18n separateJson <inputDir> <outputDir> <separateKey>Example:
npx @liberfi.io/i18n separateJson ./locales ./dist/locales extendmergeJson
Merge default and extend JSON files back into one file.
npx @liberfi.io/i18n mergeJson <inputDir> <outputDir>Example:
npx @liberfi.io/i18n mergeJson ./dist/locales1 ./dist/locales2Testing
Run unit tests:
pnpm testTests cover:
- Utility functions —
parseI18nLang,getLocalePathFromPathname,removeLangPrefix,generatePath - Backend class — async resource fetching, caching, error handling
- React hooks —
useLocale,useChangeLocalelifecycle and state updates - LocaleProvider — rendering, resource injection, language switching, context propagation
Future Improvements
- Accept an
i18ninstance prop onLocaleProviderinstead of relying on the module-level singleton, enabling multiple isolated i18n contexts. - Add
onErrorcallback toBackendOptionsfor caller-controlled error handling instead ofconsole.warn. - Expose loading/error state from
Backendso consumers can show loading indicators. - Consider lazy-loading locale modules to reduce initial bundle size for apps that only need a subset of languages.
