rt4lang
v1.0.0
Published
rt4lang is a fork off i18n library with built-in per-language font loading and fallback support.
Maintainers
Readme
rt4lang
React i18n library with built-in per-language font loading and fallback support.
Install
npm install rt4langPeer dependencies: react >=17, react-dom >=17.
Quick Start
1. Create a config file
// rt4lang.config.ts
import { createRt4Lang } from "rt4lang";
export default createRt4Lang({
defaultLanguage: "en",
languages: {
en: {
label: "English",
messages: {
greeting: "Hello {{name}}",
cart: {
empty: "Your cart is empty",
itemCount: "{{count}} item in cart | {{count}} items in cart",
},
},
font: {
family: "Inter",
fallback: ["Arial", "sans-serif"],
source: "google",
weights: [400, 500, 700],
},
},
bn: {
label: "বাংলা",
messages: {
greeting: "হ্যালো {{name}}",
cart: {
empty: "আপনার কার্ট খালি",
itemCount: "কার্টে {{count}}টি পণ্য",
},
},
font: {
family: "Hind Siliguri",
fallback: ["SolaimanLipi", "sans-serif"],
source: "google",
weights: [400, 600],
},
},
},
});2. Wrap your app with <LanguageProvider>
import { LanguageProvider } from "rt4lang";
import rt4Config from "./rt4lang.config";
function App() {
return (
<LanguageProvider config={rt4Config}>
<YourApp />
</LanguageProvider>
);
}3. Use the hooks
import { useTranslation, useLanguage } from "rt4lang";
function Header() {
const { t, language } = useTranslation();
const { languages, setLanguage } = useLanguage();
return (
<header>
<h1>{t("greeting", { name: "Rafid" })}</h1>
<select value={language} onChange={(e) => setLanguage(e.target.value)}>
{languages.map((l) => (
<option key={l.code} value={l.code}>
{l.label}
</option>
))}
</select>
</header>
);
}Font Configuration
Each language can declare its own font. The library automatically loads and applies it when the language is active.
Google Fonts
font: {
family: "Hind Siliguri",
fallback: ["sans-serif"],
source: "google",
weights: [400, 600],
}The library builds the Google Fonts CSS2 URL and injects a <link> tag. Font is cached — switching back doesn't re-inject.
Custom URL
font: {
family: "MyBrandFont",
source: "url",
files: [
{ url: "/fonts/brand-regular.woff2", weight: 400 },
{ url: "/fonts/brand-bold.woff2", weight: 700 },
],
}Injects a <style> block with @font-face rules.
Local / Self-hosted
font: {
family: "MyLocalFont",
source: "local",
}No injection — assumes the font is already available via your own CSS. The library only sets the CSS variable.
CSS Variable
The library sets --rt4lang-font-family on document.documentElement (by default). Use it in your global CSS:
body {
font-family: var(--rt4lang-font-family);
}Or let the provider inject a scoped style by passing applyFontTo="provider".
API Reference
createRt4Lang(config)
Returns a config object with sensible defaults. No side effects.
| Option | Type | Default | Description |
|---|---|---|---|
| defaultLanguage | string | required | Language code used on first visit |
| fallbackLanguage | string | defaultLanguage | Language to fall back to for missing keys |
| persist | boolean | true | Save language choice to localStorage |
| storageKey | string | "rt4lang-language" | localStorage key |
| applyFontTo | "root" \| "provider" \| "none" | "root" | Where to set the CSS font variable |
| languages | Record<string, LanguageDefinition> | required | Language definitions |
<LanguageProvider config={...}>
| Prop | Type | Description |
|---|---|---|
| config | Rt4LangConfig | Output of createRt4Lang() |
| children | ReactNode | Your app tree |
useTranslation()
Returns { t, language }.
t(key: string, vars?: Record<string, string | number>)— looks up a translation key, applies interpolation and pluralization.language— current language code.
useLanguage()
Returns { language, languages, setLanguage, isFontLoading }.
language— current language code.languages— array of{ code, label }for all configured languages.setLanguage(code)— switch language (loads font, persists choice).isFontLoading—truewhile the new language's font is loading.
Pluralization
Use the "singular | plural" pattern with a count variable:
messages: {
itemCount: "{{count}} item | {{count}} items",
}t("itemCount", { count: 1 }); // "1 item"
t("itemCount", { count: 5 }); // "5 items"Interpolation
Use {{variableName}} in messages:
t("greeting", { name: "Rafid" }); // "Hello Rafid"Missing Keys
Missing keys return the key itself and log a warning to the console:
t("missing.key"); // "missing.key" + console.warnSSR / Next.js
The library is SSR-safe — no window/document access happens during render. All DOM work (font loading, CSS variable injection) happens inside useEffect in the provider.
For Next.js App Router, wrap your root layout:
"use client";
import { LanguageProvider } from "rt4lang";
import rt4Config from "./rt4lang.config";
export default function RootLayout({ children }) {
return (
<html>
<body>
<LanguageProvider config={rt4Config}>
{children}
</LanguageProvider>
</body>
</html>
);
}License
MIT
