Getting Started
Choose a Package
For most projects, install the umbrella package:
pnpm add @orderofchaos/ling
That gives you:
- React runtime APIs
- core utilities
ling-scanling-lint@orderofchaos/ling/eslint-plugin
If you want a smaller dependency surface, install the granular packages instead:
pnpm add @orderofchaos/ling-react
pnpm add -D @orderofchaos/ling-cli @orderofchaos/eslint-plugin-ling
Create Translation Files
Create a directory such as src/i18n/translations/:
// src/i18n/translations/en.ts
export const en = {
App: {
"Hello World": "Hello World",
"Welcome, {{name}}!": "Welcome, {{name}}!",
},
};
export default en;
// src/i18n/translations/ru.ts
export const ru = {
App: {
"Hello World": "Privet mir",
"Welcome, {{name}}!": "Dobro pozhalovat, {{name}}!",
},
};
export default ru;
Wrap the App with I18nProvider
// src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import {
I18nProvider,
type Translations,
} from "@orderofchaos/ling";
import App from "./App";
import { en } from "./i18n/translations/en";
import { ru } from "./i18n/translations/ru";
type AppLang = "en" | "ru";
const translations: Record<AppLang, Translations> = { en, ru };
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<I18nProvider<AppLang>
translations={translations}
defaultLanguage="en"
supportedLanguages={["en", "ru"]}
>
<App />
</I18nProvider>
</React.StrictMode>,
);
Create a Namespace Module
// src/App.tsx
import { initI18nModule } from "@orderofchaos/ling";
const { useI18n } = initI18nModule<"en" | "ru">("App");
export function App() {
const { t, language, changeLanguage } = useI18n();
return (
<div>
<h1>{t("Hello World")}</h1>
<p>{t("Welcome, {{name}}!", { name: "User" })}</p>
<p>{t("Current language: {{lang}}", { lang: language })}</p>
<button onClick={() => changeLanguage("ru")}>Russkii</button>
<button onClick={() => changeLanguage("en")}>English</button>
</div>
);
}
Extract New Keys
ling-scan creates or updates translation files by scanning t("...") calls.
pnpm ling-scan src
Then check for missing translations:
pnpm ling-lint en src/i18n/translations
Add ESLint Guardrails
Use the ESLint plugin to enforce literal translation keys:
// eslint.config.mjs
import ling from "@orderofchaos/ling/eslint-plugin";
export default [
{
plugins: { ling },
rules: {
"ling/require-literal-keys": "error",
},
},
];