{"_id":"@broberg/i18n","name":"@broberg/i18n","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@broberg/i18n","version":"0.1.0","description":"Headless locale engine: a framework-free createI18n() with dot-path t() (fallback chain + {var} interpolation), a bilingual() helper for {da,en} content objects, localStorage persistence + navigator.language detection, an html[lang] sync, a pub/sub with n","type":"module","license":"MIT","sideEffects":false,"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"scripts":{"build":"tsup","test":"vitest run","typecheck":"tsc --noEmit"},"devDependencies":{"tsup":"^8.3.0","typescript":"^5.6.0","vitest":"^2.1.0"},"keywords":["i18n","internationalization","localization","locale","translation","language-switch","headless","broberg"],"repository":{"type":"git","url":"git+https://github.com/broberg-ai/components.git","directory":"packages/i18n"},"publishConfig":{"access":"public"},"gitHead":"2ba6981e1363d0df7df847c51e78cb27eda32de8","_id":"@broberg/i18n@0.1.0","bugs":{"url":"https://github.com/broberg-ai/components/issues"},"homepage":"https://github.com/broberg-ai/components#readme","_nodeVersion":"25.7.0","_npmVersion":"11.10.1","dist":{"integrity":"sha512-HrLUWOdv+oNJ60I/NdM7qFBXLJcej4VQ424QDlSAyuBkXqtPZ4UhiQZkr0P8eNZ8a4CXkDWmrz6aWU7RduCnTw==","shasum":"a9ecdcfabae11ebfcbf7f34b8108246f44b45b83","tarball":"https://registry.npmjs.org/@broberg/i18n/-/i18n-0.1.0.tgz","fileCount":8,"unpackedSize":37306,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCMHN4LL1xw/jbEMGas0qh3getBgiLW9itlMaLK7o7ZQgIhAMZgHEXE/0Dbfs281WgRAtxwAUiRwHaHEMlWUiShH/LS"}]},"_npmUser":{"name":"cbroberg","email":"cb@webhouse.dk"},"directories":{},"maintainers":[{"name":"cbroberg","email":"cb@webhouse.dk"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/i18n_0.1.0_1783789245887_0.6796922219908097"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-11T17:00:45.741Z","0.1.0":"2026-07-11T17:00:46.017Z","modified":"2026-07-11T17:00:46.242Z"},"maintainers":[{"name":"cbroberg","email":"cb@webhouse.dk"}],"description":"Headless locale engine: a framework-free createI18n() with dot-path t() (fallback chain + {var} interpolation), a bilingual() helper for {da,en} content objects, localStorage persistence + navigator.language detection, an html[lang] sync, a pub/sub with n","homepage":"https://github.com/broberg-ai/components#readme","keywords":["i18n","internationalization","localization","locale","translation","language-switch","headless","broberg"],"repository":{"type":"git","url":"git+https://github.com/broberg-ai/components.git","directory":"packages/i18n"},"bugs":{"url":"https://github.com/broberg-ai/components/issues"},"license":"MIT","readme":"# @broberg/i18n\n\nA **headless locale engine** — the same ~120-line i18n core that trail,\nsanneandersen and xrt81 each hand-rolled, extracted once. Detect the locale,\npersist it, resolve a dot-path key with a fallback chain + `{var}` interpolation,\nand a `bilingual()` helper for `{da,en}` content objects. Framework-free,\nSSR-safe, and pnpm-hoist-safe. The `LanguageSwitcher` widget stays copy-owned\nper stack.\n\n```bash\nnpm i @broberg/i18n\n```\n\n## Usage\n\n```ts\nimport { createI18n } from \"@broberg/i18n\";\n\nconst i18n = createI18n({\n  locales: [\"da\", \"en\"],                // first = default\n  fallbackLocale: \"en\",                 // the complete base dict\n  messages: {\n    da: { greeting: \"Hej\", nav: { home: \"Hjem\" } },\n    en: { greeting: \"Hello\", nav: { home: \"Home\" }, welcome: \"Hi {name}\" },\n  },\n  storageKey: \"acme-locale\",\n});\n\ni18n.getLocale();                        // \"da\" (stored > navigator.language > default)\ni18n.t(\"nav.home\");                      // \"Hjem\"\ni18n.t(\"welcome\", { name: \"Sanne\" });    // \"Hi Sanne\"  (falls back to en, interpolates)\ni18n.setLocale(\"en\");                    // persists, syncs <html lang>, notifies subscribers\ni18n.bilingual({ da: \"Goddag\", en: \"Good day\" });   // active-locale string, plain-string tolerant\n\nconst off = i18n.subscribe((locale) => rerender());  // pub/sub, no context provider\n```\n\n## What it gets right\n\n- **Fallback chain** — `t(key)` resolves the active locale, then the fallback\n  locale, then returns the raw key (never a blank string).\n- **`{var}` interpolation** — `t(\"welcome\", { name })` fills placeholders.\n- **`bilingual()`** — picks the active-locale field from a `{da,en}` object and\n  tolerates a plain string, so LLM-generated bilingual content and legacy plain\n  strings both work.\n- **Detection** — stored locale → `navigator.language` prefix-match → default,\n  all SSR-guarded.\n- **pnpm-hoist safe** — a `globalThis`-keyed registry means two bundle copies\n  with the same `storageKey` share one instance, so the active locale can never\n  desync.\n\n## API\n\n```ts\ncreateI18n({ locales, defaultLocale?, fallbackLocale?, messages?, storageKey?, storage?, detect? }): I18n\n// I18n: getLocale · setLocale · subscribe · t(key, vars?) · bilingual(text) · detectInitial · locales\n```\n\nDictionaries stay **in your repo** (bundling them into the package would couple\nevery consumer's copy) — the package ships only the engine. React (Next\nURL-prefix switch) and Preact (pub/sub) `LanguageSwitcher` adapters build on this\ncore.\n\n## License\n\nMIT · part of the [`@broberg/*`](https://discovery.broberg.ai) shared inventory.\n","readmeFilename":"README.md","_rev":"1-fbdeab0810d894d46a1e748458aea956"}