soon-i18n-react
v2.0.0
Published
a lightweight nested messages i18n library with smart ts prompt can be used in react , vue , svelte , solid , etc...
Downloads
60
Maintainers
Readme
soon-i18n-react v2.0
React adapter for soon-i18n, providing hooks-based i18n integration with full TypeScript support and lazy loading capabilities.
Full Document
Install
npm install soon-i18n-reactFull Example
npx degit https://github.com/leafio/soon-i18n/examples/react-demoInstance Usage
Create an instance
// lang/index.ts
import { createI18n } from "soon-i18n-react";
const globalLocales = {
zh: { g_welcome: "全局:欢迎 {name}", common: { title: "标题" } },
en: { g_welcome: "Global: Welcome {name}", common: { title: "Title" } },
} as const;
type Lang = "zh" | "en";
export const { tLocales, useLocales, useLang, getLang, setLang } = createI18n(
{ lang: () => "zh", fallbacks: (curLang, lastLang) => ["en"] },
globalLocales
);Use in JS/TS (Sync only)
import { tLocales } from "../lang";
// tLocales only supports synchronous loading
export const showToast = () => {
const t = tLocales({
zh: { tip: "哈哈,一条中文提醒!!!" },
en: { tip: "Aha, an English tip" },
});
alert(t("tip"));
};
// For lazy loading, use useLocales in componentsUse in components
Synchronous Loading
import { useLocales } from "../lang";
const Content = () => {
const [t, inited] = useLocales({
zh: { hello: "你好" },
en: { hello: "Hello" },
});
if (!inited) {
return <div>Loading translations...</div>;
}
return (
<div>
<h1>{t("common.title")}</h1>
<p>{t("hello")}</p>
<p>{t("g_welcome", { name: "张三" })}</p>
</div>
);
};
export default Content;Lazy Loading
import { useLocales } from "../lang";
const LazyComponent = () => {
const [t, inited] = useLocales({
zh: { welcome: "欢迎" },
en: () => import("./locales/en"), // Dynamic import
ja: () => fetch("/api/translations/ja")
.then(res => res.json())
.then(data => ({ default: data })), // API fetch
});
if (!inited) {
return <div>Loading translations...</div>;
}
return (
<div>
<h2>{t("welcome")}</h2>
<p>{t("common.title")}</p>
</div>
);
};
export default LazyComponent;Change lang
import { useLang } from "../lang";
const SwitchLang = () => {
const [lang, setLang] = useLang();
return (
<div>
<p>Current language: {lang}</p>
<button onClick={() => setLang(lang === "en" ? "zh" : "en")}>
Switch language
</button>
</div>
);
};
export default SwitchLang;API Reference
createI18n(config, globalLocales?)
Creates an i18n instance with React-specific hooks.
Parameters:
config: Configuration objectlang: () => Lang: Function to get current languagefallbacks?: (curLang, lastLang) => Lang[]: Fallback languages function
globalLocales?: Global translation resources object
Returns: Object with methods:
useLocales(locales?): Hook for translations with local resourcesuseLang(): Hook for getting/setting current languagetLocales(locales?): Function for translations without reactivitygetLang(): Get current languagesetLang(lang): Set current language
useLocales(locales?)
React hook for using translations with optional local resources.
Parameters:
locales?: Local translation resources (supports sync/async)
Returns: [t, inited] tuple
t: Translation function with full type safetyinited: Boolean indicating if all translations are loaded
useLang()
React hook for getting and setting current language.
Returns: [lang, setLang] tuple
lang: Current languagesetLang: Function to change language
tLocales(locales?)
Create translator without React reactivity (for non-component code).
Parameters:
locales?: Local translation resources (only synchronous)
Returns: Translation function
Type Safety
soon-i18n-react uses SafeLocales type to ensure translation keys exist in all languages. Here are different scenarios:
✅ Case 1: All keys exist in all languages
// Type-safe - all keys exist in both languages
const t = tLocales({
zh: { button: { save: "保存", cancel: "取消" } },
en: { button: { save: "Save", cancel: "Cancel" } }
});
// ✅ This works fine
t("button.save"); // OK
t("button.cancel"); // OK❌ Case 2: Different keys in different languages
// Type error - keys don't match
const t = tLocales({
zh: { button: { save: "保存", cancel: "取消" } },
en: { button: { save: "Save" } } // ❌ Missing cancel in English
});
// ❌ TypeScript will show error
t("button.cancel"); // Type error❌ Case 3: Non-existent key
const t = tLocales({
zh: { button: { save: "保存" } },
en: { button: { save: "Save" } }
});
// ✅ This works
t("button.save"); // OK
// ❌ Type error - key doesn't exist
// t("button.delete"); // Type errorExamples
Check out the example projects:
Documentation
License
MIT
