@brainz-digital/i18n
v0.3.0
Published
Type-safe i18n library with ICU MessageFormat support, React context, and CLI tools
Downloads
129
Maintainers
Readme
@brainz-digital/i18n
Type-safe internationalization library with ICU MessageFormat support, React context, and CLI tools.
Features
- Type-safe translations - Full TypeScript support with generated types
- ICU MessageFormat - Support for plurals, selects, and rich formatting
- React integration - Context provider and hooks for React apps
- CLI tools - Extract keys, convert locales, sync with Localise.biz
Installation
npm install @brainz-digital/i18n
# or
bun add @brainz-digital/i18n
# or
pnpm add @brainz-digital/i18nNo registry configuration or authentication is required — the package is published publicly to npm.
Requirements: Node.js >= 20 (or Bun). The package ships compiled ESM with type declarations and is usable from any bundler or runtime that supports ES modules.
react is an optional peer dependency; it is only needed if you import the
@brainz-digital/i18n/context subpath.
Quick Start
1. Create locale files
Create JSON locale files in src/locales/:
// src/locales/en.json
{
"greeting": "Hello, {name}!",
"items.count": "{count, plural, one {# item} other {# items}}"
}2. Configure i18n
Create i18n.config.ts in your project root:
import { defineConfig } from "@brainz-digital/i18n/config";
export default defineConfig({
srcDir: "./src",
localesDir: "./src/locales",
tsconfig: "tsconfig.json",
});3. Convert locales to TypeScript
Run the convert command to generate typed locale files:
npx i18n convertThis generates:
src/locales/en-intl.ts- Parsed ICU messagessrc/locales/types.ts- TypeScript types for all keys
4. Create i18n instance
// src/lib/i18n.ts
import { createI18n } from "@brainz-digital/i18n";
import type { Key, Keys, Locale } from "@/locales/types";
import { Locale as LocaleValues } from "@/locales/types";
import en from "@/locales/en-intl";
export const { translator, _, _any, isValidLang, locales } = createI18n<Keys, Locale>(
LocaleValues,
LocaleValues.EN,
);
// Load translations
translator.add(LocaleValues.EN, en);
export type { Key, Keys, Locale };5. Use in your app
import { _ } from "@/lib/i18n";
function Greeting({ name }: { name: string }) {
return <h1>{_("greeting", { name })}</h1>;
}
function ItemCount({ count }: { count: number }) {
return <span>{_("items.count", { count })}</span>;
}React Context (Optional)
For apps that need dynamic locale switching:
// src/lib/i18n-context.ts
import { createI18nContext, createUseI18n } from "@brainz-digital/i18n/context";
import type { Keys, Locale } from "@/locales/types";
export const I18nContext = createI18nContext<Keys, Locale>();
export const useI18n = createUseI18n(I18nContext);// src/providers/i18n-provider.tsx
import { useState, useCallback, type ReactNode } from "react";
import { I18nContext } from "@/lib/i18n-context";
import { translator } from "@/lib/i18n";
import type { Locale } from "@/locales/types";
export function I18nProvider({ children }: { children: ReactNode }) {
const [locale, setLocale] = useState(translator.locale);
const changeLocale = useCallback(async (newLocale: Locale) => {
// Dynamically load locale if not already loaded
if (!translator.hasLocale(newLocale)) {
const module = await import(`@/locales/${newLocale}-intl.ts`);
translator.add(newLocale, module.default);
}
translator.changeLocale(newLocale);
setLocale(newLocale);
}, []);
return (
<I18nContext.Provider value={{ translator, locale, changeLocale }}>
{children}
</I18nContext.Provider>
);
}CLI Commands
# Convert JSON locales to TypeScript with ICU parsing
npx i18n convert
# Extract translation keys from source code (dry-run)
npx i18n extract
# Upload new keys to Localise.biz
npx i18n upload
# Download translations from Localise.biz
npx i18n download
# Import CSV files to Localise.biz
npx i18n importConfiguration
Full configuration options in i18n.config.ts:
import { defineConfig } from "@brainz-digital/i18n/config";
export default defineConfig({
srcDir: "./src",
tsconfig: "tsconfig.json",
localesDir: "./src/locales",
typesPath: "./src/locales/types.ts",
localise: {
apiKey: process.env.LOCO_API_KEY,
projectId: "your-project-id",
},
extract: {
functionNames: ["_", "translator.translate"],
},
});ICU MessageFormat Examples
{
"simple": "Hello, world!",
"interpolation": "Hello, {name}!",
"plural": "{count, plural, one {# item} other {# items}}",
"select": "{gender, select, male {He} female {She} other {They}} liked this",
"nested": "{count, plural, one {{name} has # message} other {{name} has # messages}}",
"rich": "Click <link>here</link> to continue"
}API Reference
createI18n<TKeys, TLocale>(localeValues, defaultLocale)
Creates an i18n instance with typed translation functions.
Returns:
translator- The Translator instance_- Type-safe translation function_any- Untyped translation function (for dynamic keys)isValidLang- Locale validator functionlocales- Array of available locales
Translator class
add(locale, translations)- Add translations for a localetranslate(id, data?)- Translate a key (type-safe)translateAny(id, data?)- Translate any key (untyped)changeLocale(locale)- Switch current localehasLocale(locale)- Check if locale is loaded
License
MIT
