I18n
I18n is a reactive internationalization manager based on vanilla-signal.
Installation
npm:
Shellnpm install vanilla-signal-i18n
script:
HTML<!-- ESM --><script type="module"> import { I18n, createI18n, defaultI18n, t, } from 'https://unpkg.com/vanilla-signal-i18n/dist/index.js';</script><!-- UMD: Global variable vanillaSignalI18n --><script src="https://unpkg.com/vanilla-signal-i18n/dist/index.umd.js"></script>
Import
JavaScript// esmimport { I18n, createI18n, defaultI18n, t } from 'vanilla-signal-i18n';// umd: Global variable `vanillaSignalI18n`const { I18n, createI18n, defaultI18n, t } = vanillaSignalI18n;
Basic Usage
JavaScriptconst i18n = createI18n({ locale: 'zh-CN', fallbackLocale: 'en', messages: { en: { common: { confirm: 'Confirm', hello: 'Hello {name}', }, }, zh: { common: { confirm: '确定', hello: '你好 {name}', }, }, },});i18n.t('common.confirm'); // 确定i18n.t('common.hello', { name: 'World' }); // 你好 World
Keys support dot notation paths. When a translation is not found in the current language, it falls back in the order of zh-cn -> zh -> en. If still not found, the original key is returned.
Reactive Translation
i18n.t() reads internal signals. When called within a vanilla-signal reactive context, changes to locale or messages will automatically trigger re-computation.
JavaScriptimport { createEffect } from 'vanilla-signal';const i18n = new I18n({ locale: 'en', messages: { en: { title: 'Settings' }, zh: { title: '设置' }, },});createEffect(() => { document.title = i18n.t('title');});i18n.setLocale('zh');
If you only need to read the locale signal, you can also use getLocaleSignal():
JavaScriptconst locale = i18n.getLocaleSignal();createEffect(() => { console.log(locale());});
Appending Language Packs
JavaScripti18n.addMessages('zh', { modal: { title: '提示', cancel: '取消', },});i18n.addMessages('en', { modal: { title: 'Tip', cancel: 'Cancel', },});
addMessages(locale, messages) deeply merges with existing language packs by default. To replace the language pack for a specific locale:
JavaScripti18n.addMessages('zh', { ok: '确定' }, { merge: false });
To replace or merge complete language packs:
JavaScripti18n.setMessages( { en: { save: 'Save' }, zh: { save: '保存' }, }, { merge: true });
Namespaces
createTranslator(namespace) creates a translation function with a prefix, suitable for use within components.
JavaScriptconst modalT = i18n.createTranslator('modal');modalT('title'); // Equivalent to i18n.t('modal.title')modalT('confirm');
Missing Translations
By default, missing translations return the original key. You can output warnings via warnMissing or customize the return value via missing.
JavaScriptconst i18n = createI18n({ locale: 'zh', fallbackLocale: 'en', warnMissing: true, missing: ({ key }) => `[missing:${key}]`,});
Subscribing to Changes
subscribe(handler) listens for changes in locale, fallback locale, and messages, suitable for integration with non-signal code.
JavaScriptconst unsubscribe = i18n.subscribe((event) => { console.log(event.type, event.locale);});i18n.setLocale('zh');unsubscribe();
Event types:
| Type | Triggered When |
|---|---|
locale |
Current language changes |
fallback-locale |
Fallback language changes |
messages |
Language packs are set or appended |
Default Instance
defaultI18n is the built-in default instance of the library. Legacy utility functions delegate to it:
JavaScriptimport { setLanguages, getLanguages, getLocale, getLang, t,} from 'vanilla-signal-i18n';setLanguages({ en: { ok: 'OK' }, zh: { ok: '确定' },});t('ok'); // Returns text based on current default localegetLanguages();getLocale();getLang();
t() is also compatible with the old signature:
JavaScriptt( 'ok', { en: { ok: 'OK' }, zh: { ok: '确定' }, }, 'zh'); // 确定
For new code requiring interpolation, dynamic language switching, or isolated language states for different components, it is recommended to use the i18n.t() method of an independent I18n instance.
Options
| Parameter | Type | Default | Description |
|---|---|---|---|
locale |
string |
Auto | Initial language; reads html lang or browser if empty |
fallbackLocale |
string |
'en' |
Fallback language |
messages |
Record<string, Record<string, any>> |
{} |
Language packs |
languages |
Record<string, Record<string, any>> |
{} |
Alias for messages, for backward compatibility |
missing |
(payload: object) => string |
null |
Handler function for missing translations |
warnMissing |
boolean |
false |
Whether to output warning for missing translations |
Instance Properties
The state of I18n is accessed via instance methods; no public properties are exposed for direct modification. messages are shallow/deep cloned upon writing to prevent direct reuse of external object references.
Instance Methods
| Method | Description |
|---|---|
getLocaleSignal() |
Get the signal accessor for the current locale |
getLocale() |
Get the current locale |
setLocale(locale) |
Set the current locale |
getFallbackLocale() |
Get the fallback locale |
setFallbackLocale(locale) |
Set the fallback locale |
setMessages(messages, options) |
Set complete language packs |
setLanguages(messages) |
Compatible alias for setMessages() |
addMessages(locale, messages, options) |
Append or replace language pack for a specific locale |
getMessages(locale) |
Get language pack for a specific locale; returns all if no locale provided |
getLanguages() |
Compatible alias for getMessages() |
has(key, options) |
Check if a key has an available translation |
resolve(key, options) |
Resolve translation, returning matched locale and original value |
t(key, params, options) |
Get translated text and perform interpolation |
createTranslator(namespace, defaults) |
Create a namespaced translation function |
subscribe(handler) |
Subscribe to i18n state changes, returns unsubscribe function |
destroy() |
Clean up listeners and language packs |
Translation Value Types
Translation values can be strings, numbers, booleans, or functions.
JavaScriptconst i18n = createI18n({ locale: 'en', messages: { en: { count: ({ value }) => `${value} items`, }, },});i18n.t('count', { value: 3 }); // 3 items
Functions receive two parameters:
| Parameter | Description |
|---|---|
params |
Interpolation parameters passed when calling t() |
context |
{ key, locale, i18n } |
Locale Rules
Locales are normalized to lowercase, and _ is converted to -:
JavaScripti18n.setLocale('zh_CN');i18n.getLocale(); // zh-cn
When looking up translations, it falls back in the order of full locale, base language, fallback locale, and fallback base language. For example, if the current locale is zh-CN and the fallback locale is en-US, the lookup order is:
Markdownzh-cn -> zh -> en-us -> en