@pyreon/i18n 0.3.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5386,7 +5386,7 @@ var drawChart = (function (exports) {
5386
5386
  </script>
5387
5387
  <script>
5388
5388
  /*<!--*/
5389
- const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"2a0ea7b0-1","name":"interpolation.ts"},{"uid":"2a0ea7b0-3","name":"pluralization.ts"},{"uid":"2a0ea7b0-5","name":"create-i18n.ts"},{"uid":"2a0ea7b0-7","name":"context.ts"},{"uid":"2a0ea7b0-9","name":"trans.ts"},{"uid":"2a0ea7b0-11","name":"index.ts"}]}]}],"isRoot":true},"nodeParts":{"2a0ea7b0-1":{"renderedLength":711,"gzipLength":437,"brotliLength":0,"metaUid":"2a0ea7b0-0"},"2a0ea7b0-3":{"renderedLength":560,"gzipLength":337,"brotliLength":0,"metaUid":"2a0ea7b0-2"},"2a0ea7b0-5":{"renderedLength":5789,"gzipLength":1812,"brotliLength":0,"metaUid":"2a0ea7b0-4"},"2a0ea7b0-7":{"renderedLength":954,"gzipLength":521,"brotliLength":0,"metaUid":"2a0ea7b0-6"},"2a0ea7b0-9":{"renderedLength":2143,"gzipLength":987,"brotliLength":0,"metaUid":"2a0ea7b0-8"},"2a0ea7b0-11":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"2a0ea7b0-10"}},"nodeMetas":{"2a0ea7b0-0":{"id":"/src/interpolation.ts","moduleParts":{"index.js":"2a0ea7b0-1"},"imported":[],"importedBy":[{"uid":"2a0ea7b0-10"},{"uid":"2a0ea7b0-4"}]},"2a0ea7b0-2":{"id":"/src/pluralization.ts","moduleParts":{"index.js":"2a0ea7b0-3"},"imported":[],"importedBy":[{"uid":"2a0ea7b0-10"},{"uid":"2a0ea7b0-4"}]},"2a0ea7b0-4":{"id":"/src/create-i18n.ts","moduleParts":{"index.js":"2a0ea7b0-5"},"imported":[{"uid":"2a0ea7b0-12"},{"uid":"2a0ea7b0-0"},{"uid":"2a0ea7b0-2"}],"importedBy":[{"uid":"2a0ea7b0-10"}]},"2a0ea7b0-6":{"id":"/src/context.ts","moduleParts":{"index.js":"2a0ea7b0-7"},"imported":[{"uid":"2a0ea7b0-13"}],"importedBy":[{"uid":"2a0ea7b0-10"}]},"2a0ea7b0-8":{"id":"/src/trans.ts","moduleParts":{"index.js":"2a0ea7b0-9"},"imported":[{"uid":"2a0ea7b0-13"}],"importedBy":[{"uid":"2a0ea7b0-10"}]},"2a0ea7b0-10":{"id":"/src/index.ts","moduleParts":{"index.js":"2a0ea7b0-11"},"imported":[{"uid":"2a0ea7b0-4"},{"uid":"2a0ea7b0-0"},{"uid":"2a0ea7b0-2"},{"uid":"2a0ea7b0-6"},{"uid":"2a0ea7b0-8"}],"importedBy":[],"isEntry":true},"2a0ea7b0-12":{"id":"@pyreon/reactivity","moduleParts":{},"imported":[],"importedBy":[{"uid":"2a0ea7b0-4"}]},"2a0ea7b0-13":{"id":"@pyreon/core","moduleParts":{},"imported":[],"importedBy":[{"uid":"2a0ea7b0-6"},{"uid":"2a0ea7b0-8"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
5389
+ const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"3f0f3dda-1","name":"context.ts"},{"uid":"3f0f3dda-3","name":"interpolation.ts"},{"uid":"3f0f3dda-5","name":"pluralization.ts"},{"uid":"3f0f3dda-7","name":"create-i18n.ts"},{"uid":"3f0f3dda-11","name":"trans.tsx"},{"uid":"3f0f3dda-13","name":"index.ts"}]},{"name":"home/runner/work/fundamentals/fundamentals/node_modules/.bun/@pyreon+core@0.6.0/node_modules/@pyreon/core/lib/jsx-runtime.js","uid":"3f0f3dda-9"}]}],"isRoot":true},"nodeParts":{"3f0f3dda-1":{"renderedLength":902,"gzipLength":490,"brotliLength":0,"metaUid":"3f0f3dda-0"},"3f0f3dda-3":{"renderedLength":711,"gzipLength":437,"brotliLength":0,"metaUid":"3f0f3dda-2"},"3f0f3dda-5":{"renderedLength":560,"gzipLength":337,"brotliLength":0,"metaUid":"3f0f3dda-4"},"3f0f3dda-7":{"renderedLength":5789,"gzipLength":1812,"brotliLength":0,"metaUid":"3f0f3dda-6"},"3f0f3dda-9":{"renderedLength":1758,"gzipLength":884,"brotliLength":0,"metaUid":"3f0f3dda-8"},"3f0f3dda-11":{"renderedLength":2167,"gzipLength":1003,"brotliLength":0,"metaUid":"3f0f3dda-10"},"3f0f3dda-13":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"3f0f3dda-12"}},"nodeMetas":{"3f0f3dda-0":{"id":"/src/context.ts","moduleParts":{"index.js":"3f0f3dda-1"},"imported":[{"uid":"3f0f3dda-14"}],"importedBy":[{"uid":"3f0f3dda-12"}]},"3f0f3dda-2":{"id":"/src/interpolation.ts","moduleParts":{"index.js":"3f0f3dda-3"},"imported":[],"importedBy":[{"uid":"3f0f3dda-12"},{"uid":"3f0f3dda-6"}]},"3f0f3dda-4":{"id":"/src/pluralization.ts","moduleParts":{"index.js":"3f0f3dda-5"},"imported":[],"importedBy":[{"uid":"3f0f3dda-12"},{"uid":"3f0f3dda-6"}]},"3f0f3dda-6":{"id":"/src/create-i18n.ts","moduleParts":{"index.js":"3f0f3dda-7"},"imported":[{"uid":"3f0f3dda-15"},{"uid":"3f0f3dda-2"},{"uid":"3f0f3dda-4"}],"importedBy":[{"uid":"3f0f3dda-12"}]},"3f0f3dda-8":{"id":"/home/runner/work/fundamentals/fundamentals/node_modules/.bun/@pyreon+core@0.6.0/node_modules/@pyreon/core/lib/jsx-runtime.js","moduleParts":{"index.js":"3f0f3dda-9"},"imported":[],"importedBy":[{"uid":"3f0f3dda-10"}]},"3f0f3dda-10":{"id":"/src/trans.tsx","moduleParts":{"index.js":"3f0f3dda-11"},"imported":[{"uid":"3f0f3dda-8"}],"importedBy":[{"uid":"3f0f3dda-12"}]},"3f0f3dda-12":{"id":"/src/index.ts","moduleParts":{"index.js":"3f0f3dda-13"},"imported":[{"uid":"3f0f3dda-0"},{"uid":"3f0f3dda-6"},{"uid":"3f0f3dda-2"},{"uid":"3f0f3dda-4"},{"uid":"3f0f3dda-10"}],"importedBy":[],"isEntry":true},"3f0f3dda-14":{"id":"@pyreon/core","moduleParts":{},"imported":[],"importedBy":[{"uid":"3f0f3dda-0"}]},"3f0f3dda-15":{"id":"@pyreon/reactivity","moduleParts":{},"imported":[],"importedBy":[{"uid":"3f0f3dda-6"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
5390
5390
 
5391
5391
  const run = () => {
5392
5392
  const width = window.innerWidth;
package/lib/index.js CHANGED
@@ -1,6 +1,41 @@
1
+ import { createContext, provide, useContext } from "@pyreon/core";
1
2
  import { computed, signal } from "@pyreon/reactivity";
2
- import { Fragment, createContext, h, onUnmount, popContext, pushContext, useContext } from "@pyreon/core";
3
3
 
4
+ //#region src/context.ts
5
+ const I18nContext = createContext(null);
6
+ /**
7
+ * Provide an i18n instance to the component tree.
8
+ *
9
+ * @example
10
+ * const i18n = createI18n({ locale: 'en', messages: { en: { hello: 'Hello' } } })
11
+ *
12
+ * // In JSX:
13
+ * <I18nProvider instance={i18n}>
14
+ * <App />
15
+ * </I18nProvider>
16
+ */
17
+ function I18nProvider(props) {
18
+ provide(I18nContext, props.instance);
19
+ const ch = props.children;
20
+ return typeof ch === "function" ? ch() : ch;
21
+ }
22
+ /**
23
+ * Access the i18n instance from the nearest I18nProvider.
24
+ * Must be called within a component tree wrapped by I18nProvider.
25
+ *
26
+ * @example
27
+ * function Greeting() {
28
+ * const { t, locale } = useI18n()
29
+ * return <h1>{t('greeting', { name: 'World' })}</h1>
30
+ * }
31
+ */
32
+ function useI18n() {
33
+ const instance = useContext(I18nContext);
34
+ if (!instance) throw new Error("[@pyreon/i18n] useI18n() must be used within an <I18nProvider>.");
35
+ return instance;
36
+ }
37
+
38
+ //#endregion
4
39
  //#region src/interpolation.ts
5
40
  const INTERPOLATION_RE = /\{\{(\s*\w+\s*)\}\}/g;
6
41
  /**
@@ -220,43 +255,58 @@ function createI18n(options) {
220
255
  }
221
256
 
222
257
  //#endregion
223
- //#region src/context.ts
224
- const I18nContext = createContext(null);
258
+ //#region ../../node_modules/.bun/@pyreon+core@0.6.0/node_modules/@pyreon/core/lib/jsx-runtime.js
259
+ /** Marker for fragment nodes — renders children without a wrapper element */
260
+ const Fragment = Symbol("Pyreon.Fragment");
225
261
  /**
226
- * Provide an i18n instance to the component tree.
227
- *
228
- * @example
229
- * const i18n = createI18n({ locale: 'en', messages: { en: { hello: 'Hello' } } })
262
+ * Hyperscript function the compiled output of JSX.
263
+ * `<div class="x">hello</div>` → `h("div", { class: "x" }, "hello")`
230
264
  *
231
- * // In JSX:
232
- * <I18nProvider instance={i18n}>
233
- * <App />
234
- * </I18nProvider>
265
+ * Generic on P so TypeScript validates props match the component's signature
266
+ * at the call site, then stores the result in the loosely-typed VNode.
235
267
  */
236
- function I18nProvider(props) {
237
- pushContext(new Map([[I18nContext.id, props.instance]]));
238
- onUnmount(() => popContext());
239
- const ch = props.children;
240
- return typeof ch === "function" ? ch() : ch;
268
+ /** Shared empty props sentinel — identity-checked in mountElement to skip applyProps. */
269
+ const EMPTY_PROPS = {};
270
+ function h(type, props, ...children) {
271
+ return {
272
+ type,
273
+ props: props ?? EMPTY_PROPS,
274
+ children: normalizeChildren(children),
275
+ key: props?.key ?? null
276
+ };
277
+ }
278
+ function normalizeChildren(children) {
279
+ for (let i = 0; i < children.length; i++) if (Array.isArray(children[i])) return flattenChildren(children);
280
+ return children;
281
+ }
282
+ function flattenChildren(children) {
283
+ const result = [];
284
+ for (const child of children) if (Array.isArray(child)) result.push(...flattenChildren(child));
285
+ else result.push(child);
286
+ return result;
241
287
  }
242
288
  /**
243
- * Access the i18n instance from the nearest I18nProvider.
244
- * Must be called within a component tree wrapped by I18nProvider.
289
+ * JSX automatic runtime.
245
290
  *
246
- * @example
247
- * function Greeting() {
248
- * const { t, locale } = useI18n()
249
- * return <h1>{t('greeting', { name: 'World' })}</h1>
250
- * }
291
+ * When tsconfig has `"jsxImportSource": "@pyreon/core"`, the TS/bundler compiler
292
+ * rewrites JSX to imports from this file automatically:
293
+ * <div class="x" /> → jsx("div", { class: "x" })
251
294
  */
252
- function useI18n() {
253
- const instance = useContext(I18nContext);
254
- if (!instance) throw new Error("[@pyreon/i18n] useI18n() must be used within an <I18nProvider>.");
255
- return instance;
295
+ function jsx(type, props, key) {
296
+ const { children, ...rest } = props;
297
+ const propsWithKey = key != null ? {
298
+ ...rest,
299
+ key
300
+ } : rest;
301
+ if (typeof type === "function") return h(type, children !== void 0 ? {
302
+ ...propsWithKey,
303
+ children
304
+ } : propsWithKey);
305
+ return h(type, propsWithKey, ...children === void 0 ? [] : Array.isArray(children) ? children : [children]);
256
306
  }
257
307
 
258
308
  //#endregion
259
- //#region src/trans.ts
309
+ //#region src/trans.tsx
260
310
  const TAG_RE = /<(\w+)>([^<]*)<\/\1>/g;
261
311
  /**
262
312
  * Parse a translated string into an array of plain text and rich tag segments.
@@ -317,12 +367,12 @@ function Trans(props) {
317
367
  if (!props.components) return translated;
318
368
  const parts = parseRichText(translated);
319
369
  if (parts.length === 1 && typeof parts[0] === "string") return parts[0];
320
- return h(Fragment, null, ...parts.map((part) => {
370
+ return /* @__PURE__ */ jsx(Fragment, { children: parts.map((part) => {
321
371
  if (typeof part === "string") return part;
322
372
  const component = props.components[part.tag];
323
373
  if (!component) return part.children;
324
374
  return component(part.children);
325
- }));
375
+ }) });
326
376
  }
327
377
 
328
378
  //#endregion
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/interpolation.ts","../src/pluralization.ts","../src/create-i18n.ts","../src/context.ts","../src/trans.ts"],"sourcesContent":["import type { InterpolationValues } from './types'\n\nconst INTERPOLATION_RE = /\\{\\{(\\s*\\w+\\s*)\\}\\}/g\n\n/**\n * Replace `{{key}}` placeholders in a string with values from the given record.\n * Supports optional whitespace inside braces: `{{ name }}` works too.\n * Unmatched placeholders are left as-is.\n */\nexport function interpolate(\n template: string,\n values?: InterpolationValues,\n): string {\n if (!values || !template.includes('{{')) return template\n return template.replace(INTERPOLATION_RE, (_, key: string) => {\n const trimmed = key.trim()\n const value = values[trimmed]\n if (value === undefined) return `{{${trimmed}}}`\n // Safely coerce — guard against malicious toString/valueOf\n try {\n return typeof value === 'object' && value !== null\n ? JSON.stringify(value)\n : `${value}`\n } catch {\n return `{{${trimmed}}}`\n }\n })\n}\n","import type { PluralRules } from './types'\n\n/**\n * Resolve the plural category for a given count and locale.\n *\n * Uses custom rules if provided, otherwise falls back to `Intl.PluralRules`.\n * Returns CLDR plural categories: \"zero\", \"one\", \"two\", \"few\", \"many\", \"other\".\n */\nexport function resolvePluralCategory(\n locale: string,\n count: number,\n customRules?: PluralRules,\n): string {\n // Custom rules take priority\n if (customRules?.[locale]) {\n return customRules[locale](count)\n }\n\n // Use Intl.PluralRules if available\n if (typeof Intl !== 'undefined' && Intl.PluralRules) {\n try {\n const pr = new Intl.PluralRules(locale)\n return pr.select(count)\n } catch {\n // Invalid locale — fall through\n }\n }\n\n // Basic fallback\n return count === 1 ? 'one' : 'other'\n}\n","import { signal, computed } from '@pyreon/reactivity'\nimport type {\n I18nOptions,\n I18nInstance,\n TranslationDictionary,\n InterpolationValues,\n} from './types'\nimport { interpolate } from './interpolation'\nimport { resolvePluralCategory } from './pluralization'\n\n/**\n * Resolve a dot-separated key path in a nested dictionary.\n * E.g. \"user.greeting\" → dictionary.user.greeting\n */\nfunction resolveKey(\n dict: TranslationDictionary,\n keyPath: string,\n): string | undefined {\n const parts = keyPath.split('.')\n let current: TranslationDictionary | string = dict\n\n for (const part of parts) {\n if (current == null || typeof current === 'string') return undefined\n current = current[part] as TranslationDictionary | string\n }\n\n return typeof current === 'string' ? current : undefined\n}\n\n/**\n * Deep-merge source into target (mutates target).\n */\nfunction deepMerge(\n target: TranslationDictionary,\n source: TranslationDictionary,\n): void {\n for (const key of Object.keys(source)) {\n if (key === '__proto__' || key === 'constructor' || key === 'prototype')\n continue\n const sourceVal = source[key]\n const targetVal = target[key]\n if (\n typeof sourceVal === 'object' &&\n sourceVal !== null &&\n typeof targetVal === 'object' &&\n targetVal !== null\n ) {\n deepMerge(\n targetVal as TranslationDictionary,\n sourceVal as TranslationDictionary,\n )\n } else {\n target[key] = sourceVal!\n }\n }\n}\n\n/**\n * Create a reactive i18n instance.\n *\n * @example\n * const i18n = createI18n({\n * locale: 'en',\n * fallbackLocale: 'en',\n * messages: {\n * en: { greeting: 'Hello {{name}}!' },\n * de: { greeting: 'Hallo {{name}}!' },\n * },\n * })\n *\n * // Reactive translation — re-evaluates on locale change\n * i18n.t('greeting', { name: 'Alice' }) // \"Hello Alice!\"\n * i18n.locale.set('de')\n * i18n.t('greeting', { name: 'Alice' }) // \"Hallo Alice!\"\n *\n * @example\n * // Async namespace loading\n * const i18n = createI18n({\n * locale: 'en',\n * loader: async (locale, namespace) => {\n * const mod = await import(`./locales/${locale}/${namespace}.json`)\n * return mod.default\n * },\n * })\n * await i18n.loadNamespace('auth')\n * i18n.t('auth:errors.invalid') // looks up \"errors.invalid\" in \"auth\" namespace\n */\nexport function createI18n(options: I18nOptions): I18nInstance {\n const {\n fallbackLocale,\n loader,\n defaultNamespace = 'common',\n pluralRules,\n onMissingKey,\n } = options\n\n // ── Reactive state ──────────────────────────────────────────────────\n\n const locale = signal(options.locale)\n\n // Internal store: locale → namespace → dictionary\n // We use a version counter to trigger reactive updates when messages change,\n // since the store is mutated in place (Object.is would skip same-reference sets).\n const store = new Map<string, Map<string, TranslationDictionary>>()\n const storeVersion = signal(0)\n\n // Loading state\n const pendingLoads = signal(0)\n const loadedNsVersion = signal(0)\n\n // In-flight load promises — deduplicates concurrent loads for the same locale:namespace\n const pendingPromises = new Map<string, Promise<void>>()\n\n const isLoading = computed(() => pendingLoads() > 0)\n const loadedNamespaces = computed(() => {\n loadedNsVersion()\n const currentLocale = locale()\n const nsMap = store.get(currentLocale)\n return new Set(nsMap ? nsMap.keys() : [])\n })\n const availableLocales = computed(() => {\n storeVersion() // subscribe to store changes\n return [...store.keys()]\n })\n\n // ── Initialize static messages ──────────────────────────────────────\n\n if (options.messages) {\n for (const [loc, dict] of Object.entries(options.messages)) {\n const nsMap = new Map<string, TranslationDictionary>()\n nsMap.set(defaultNamespace, dict)\n store.set(loc, nsMap)\n }\n }\n\n // ── Internal helpers ────────────────────────────────────────────────\n\n function getNamespaceMap(loc: string): Map<string, TranslationDictionary> {\n let nsMap = store.get(loc)\n if (!nsMap) {\n nsMap = new Map()\n store.set(loc, nsMap)\n }\n return nsMap\n }\n\n function lookupKey(\n loc: string,\n namespace: string,\n keyPath: string,\n ): string | undefined {\n const nsMap = store.get(loc)\n if (!nsMap) return undefined\n const dict = nsMap.get(namespace)\n if (!dict) return undefined\n return resolveKey(dict, keyPath)\n }\n\n function resolveTranslation(\n key: string,\n values?: InterpolationValues,\n ): string {\n // Subscribe to reactive dependencies\n const currentLocale = locale()\n storeVersion()\n\n // Parse key: \"namespace:key.path\" or just \"key.path\"\n let namespace = defaultNamespace\n let keyPath = key\n\n const colonIndex = key.indexOf(':')\n if (colonIndex > 0) {\n namespace = key.slice(0, colonIndex)\n keyPath = key.slice(colonIndex + 1)\n }\n\n // Handle pluralization: if values contain `count`, try plural suffixes\n if (values && 'count' in values) {\n const count = Number(values.count)\n const category = resolvePluralCategory(currentLocale, count, pluralRules)\n\n // Try exact form first (e.g. \"items_one\"), then fall back to base key\n const pluralKey = `${keyPath}_${category}`\n const pluralResult =\n lookupKey(currentLocale, namespace, pluralKey) ??\n (fallbackLocale\n ? lookupKey(fallbackLocale, namespace, pluralKey)\n : undefined)\n\n if (pluralResult) {\n return interpolate(pluralResult, values)\n }\n }\n\n // Standard lookup: current locale → fallback locale\n const result =\n lookupKey(currentLocale, namespace, keyPath) ??\n (fallbackLocale\n ? lookupKey(fallbackLocale, namespace, keyPath)\n : undefined)\n\n if (result !== undefined) {\n return interpolate(result, values)\n }\n\n // Missing key handler\n if (onMissingKey) {\n const custom = onMissingKey(currentLocale, key, namespace)\n if (custom !== undefined) return custom!\n }\n\n // Return the key itself as a visual fallback\n return key\n }\n\n // ── Public API ──────────────────────────────────────────────────────\n\n const t = (key: string, values?: InterpolationValues): string => {\n return resolveTranslation(key, values)\n }\n\n const loadNamespace = async (\n namespace: string,\n loc?: string,\n ): Promise<void> => {\n if (!loader) return\n\n const targetLocale = loc ?? locale.peek()\n const cacheKey = `${targetLocale}:${namespace}`\n const nsMap = getNamespaceMap(targetLocale)\n\n // Skip if already loaded\n if (nsMap.has(namespace)) return\n\n // Deduplicate concurrent loads for the same locale:namespace\n const existing = pendingPromises.get(cacheKey)\n if (existing) return existing\n\n pendingLoads.update((n) => n + 1)\n\n const promise = loader(targetLocale, namespace)\n .then((dict) => {\n if (dict) {\n nsMap.set(namespace, dict)\n storeVersion.update((n) => n + 1)\n loadedNsVersion.update((n) => n + 1)\n }\n })\n .finally(() => {\n pendingPromises.delete(cacheKey)\n pendingLoads.update((n) => n - 1)\n })\n\n pendingPromises.set(cacheKey, promise)\n return promise\n }\n\n const exists = (key: string): boolean => {\n const currentLocale = locale.peek()\n\n let namespace = defaultNamespace\n let keyPath = key\n const colonIndex = key.indexOf(':')\n if (colonIndex > 0) {\n namespace = key.slice(0, colonIndex)\n keyPath = key.slice(colonIndex + 1)\n }\n\n return (\n lookupKey(currentLocale, namespace, keyPath) !== undefined ||\n (fallbackLocale\n ? lookupKey(fallbackLocale, namespace, keyPath) !== undefined\n : false)\n )\n }\n\n const addMessages = (\n loc: string,\n messages: TranslationDictionary,\n namespace?: string,\n ): void => {\n const ns = namespace ?? defaultNamespace\n const nsMap = getNamespaceMap(loc)\n const existing = nsMap.get(ns)\n\n if (existing) {\n deepMerge(existing, messages)\n } else {\n // Deep-clone to prevent external mutation from corrupting the store\n const cloned: TranslationDictionary = {}\n deepMerge(cloned, messages)\n nsMap.set(ns, cloned)\n }\n\n storeVersion.update((n) => n + 1)\n loadedNsVersion.update((n) => n + 1)\n }\n\n return {\n t,\n locale,\n loadNamespace,\n isLoading,\n loadedNamespaces,\n exists,\n addMessages,\n availableLocales,\n }\n}\n","import {\n createContext,\n pushContext,\n popContext,\n onUnmount,\n useContext,\n} from '@pyreon/core'\nimport type { VNodeChild, VNode, Props } from '@pyreon/core'\nimport type { I18nInstance } from './types'\n\nexport const I18nContext = createContext<I18nInstance | null>(null)\n\nexport interface I18nProviderProps extends Props {\n instance: I18nInstance\n children?: VNodeChild\n}\n\n/**\n * Provide an i18n instance to the component tree.\n *\n * @example\n * const i18n = createI18n({ locale: 'en', messages: { en: { hello: 'Hello' } } })\n *\n * // In JSX:\n * <I18nProvider instance={i18n}>\n * <App />\n * </I18nProvider>\n */\nexport function I18nProvider(props: I18nProviderProps): VNode {\n const frame = new Map([[I18nContext.id, props.instance]])\n pushContext(frame)\n\n onUnmount(() => popContext())\n\n const ch = props.children\n return (typeof ch === 'function' ? (ch as () => VNodeChild)() : ch) as VNode\n}\n\n/**\n * Access the i18n instance from the nearest I18nProvider.\n * Must be called within a component tree wrapped by I18nProvider.\n *\n * @example\n * function Greeting() {\n * const { t, locale } = useI18n()\n * return <h1>{t('greeting', { name: 'World' })}</h1>\n * }\n */\nexport function useI18n(): I18nInstance {\n const instance = useContext(I18nContext)\n if (!instance) {\n throw new Error(\n '[@pyreon/i18n] useI18n() must be used within an <I18nProvider>.',\n )\n }\n return instance\n}\n","import { h, Fragment } from '@pyreon/core'\nimport type { VNode, Props } from '@pyreon/core'\nimport type { InterpolationValues } from './types'\n\nconst TAG_RE = /<(\\w+)>([^<]*)<\\/\\1>/g\n\ninterface RichPart {\n tag: string\n children: string\n}\n\n/**\n * Parse a translated string into an array of plain text and rich tag segments.\n *\n * @example\n * parseRichText(\"Hello <bold>world</bold>, click <link>here</link>\")\n * // → [\"Hello \", { tag: \"bold\", children: \"world\" }, \", click \", { tag: \"link\", children: \"here\" }]\n */\nexport function parseRichText(text: string): (string | RichPart)[] {\n const parts: (string | RichPart)[] = []\n let lastIndex = 0\n\n for (const match of text.matchAll(TAG_RE)) {\n const before = text.slice(lastIndex, match.index)\n if (before) parts.push(before)\n parts.push({ tag: match[1]!, children: match[2]! })\n lastIndex = match.index! + match[0].length\n }\n\n const after = text.slice(lastIndex)\n if (after) parts.push(after)\n\n return parts\n}\n\nexport interface TransProps extends Props {\n /** Translation key (supports namespace:key syntax). */\n i18nKey: string\n /** Interpolation values for {{placeholder}} syntax. */\n values?: InterpolationValues\n /**\n * Component map for rich interpolation.\n * Keys match tag names in the translation string.\n * Values are component functions: `(children: any) => VNode`\n *\n * @example\n * // Translation: \"Read the <terms>terms</terms> and <privacy>policy</privacy>\"\n * components={{\n * terms: (children) => <a href=\"/terms\">{children}</a>,\n * privacy: (children) => <a href=\"/privacy\">{children}</a>,\n * }}\n */\n components?: Record<string, (children: any) => any>\n /**\n * The i18n instance's `t` function.\n * Can be obtained from `useI18n()` or passed directly.\n */\n t: (key: string, values?: InterpolationValues) => string\n}\n\n/**\n * Rich JSX interpolation component for translations.\n *\n * Allows embedding JSX components within translated strings using XML-like tags.\n * The `t` function resolves the translation and interpolates `{{values}}` first,\n * then `<tag>content</tag>` patterns are mapped to the provided components.\n *\n * @example\n * // Translation: \"You have <bold>{{count}}</bold> unread messages\"\n * const { t } = useI18n()\n * <Trans\n * t={t}\n * i18nKey=\"messages.unread\"\n * values={{ count: 5 }}\n * components={{\n * bold: (children) => <strong>{children}</strong>,\n * }}\n * />\n * // Renders: You have <strong>5</strong> unread messages\n *\n * @example\n * // Translation: \"Read our <terms>terms of service</terms> and <privacy>privacy policy</privacy>\"\n * <Trans\n * t={t}\n * i18nKey=\"legal\"\n * components={{\n * terms: (children) => <a href=\"/terms\">{children}</a>,\n * privacy: (children) => <a href=\"/privacy\">{children}</a>,\n * }}\n * />\n */\nexport function Trans(props: TransProps): VNode | string {\n const translated = props.t(props.i18nKey, props.values)\n\n if (!props.components) return translated\n\n const parts = parseRichText(translated)\n\n // If the result is a single plain string, return it directly\n if (parts.length === 1 && typeof parts[0] === 'string') return parts[0]\n\n const children = parts.map((part) => {\n if (typeof part === 'string') return part\n const component = props.components![part.tag]\n // Unmatched tags: render children as plain text (no raw HTML markup)\n if (!component) return part.children\n return component(part.children)\n })\n\n return h(Fragment, null, ...children)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/context.ts","../src/interpolation.ts","../src/pluralization.ts","../src/create-i18n.ts","../../../node_modules/.bun/@pyreon+core@0.6.0/node_modules/@pyreon/core/lib/jsx-runtime.js","../src/trans.tsx"],"sourcesContent":["import type { Props, VNode, VNodeChild } from '@pyreon/core'\nimport { createContext, provide, useContext } from '@pyreon/core'\nimport type { I18nInstance } from './types'\n\nexport const I18nContext = createContext<I18nInstance | null>(null)\n\nexport interface I18nProviderProps extends Props {\n instance: I18nInstance\n children?: VNodeChild\n}\n\n/**\n * Provide an i18n instance to the component tree.\n *\n * @example\n * const i18n = createI18n({ locale: 'en', messages: { en: { hello: 'Hello' } } })\n *\n * // In JSX:\n * <I18nProvider instance={i18n}>\n * <App />\n * </I18nProvider>\n */\nexport function I18nProvider(props: I18nProviderProps): VNode {\n provide(I18nContext, props.instance)\n\n const ch = props.children\n return (typeof ch === 'function' ? (ch as () => VNodeChild)() : ch) as VNode\n}\n\n/**\n * Access the i18n instance from the nearest I18nProvider.\n * Must be called within a component tree wrapped by I18nProvider.\n *\n * @example\n * function Greeting() {\n * const { t, locale } = useI18n()\n * return <h1>{t('greeting', { name: 'World' })}</h1>\n * }\n */\nexport function useI18n(): I18nInstance {\n const instance = useContext(I18nContext)\n if (!instance) {\n throw new Error(\n '[@pyreon/i18n] useI18n() must be used within an <I18nProvider>.',\n )\n }\n return instance\n}\n","import type { InterpolationValues } from './types'\n\nconst INTERPOLATION_RE = /\\{\\{(\\s*\\w+\\s*)\\}\\}/g\n\n/**\n * Replace `{{key}}` placeholders in a string with values from the given record.\n * Supports optional whitespace inside braces: `{{ name }}` works too.\n * Unmatched placeholders are left as-is.\n */\nexport function interpolate(\n template: string,\n values?: InterpolationValues,\n): string {\n if (!values || !template.includes('{{')) return template\n return template.replace(INTERPOLATION_RE, (_, key: string) => {\n const trimmed = key.trim()\n const value = values[trimmed]\n if (value === undefined) return `{{${trimmed}}}`\n // Safely coerce — guard against malicious toString/valueOf\n try {\n return typeof value === 'object' && value !== null\n ? JSON.stringify(value)\n : `${value}`\n } catch {\n return `{{${trimmed}}}`\n }\n })\n}\n","import type { PluralRules } from './types'\n\n/**\n * Resolve the plural category for a given count and locale.\n *\n * Uses custom rules if provided, otherwise falls back to `Intl.PluralRules`.\n * Returns CLDR plural categories: \"zero\", \"one\", \"two\", \"few\", \"many\", \"other\".\n */\nexport function resolvePluralCategory(\n locale: string,\n count: number,\n customRules?: PluralRules,\n): string {\n // Custom rules take priority\n if (customRules?.[locale]) {\n return customRules[locale](count)\n }\n\n // Use Intl.PluralRules if available\n if (typeof Intl !== 'undefined' && Intl.PluralRules) {\n try {\n const pr = new Intl.PluralRules(locale)\n return pr.select(count)\n } catch {\n // Invalid locale — fall through\n }\n }\n\n // Basic fallback\n return count === 1 ? 'one' : 'other'\n}\n","import { computed, signal } from '@pyreon/reactivity'\nimport { interpolate } from './interpolation'\nimport { resolvePluralCategory } from './pluralization'\nimport type {\n I18nInstance,\n I18nOptions,\n InterpolationValues,\n TranslationDictionary,\n} from './types'\n\n/**\n * Resolve a dot-separated key path in a nested dictionary.\n * E.g. \"user.greeting\" → dictionary.user.greeting\n */\nfunction resolveKey(\n dict: TranslationDictionary,\n keyPath: string,\n): string | undefined {\n const parts = keyPath.split('.')\n let current: TranslationDictionary | string = dict\n\n for (const part of parts) {\n if (current == null || typeof current === 'string') return undefined\n current = current[part] as TranslationDictionary | string\n }\n\n return typeof current === 'string' ? current : undefined\n}\n\n/**\n * Deep-merge source into target (mutates target).\n */\nfunction deepMerge(\n target: TranslationDictionary,\n source: TranslationDictionary,\n): void {\n for (const key of Object.keys(source)) {\n if (key === '__proto__' || key === 'constructor' || key === 'prototype')\n continue\n const sourceVal = source[key]\n const targetVal = target[key]\n if (\n typeof sourceVal === 'object' &&\n sourceVal !== null &&\n typeof targetVal === 'object' &&\n targetVal !== null\n ) {\n deepMerge(\n targetVal as TranslationDictionary,\n sourceVal as TranslationDictionary,\n )\n } else {\n target[key] = sourceVal!\n }\n }\n}\n\n/**\n * Create a reactive i18n instance.\n *\n * @example\n * const i18n = createI18n({\n * locale: 'en',\n * fallbackLocale: 'en',\n * messages: {\n * en: { greeting: 'Hello {{name}}!' },\n * de: { greeting: 'Hallo {{name}}!' },\n * },\n * })\n *\n * // Reactive translation — re-evaluates on locale change\n * i18n.t('greeting', { name: 'Alice' }) // \"Hello Alice!\"\n * i18n.locale.set('de')\n * i18n.t('greeting', { name: 'Alice' }) // \"Hallo Alice!\"\n *\n * @example\n * // Async namespace loading\n * const i18n = createI18n({\n * locale: 'en',\n * loader: async (locale, namespace) => {\n * const mod = await import(`./locales/${locale}/${namespace}.json`)\n * return mod.default\n * },\n * })\n * await i18n.loadNamespace('auth')\n * i18n.t('auth:errors.invalid') // looks up \"errors.invalid\" in \"auth\" namespace\n */\nexport function createI18n(options: I18nOptions): I18nInstance {\n const {\n fallbackLocale,\n loader,\n defaultNamespace = 'common',\n pluralRules,\n onMissingKey,\n } = options\n\n // ── Reactive state ──────────────────────────────────────────────────\n\n const locale = signal(options.locale)\n\n // Internal store: locale → namespace → dictionary\n // We use a version counter to trigger reactive updates when messages change,\n // since the store is mutated in place (Object.is would skip same-reference sets).\n const store = new Map<string, Map<string, TranslationDictionary>>()\n const storeVersion = signal(0)\n\n // Loading state\n const pendingLoads = signal(0)\n const loadedNsVersion = signal(0)\n\n // In-flight load promises — deduplicates concurrent loads for the same locale:namespace\n const pendingPromises = new Map<string, Promise<void>>()\n\n const isLoading = computed(() => pendingLoads() > 0)\n const loadedNamespaces = computed(() => {\n loadedNsVersion()\n const currentLocale = locale()\n const nsMap = store.get(currentLocale)\n return new Set(nsMap ? nsMap.keys() : [])\n })\n const availableLocales = computed(() => {\n storeVersion() // subscribe to store changes\n return [...store.keys()]\n })\n\n // ── Initialize static messages ──────────────────────────────────────\n\n if (options.messages) {\n for (const [loc, dict] of Object.entries(options.messages)) {\n const nsMap = new Map<string, TranslationDictionary>()\n nsMap.set(defaultNamespace, dict)\n store.set(loc, nsMap)\n }\n }\n\n // ── Internal helpers ────────────────────────────────────────────────\n\n function getNamespaceMap(loc: string): Map<string, TranslationDictionary> {\n let nsMap = store.get(loc)\n if (!nsMap) {\n nsMap = new Map()\n store.set(loc, nsMap)\n }\n return nsMap\n }\n\n function lookupKey(\n loc: string,\n namespace: string,\n keyPath: string,\n ): string | undefined {\n const nsMap = store.get(loc)\n if (!nsMap) return undefined\n const dict = nsMap.get(namespace)\n if (!dict) return undefined\n return resolveKey(dict, keyPath)\n }\n\n function resolveTranslation(\n key: string,\n values?: InterpolationValues,\n ): string {\n // Subscribe to reactive dependencies\n const currentLocale = locale()\n storeVersion()\n\n // Parse key: \"namespace:key.path\" or just \"key.path\"\n let namespace = defaultNamespace\n let keyPath = key\n\n const colonIndex = key.indexOf(':')\n if (colonIndex > 0) {\n namespace = key.slice(0, colonIndex)\n keyPath = key.slice(colonIndex + 1)\n }\n\n // Handle pluralization: if values contain `count`, try plural suffixes\n if (values && 'count' in values) {\n const count = Number(values.count)\n const category = resolvePluralCategory(currentLocale, count, pluralRules)\n\n // Try exact form first (e.g. \"items_one\"), then fall back to base key\n const pluralKey = `${keyPath}_${category}`\n const pluralResult =\n lookupKey(currentLocale, namespace, pluralKey) ??\n (fallbackLocale\n ? lookupKey(fallbackLocale, namespace, pluralKey)\n : undefined)\n\n if (pluralResult) {\n return interpolate(pluralResult, values)\n }\n }\n\n // Standard lookup: current locale → fallback locale\n const result =\n lookupKey(currentLocale, namespace, keyPath) ??\n (fallbackLocale\n ? lookupKey(fallbackLocale, namespace, keyPath)\n : undefined)\n\n if (result !== undefined) {\n return interpolate(result, values)\n }\n\n // Missing key handler\n if (onMissingKey) {\n const custom = onMissingKey(currentLocale, key, namespace)\n if (custom !== undefined) return custom!\n }\n\n // Return the key itself as a visual fallback\n return key\n }\n\n // ── Public API ──────────────────────────────────────────────────────\n\n const t = (key: string, values?: InterpolationValues): string => {\n return resolveTranslation(key, values)\n }\n\n const loadNamespace = async (\n namespace: string,\n loc?: string,\n ): Promise<void> => {\n if (!loader) return\n\n const targetLocale = loc ?? locale.peek()\n const cacheKey = `${targetLocale}:${namespace}`\n const nsMap = getNamespaceMap(targetLocale)\n\n // Skip if already loaded\n if (nsMap.has(namespace)) return\n\n // Deduplicate concurrent loads for the same locale:namespace\n const existing = pendingPromises.get(cacheKey)\n if (existing) return existing\n\n pendingLoads.update((n) => n + 1)\n\n const promise = loader(targetLocale, namespace)\n .then((dict) => {\n if (dict) {\n nsMap.set(namespace, dict)\n storeVersion.update((n) => n + 1)\n loadedNsVersion.update((n) => n + 1)\n }\n })\n .finally(() => {\n pendingPromises.delete(cacheKey)\n pendingLoads.update((n) => n - 1)\n })\n\n pendingPromises.set(cacheKey, promise)\n return promise\n }\n\n const exists = (key: string): boolean => {\n const currentLocale = locale.peek()\n\n let namespace = defaultNamespace\n let keyPath = key\n const colonIndex = key.indexOf(':')\n if (colonIndex > 0) {\n namespace = key.slice(0, colonIndex)\n keyPath = key.slice(colonIndex + 1)\n }\n\n return (\n lookupKey(currentLocale, namespace, keyPath) !== undefined ||\n (fallbackLocale\n ? lookupKey(fallbackLocale, namespace, keyPath) !== undefined\n : false)\n )\n }\n\n const addMessages = (\n loc: string,\n messages: TranslationDictionary,\n namespace?: string,\n ): void => {\n const ns = namespace ?? defaultNamespace\n const nsMap = getNamespaceMap(loc)\n const existing = nsMap.get(ns)\n\n if (existing) {\n deepMerge(existing, messages)\n } else {\n // Deep-clone to prevent external mutation from corrupting the store\n const cloned: TranslationDictionary = {}\n deepMerge(cloned, messages)\n nsMap.set(ns, cloned)\n }\n\n storeVersion.update((n) => n + 1)\n loadedNsVersion.update((n) => n + 1)\n }\n\n return {\n t,\n locale,\n loadNamespace,\n isLoading,\n loadedNamespaces,\n exists,\n addMessages,\n availableLocales,\n }\n}\n","//#region src/h.ts\n/** Marker for fragment nodes — renders children without a wrapper element */\nconst Fragment = Symbol(\"Pyreon.Fragment\");\n/**\n* Hyperscript function — the compiled output of JSX.\n* `<div class=\"x\">hello</div>` → `h(\"div\", { class: \"x\" }, \"hello\")`\n*\n* Generic on P so TypeScript validates props match the component's signature\n* at the call site, then stores the result in the loosely-typed VNode.\n*/\n/** Shared empty props sentinel — identity-checked in mountElement to skip applyProps. */\nconst EMPTY_PROPS = {};\nfunction h(type, props, ...children) {\n\treturn {\n\t\ttype,\n\t\tprops: props ?? EMPTY_PROPS,\n\t\tchildren: normalizeChildren(children),\n\t\tkey: props?.key ?? null\n\t};\n}\nfunction normalizeChildren(children) {\n\tfor (let i = 0; i < children.length; i++) if (Array.isArray(children[i])) return flattenChildren(children);\n\treturn children;\n}\nfunction flattenChildren(children) {\n\tconst result = [];\n\tfor (const child of children) if (Array.isArray(child)) result.push(...flattenChildren(child));\n\telse result.push(child);\n\treturn result;\n}\n\n//#endregion\n//#region src/jsx-runtime.ts\n/**\n* JSX automatic runtime.\n*\n* When tsconfig has `\"jsxImportSource\": \"@pyreon/core\"`, the TS/bundler compiler\n* rewrites JSX to imports from this file automatically:\n* <div class=\"x\" /> → jsx(\"div\", { class: \"x\" })\n*/\nfunction jsx(type, props, key) {\n\tconst { children, ...rest } = props;\n\tconst propsWithKey = key != null ? {\n\t\t...rest,\n\t\tkey\n\t} : rest;\n\tif (typeof type === \"function\") return h(type, children !== void 0 ? {\n\t\t...propsWithKey,\n\t\tchildren\n\t} : propsWithKey);\n\treturn h(type, propsWithKey, ...children === void 0 ? [] : Array.isArray(children) ? children : [children]);\n}\nconst jsxs = jsx;\n\n//#endregion\nexport { Fragment, jsx, jsxs };\n//# sourceMappingURL=jsx-runtime.js.map","import type { Props, VNode } from '@pyreon/core'\nimport type { InterpolationValues } from './types'\n\nconst TAG_RE = /<(\\w+)>([^<]*)<\\/\\1>/g\n\ninterface RichPart {\n tag: string\n children: string\n}\n\n/**\n * Parse a translated string into an array of plain text and rich tag segments.\n *\n * @example\n * parseRichText(\"Hello <bold>world</bold>, click <link>here</link>\")\n * // → [\"Hello \", { tag: \"bold\", children: \"world\" }, \", click \", { tag: \"link\", children: \"here\" }]\n */\nexport function parseRichText(text: string): (string | RichPart)[] {\n const parts: (string | RichPart)[] = []\n let lastIndex = 0\n\n for (const match of text.matchAll(TAG_RE)) {\n const before = text.slice(lastIndex, match.index)\n if (before) parts.push(before)\n parts.push({ tag: match[1]!, children: match[2]! })\n lastIndex = match.index! + match[0].length\n }\n\n const after = text.slice(lastIndex)\n if (after) parts.push(after)\n\n return parts\n}\n\nexport interface TransProps extends Props {\n /** Translation key (supports namespace:key syntax). */\n i18nKey: string\n /** Interpolation values for {{placeholder}} syntax. */\n values?: InterpolationValues\n /**\n * Component map for rich interpolation.\n * Keys match tag names in the translation string.\n * Values are component functions: `(children: any) => VNode`\n *\n * @example\n * // Translation: \"Read the <terms>terms</terms> and <privacy>policy</privacy>\"\n * components={{\n * terms: (children) => <a href=\"/terms\">{children}</a>,\n * privacy: (children) => <a href=\"/privacy\">{children}</a>,\n * }}\n */\n components?: Record<string, (children: any) => any>\n /**\n * The i18n instance's `t` function.\n * Can be obtained from `useI18n()` or passed directly.\n */\n t: (key: string, values?: InterpolationValues) => string\n}\n\n/**\n * Rich JSX interpolation component for translations.\n *\n * Allows embedding JSX components within translated strings using XML-like tags.\n * The `t` function resolves the translation and interpolates `{{values}}` first,\n * then `<tag>content</tag>` patterns are mapped to the provided components.\n *\n * @example\n * // Translation: \"You have <bold>{{count}}</bold> unread messages\"\n * const { t } = useI18n()\n * <Trans\n * t={t}\n * i18nKey=\"messages.unread\"\n * values={{ count: 5 }}\n * components={{\n * bold: (children) => <strong>{children}</strong>,\n * }}\n * />\n * // Renders: You have <strong>5</strong> unread messages\n *\n * @example\n * // Translation: \"Read our <terms>terms of service</terms> and <privacy>privacy policy</privacy>\"\n * <Trans\n * t={t}\n * i18nKey=\"legal\"\n * components={{\n * terms: (children) => <a href=\"/terms\">{children}</a>,\n * privacy: (children) => <a href=\"/privacy\">{children}</a>,\n * }}\n * />\n */\nexport function Trans(props: TransProps): VNode | string {\n const translated = props.t(props.i18nKey, props.values)\n\n if (!props.components) return translated\n\n const parts = parseRichText(translated)\n\n // If the result is a single plain string, return it directly\n if (parts.length === 1 && typeof parts[0] === 'string') return parts[0]\n\n const children = parts.map((part) => {\n if (typeof part === 'string') return part\n const component = props.components![part.tag]\n // Unmatched tags: render children as plain text (no raw HTML markup)\n if (!component) return part.children\n return component(part.children)\n })\n\n return <>{children}</>\n}\n"],"x_google_ignoreList":[4],"mappings":"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"}
@@ -1,6 +1,41 @@
1
+ import { createContext, provide, useContext } from "@pyreon/core";
1
2
  import { computed, signal } from "@pyreon/reactivity";
2
- import { Fragment, createContext, h, onUnmount, popContext, pushContext, useContext } from "@pyreon/core";
3
3
 
4
+ //#region src/context.ts
5
+
6
+ /**
7
+ * Provide an i18n instance to the component tree.
8
+ *
9
+ * @example
10
+ * const i18n = createI18n({ locale: 'en', messages: { en: { hello: 'Hello' } } })
11
+ *
12
+ * // In JSX:
13
+ * <I18nProvider instance={i18n}>
14
+ * <App />
15
+ * </I18nProvider>
16
+ */
17
+ function I18nProvider(props) {
18
+ provide(I18nContext, props.instance);
19
+ const ch = props.children;
20
+ return typeof ch === "function" ? ch() : ch;
21
+ }
22
+ /**
23
+ * Access the i18n instance from the nearest I18nProvider.
24
+ * Must be called within a component tree wrapped by I18nProvider.
25
+ *
26
+ * @example
27
+ * function Greeting() {
28
+ * const { t, locale } = useI18n()
29
+ * return <h1>{t('greeting', { name: 'World' })}</h1>
30
+ * }
31
+ */
32
+ function useI18n() {
33
+ const instance = useContext(I18nContext);
34
+ if (!instance) throw new Error("[@pyreon/i18n] useI18n() must be used within an <I18nProvider>.");
35
+ return instance;
36
+ }
37
+
38
+ //#endregion
4
39
  //#region src/interpolation.ts
5
40
 
6
41
  /**
@@ -224,43 +259,51 @@ function createI18n(options) {
224
259
  }
225
260
 
226
261
  //#endregion
227
- //#region src/context.ts
262
+ //#region ../../node_modules/.bun/@pyreon+core@0.6.0/node_modules/@pyreon/core/lib/jsx-runtime.js
263
+ /** Marker for fragment nodes — renders children without a wrapper element */
228
264
 
229
- /**
230
- * Provide an i18n instance to the component tree.
231
- *
232
- * @example
233
- * const i18n = createI18n({ locale: 'en', messages: { en: { hello: 'Hello' } } })
234
- *
235
- * // In JSX:
236
- * <I18nProvider instance={i18n}>
237
- * <App />
238
- * </I18nProvider>
239
- */
240
- function I18nProvider(props) {
241
- pushContext(new Map([[I18nContext.id, props.instance]]));
242
- onUnmount(() => popContext());
243
- const ch = props.children;
244
- return typeof ch === "function" ? ch() : ch;
265
+ function h(type, props, ...children) {
266
+ return {
267
+ type,
268
+ props: props ?? EMPTY_PROPS,
269
+ children: normalizeChildren(children),
270
+ key: props?.key ?? null
271
+ };
272
+ }
273
+ function normalizeChildren(children) {
274
+ for (let i = 0; i < children.length; i++) if (Array.isArray(children[i])) return flattenChildren(children);
275
+ return children;
276
+ }
277
+ function flattenChildren(children) {
278
+ const result = [];
279
+ for (const child of children) if (Array.isArray(child)) result.push(...flattenChildren(child));else result.push(child);
280
+ return result;
245
281
  }
246
282
  /**
247
- * Access the i18n instance from the nearest I18nProvider.
248
- * Must be called within a component tree wrapped by I18nProvider.
283
+ * JSX automatic runtime.
249
284
  *
250
- * @example
251
- * function Greeting() {
252
- * const { t, locale } = useI18n()
253
- * return <h1>{t('greeting', { name: 'World' })}</h1>
254
- * }
285
+ * When tsconfig has `"jsxImportSource": "@pyreon/core"`, the TS/bundler compiler
286
+ * rewrites JSX to imports from this file automatically:
287
+ * <div class="x" /> → jsx("div", { class: "x" })
255
288
  */
256
- function useI18n() {
257
- const instance = useContext(I18nContext);
258
- if (!instance) throw new Error("[@pyreon/i18n] useI18n() must be used within an <I18nProvider>.");
259
- return instance;
289
+ function jsx(type, props, key) {
290
+ const {
291
+ children,
292
+ ...rest
293
+ } = props;
294
+ const propsWithKey = key != null ? {
295
+ ...rest,
296
+ key
297
+ } : rest;
298
+ if (typeof type === "function") return h(type, children !== void 0 ? {
299
+ ...propsWithKey,
300
+ children
301
+ } : propsWithKey);
302
+ return h(type, propsWithKey, ...(children === void 0 ? [] : Array.isArray(children) ? children : [children]));
260
303
  }
261
304
 
262
305
  //#endregion
263
- //#region src/trans.ts
306
+ //#region src/trans.tsx
264
307
 
265
308
  /**
266
309
  * Parse a translated string into an array of plain text and rich tag segments.
@@ -321,12 +364,14 @@ function Trans(props) {
321
364
  if (!props.components) return translated;
322
365
  const parts = parseRichText(translated);
323
366
  if (parts.length === 1 && typeof parts[0] === "string") return parts[0];
324
- return h(Fragment, null, ...parts.map(part => {
325
- if (typeof part === "string") return part;
326
- const component = props.components[part.tag];
327
- if (!component) return part.children;
328
- return component(part.children);
329
- }));
367
+ return /* @__PURE__ */jsx(Fragment, {
368
+ children: parts.map(part => {
369
+ if (typeof part === "string") return part;
370
+ const component = props.components[part.tag];
371
+ if (!component) return part.children;
372
+ return component(part.children);
373
+ })
374
+ });
330
375
  }
331
376
 
332
377
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/interpolation.ts","../../src/pluralization.ts","../../src/create-i18n.ts","../../src/context.ts","../../src/trans.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/context.ts","../../src/interpolation.ts","../../src/pluralization.ts","../../src/create-i18n.ts","../../../../node_modules/.bun/@pyreon+core@0.6.0/node_modules/@pyreon/core/lib/jsx-runtime.js","../../src/trans.tsx"],"x_google_ignoreList":[4],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { Computed, Signal } from "@pyreon/reactivity";
2
1
  import * as _pyreon_core0 from "@pyreon/core";
3
2
  import { Props, VNode, VNodeChild } from "@pyreon/core";
3
+ import { Computed, Signal } from "@pyreon/reactivity";
4
4
 
5
5
  //#region src/types.d.ts
6
6
  /** A nested dictionary of translation strings. */
@@ -90,6 +90,36 @@ interface I18nInstance {
90
90
  availableLocales: Computed<string[]>;
91
91
  }
92
92
  //#endregion
93
+ //#region src/context.d.ts
94
+ declare const I18nContext: _pyreon_core0.Context<I18nInstance | null>;
95
+ interface I18nProviderProps extends Props {
96
+ instance: I18nInstance;
97
+ children?: VNodeChild;
98
+ }
99
+ /**
100
+ * Provide an i18n instance to the component tree.
101
+ *
102
+ * @example
103
+ * const i18n = createI18n({ locale: 'en', messages: { en: { hello: 'Hello' } } })
104
+ *
105
+ * // In JSX:
106
+ * <I18nProvider instance={i18n}>
107
+ * <App />
108
+ * </I18nProvider>
109
+ */
110
+ declare function I18nProvider(props: I18nProviderProps): VNode;
111
+ /**
112
+ * Access the i18n instance from the nearest I18nProvider.
113
+ * Must be called within a component tree wrapped by I18nProvider.
114
+ *
115
+ * @example
116
+ * function Greeting() {
117
+ * const { t, locale } = useI18n()
118
+ * return <h1>{t('greeting', { name: 'World' })}</h1>
119
+ * }
120
+ */
121
+ declare function useI18n(): I18nInstance;
122
+ //#endregion
93
123
  //#region src/create-i18n.d.ts
94
124
  /**
95
125
  * Create a reactive i18n instance.
@@ -140,36 +170,6 @@ declare function interpolate(template: string, values?: InterpolationValues): st
140
170
  */
141
171
  declare function resolvePluralCategory(locale: string, count: number, customRules?: PluralRules): string;
142
172
  //#endregion
143
- //#region src/context.d.ts
144
- declare const I18nContext: _pyreon_core0.Context<I18nInstance | null>;
145
- interface I18nProviderProps extends Props {
146
- instance: I18nInstance;
147
- children?: VNodeChild;
148
- }
149
- /**
150
- * Provide an i18n instance to the component tree.
151
- *
152
- * @example
153
- * const i18n = createI18n({ locale: 'en', messages: { en: { hello: 'Hello' } } })
154
- *
155
- * // In JSX:
156
- * <I18nProvider instance={i18n}>
157
- * <App />
158
- * </I18nProvider>
159
- */
160
- declare function I18nProvider(props: I18nProviderProps): VNode;
161
- /**
162
- * Access the i18n instance from the nearest I18nProvider.
163
- * Must be called within a component tree wrapped by I18nProvider.
164
- *
165
- * @example
166
- * function Greeting() {
167
- * const { t, locale } = useI18n()
168
- * return <h1>{t('greeting', { name: 'World' })}</h1>
169
- * }
170
- */
171
- declare function useI18n(): I18nInstance;
172
- //#endregion
173
173
  //#region src/trans.d.ts
174
174
  interface RichPart {
175
175
  tag: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index2.d.ts","names":[],"sources":["../../src/types.ts","../../src/create-i18n.ts","../../src/interpolation.ts","../../src/pluralization.ts","../../src/context.ts","../../src/trans.ts"],"mappings":";;;;;;KAGY,qBAAA;EAAA,CACT,GAAA,oBAAuB,qBAAA;AAAA;AAD1B;AAAA,KAKY,mBAAA,GAAsB,MAAA,SAAe,qBAAA;;;;AAAjD;KAMY,eAAA,IACV,MAAA,UACA,SAAA,aACG,OAAA,CAAQ,qBAAA;;KAGD,mBAAA,GAAsB,MAAA;;KAGtB,WAAA,GAAc,MAAA,UAAgB,KAAA;;UAGzB,WAAA;EATL;EAWV,MAAA;EAZA;EAcA,cAAA;EAbW;EAeX,QAAA,GAAW,MAAA,SAAe,qBAAA;EAfM;AAGlC;;;EAiBE,MAAA,GAAS,eAAA;EAjB6B;AAGxC;;;EAmBE,gBAAA;EAnBqD;AAGvD;;;EAqBE,WAAA,GAAc,WAAA;EAfH;;;;EAoBX,YAAA,IACE,MAAA,UACA,GAAA,UACA,SAAA;AAAA;;UAKa,YAAA;EA5BJ;;;;;;;;;;EAuCX,CAAA,GAAI,GAAA,UAAa,MAAA,GAAS,mBAAA;EAhBN;EAmBpB,MAAA,EAAQ,MAAA;EAdO;;;;EAoBf,aAAA,GAAgB,SAAA,UAAmB,MAAA,cAAoB,OAAA;EAAA;;;EAKvD,SAAA,EAAW,QAAA;EAkBC;;;EAbZ,gBAAA,EAAkB,QAAA,CAAS,GAAA;EAnB3B;;;EAwBA,MAAA,GAAS,GAAA;EArBT;;;;EA2BA,WAAA,GACE,MAAA,UACA,QAAA,EAAU,qBAAA,EACV,SAAA;EAxBqD;;;EA8BvD,gBAAA,EAAkB,QAAA;AAAA;;;;;;;AA3GpB;;;;;AAKA;;;;;AAMA;;;;;;;;;;AAMA;;;;;AAGA;iBCgEgB,UAAA,CAAW,OAAA,EAAS,WAAA,GAAc,YAAA;;;;;;;ADpFlD;iBEMgB,WAAA,CACd,QAAA,UACA,MAAA,GAAS,mBAAA;;;;;;;AFRX;;iBGKgB,qBAAA,CACd,MAAA,UACA,KAAA,UACA,WAAA,GAAc,WAAA;;;cCDH,WAAA,EAAW,aAAA,CAAA,OAAA,CAAA,YAAA;AAAA,UAEP,iBAAA,SAA0B,KAAA;EACzC,QAAA,EAAU,YAAA;EACV,QAAA,GAAW,UAAA;AAAA;;;;AJNb;;;;;AAMA;;;iBIcgB,YAAA,CAAa,KAAA,EAAO,iBAAA,GAAoB,KAAA;;;;;;;AJRxD;;;;iBI4BgB,OAAA,CAAA,GAAW,YAAA;;;UC1CjB,QAAA;EACR,GAAA;EACA,QAAA;AAAA;;;;;ALAF;;;iBKUgB,aAAA,CAAc,IAAA,qBAAyB,QAAA;AAAA,UAiBtC,UAAA,SAAmB,KAAA;ELrBxB;EKuBV,OAAA;;EAEA,MAAA,GAAS,mBAAA;ELxBT;;;;;;AAKF;;;;;AAGA;EK6BE,UAAA,GAAa,MAAA,UAAgB,QAAA;;;;AL1B/B;EK+BE,CAAA,GAAI,GAAA,UAAa,MAAA,GAAS,mBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;ALG5B;;;;;;;;;iBK+BgB,KAAA,CAAM,KAAA,EAAO,UAAA,GAAa,KAAA"}
1
+ {"version":3,"file":"index2.d.ts","names":[],"sources":["../../src/types.ts","../../src/context.ts","../../src/create-i18n.ts","../../src/interpolation.ts","../../src/pluralization.ts","../../src/trans.tsx"],"mappings":";;;;;;KAGY,qBAAA;EAAA,CACT,GAAA,oBAAuB,qBAAA;AAAA;AAD1B;AAAA,KAKY,mBAAA,GAAsB,MAAA,SAAe,qBAAA;;;;AAAjD;KAMY,eAAA,IACV,MAAA,UACA,SAAA,aACG,OAAA,CAAQ,qBAAA;;KAGD,mBAAA,GAAsB,MAAA;;KAGtB,WAAA,GAAc,MAAA,UAAgB,KAAA;;UAGzB,WAAA;EATL;EAWV,MAAA;EAZA;EAcA,cAAA;EAbW;EAeX,QAAA,GAAW,MAAA,SAAe,qBAAA;EAfM;AAGlC;;;EAiBE,MAAA,GAAS,eAAA;EAjB6B;AAGxC;;;EAmBE,gBAAA;EAnBqD;AAGvD;;;EAqBE,WAAA,GAAc,WAAA;EAfH;;;;EAoBX,YAAA,IACE,MAAA,UACA,GAAA,UACA,SAAA;AAAA;;UAKa,YAAA;EA5BJ;;;;;;;;;;EAuCX,CAAA,GAAI,GAAA,UAAa,MAAA,GAAS,mBAAA;EAhBN;EAmBpB,MAAA,EAAQ,MAAA;EAdO;;;;EAoBf,aAAA,GAAgB,SAAA,UAAmB,MAAA,cAAoB,OAAA;EAAA;;;EAKvD,SAAA,EAAW,QAAA;EAkBC;;;EAbZ,gBAAA,EAAkB,QAAA,CAAS,GAAA;EAnB3B;;;EAwBA,MAAA,GAAS,GAAA;EArBT;;;;EA2BA,WAAA,GACE,MAAA,UACA,QAAA,EAAU,qBAAA,EACV,SAAA;EAxBqD;;;EA8BvD,gBAAA,EAAkB,QAAA;AAAA;;;cC1GP,WAAA,EAAW,aAAA,CAAA,OAAA,CAAA,YAAA;AAAA,UAEP,iBAAA,SAA0B,KAAA;EACzC,QAAA,EAAU,YAAA;EACV,QAAA,GAAW,UAAA;AAAA;;;;ADAb;;;;;AAMA;;;iBCQgB,YAAA,CAAa,KAAA,EAAO,iBAAA,GAAoB,KAAA;;;;;;;ADFxD;;;;iBCmBgB,OAAA,CAAA,GAAW,YAAA;;;;;;;ADpC3B;;;;;AAKA;;;;;AAMA;;;;;;;;;;AAMA;;;;;AAGA;iBEgEgB,UAAA,CAAW,OAAA,EAAS,WAAA,GAAc,YAAA;;;;;;;AFpFlD;iBGMgB,WAAA,CACd,QAAA,UACA,MAAA,GAAS,mBAAA;;;;;;;AHRX;;iBIKgB,qBAAA,CACd,MAAA,UACA,KAAA,UACA,WAAA,GAAc,WAAA;;;UCNN,QAAA;EACR,GAAA;EACA,QAAA;AAAA;;;;;ALCF;;;iBKSgB,aAAA,CAAc,IAAA,qBAAyB,QAAA;AAAA,UAiBtC,UAAA,SAAmB,KAAA;ELpBxB;EKsBV,OAAA;;EAEA,MAAA,GAAS,mBAAA;ELvBT;;;;;;AAKF;;;;;AAGA;EK4BE,UAAA,GAAa,MAAA,UAAgB,QAAA;;;;ALzB/B;EK8BE,CAAA,GAAI,GAAA,UAAa,MAAA,GAAS,mBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;ALI5B;;;;;;;;;iBK8BgB,KAAA,CAAM,KAAA,EAAO,UAAA,GAAa,KAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyreon/i18n",
3
- "version": "0.3.0",
3
+ "version": "0.6.0",
4
4
  "description": "Reactive internationalization for Pyreon with async namespace loading",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -45,7 +45,7 @@
45
45
  "typecheck": "tsc --noEmit"
46
46
  },
47
47
  "peerDependencies": {
48
- "@pyreon/core": ">=0.4.0 <1.0.0",
49
- "@pyreon/reactivity": ">=0.4.0 <1.0.0"
48
+ "@pyreon/core": ">=0.5.0 <1.0.0",
49
+ "@pyreon/reactivity": ">=0.5.0 <1.0.0"
50
50
  }
51
51
  }
package/src/context.ts CHANGED
@@ -1,11 +1,5 @@
1
- import {
2
- createContext,
3
- pushContext,
4
- popContext,
5
- onUnmount,
6
- useContext,
7
- } from '@pyreon/core'
8
- import type { VNodeChild, VNode, Props } from '@pyreon/core'
1
+ import type { Props, VNode, VNodeChild } from '@pyreon/core'
2
+ import { createContext, provide, useContext } from '@pyreon/core'
9
3
  import type { I18nInstance } from './types'
10
4
 
11
5
  export const I18nContext = createContext<I18nInstance | null>(null)
@@ -27,10 +21,7 @@ export interface I18nProviderProps extends Props {
27
21
  * </I18nProvider>
28
22
  */
29
23
  export function I18nProvider(props: I18nProviderProps): VNode {
30
- const frame = new Map([[I18nContext.id, props.instance]])
31
- pushContext(frame)
32
-
33
- onUnmount(() => popContext())
24
+ provide(I18nContext, props.instance)
34
25
 
35
26
  const ch = props.children
36
27
  return (typeof ch === 'function' ? (ch as () => VNodeChild)() : ch) as VNode
@@ -1,12 +1,12 @@
1
- import { signal, computed } from '@pyreon/reactivity'
1
+ import { computed, signal } from '@pyreon/reactivity'
2
+ import { interpolate } from './interpolation'
3
+ import { resolvePluralCategory } from './pluralization'
2
4
  import type {
3
- I18nOptions,
4
5
  I18nInstance,
5
- TranslationDictionary,
6
+ I18nOptions,
6
7
  InterpolationValues,
8
+ TranslationDictionary,
7
9
  } from './types'
8
- import { interpolate } from './interpolation'
9
- import { resolvePluralCategory } from './pluralization'
10
10
 
11
11
  /**
12
12
  * Resolve a dot-separated key path in a nested dictionary.
package/src/index.ts CHANGED
@@ -1,18 +1,16 @@
1
+ export type { I18nProviderProps } from './context'
2
+ export { I18nContext, I18nProvider, useI18n } from './context'
1
3
  export { createI18n } from './create-i18n'
2
4
  export { interpolate } from './interpolation'
3
5
  export { resolvePluralCategory } from './pluralization'
4
- export { I18nProvider, useI18n, I18nContext } from './context'
5
- export { Trans, parseRichText } from './trans'
6
-
6
+ export type { TransProps } from './trans'
7
+ export { parseRichText, Trans } from './trans'
7
8
  export type {
8
9
  I18nInstance,
9
10
  I18nOptions,
10
- TranslationDictionary,
11
- TranslationMessages,
12
- NamespaceLoader,
13
11
  InterpolationValues,
12
+ NamespaceLoader,
14
13
  PluralRules,
14
+ TranslationDictionary,
15
+ TranslationMessages,
15
16
  } from './types'
16
-
17
- export type { I18nProviderProps } from './context'
18
- export type { TransProps } from './trans'
@@ -1,12 +1,12 @@
1
1
  import { createI18n } from '../create-i18n'
2
2
  import {
3
- registerI18n,
4
- unregisterI18n,
3
+ _resetDevtools,
5
4
  getActiveI18nInstances,
6
5
  getI18nInstance,
7
6
  getI18nSnapshot,
8
7
  onI18nChange,
9
- _resetDevtools,
8
+ registerI18n,
9
+ unregisterI18n,
10
10
  } from '../devtools'
11
11
 
12
12
  afterEach(() => _resetDevtools())
@@ -1,8 +1,7 @@
1
- import { h } from '@pyreon/core'
2
- import { mount } from '@pyreon/runtime-dom'
3
1
  import { effect } from '@pyreon/reactivity'
4
- import { createI18n } from '../create-i18n'
2
+ import { mount } from '@pyreon/runtime-dom'
5
3
  import { I18nProvider, useI18n } from '../context'
4
+ import { createI18n } from '../create-i18n'
6
5
  import { interpolate } from '../interpolation'
7
6
  import { resolvePluralCategory } from '../pluralization'
8
7
  import { parseRichText, Trans } from '../trans'
@@ -593,15 +592,14 @@ describe('I18nProvider / useI18n', () => {
593
592
  let received: ReturnType<typeof useI18n> | undefined
594
593
  const el = document.createElement('div')
595
594
  document.body.appendChild(el)
595
+ const Child = () => {
596
+ received = useI18n()
597
+ return null
598
+ }
596
599
  const unmount = mount(
597
- h(
598
- I18nProvider,
599
- { instance: i18n },
600
- h(() => {
601
- received = useI18n()
602
- return null
603
- }, null),
604
- ),
600
+ <I18nProvider instance={i18n}>
601
+ <Child />
602
+ </I18nProvider>,
605
603
  el,
606
604
  )
607
605
 
@@ -620,13 +618,12 @@ describe('I18nProvider / useI18n', () => {
620
618
  let received: ReturnType<typeof useI18n> | undefined
621
619
  const el = document.createElement('div')
622
620
  document.body.appendChild(el)
621
+ const Child = () => {
622
+ received = useI18n()
623
+ return null
624
+ }
623
625
  const unmount = mount(
624
- h(I18nProvider, { instance: i18n }, () => {
625
- return h(() => {
626
- received = useI18n()
627
- return null
628
- }, null)
629
- }),
626
+ <I18nProvider instance={i18n}>{() => <Child />}</I18nProvider>,
630
627
  el,
631
628
  )
632
629
 
@@ -641,17 +638,15 @@ describe('I18nProvider / useI18n', () => {
641
638
  const el = document.createElement('div')
642
639
  document.body.appendChild(el)
643
640
 
644
- const unmount = mount(
645
- h(() => {
646
- try {
647
- useI18n()
648
- } catch (e) {
649
- error = e as Error
650
- }
651
- return null
652
- }, null),
653
- el,
654
- )
641
+ const Child = () => {
642
+ try {
643
+ useI18n()
644
+ } catch (e) {
645
+ error = e as Error
646
+ }
647
+ return null
648
+ }
649
+ const unmount = mount(<Child />, el)
655
650
 
656
651
  expect(error).toBeDefined()
657
652
  expect(error!.message).toContain(
@@ -670,15 +665,14 @@ describe('I18nProvider / useI18n', () => {
670
665
  let received: ReturnType<typeof useI18n> | undefined
671
666
  const el = document.createElement('div')
672
667
  document.body.appendChild(el)
668
+ const Child = () => {
669
+ received = useI18n()
670
+ return null
671
+ }
673
672
  const unmount = mount(
674
- h(
675
- I18nProvider,
676
- { instance: i18n },
677
- h(() => {
678
- received = useI18n()
679
- return null
680
- }, null),
681
- ),
673
+ <I18nProvider instance={i18n}>
674
+ <Child />
675
+ </I18nProvider>,
682
676
  el,
683
677
  )
684
678
 
@@ -1,5 +1,4 @@
1
- import { h, Fragment } from '@pyreon/core'
2
- import type { VNode, Props } from '@pyreon/core'
1
+ import type { Props, VNode } from '@pyreon/core'
3
2
  import type { InterpolationValues } from './types'
4
3
 
5
4
  const TAG_RE = /<(\w+)>([^<]*)<\/\1>/g
@@ -107,5 +106,5 @@ export function Trans(props: TransProps): VNode | string {
107
106
  return component(part.children)
108
107
  })
109
108
 
110
- return h(Fragment, null, ...children)
109
+ return <>{children}</>
111
110
  }
package/src/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Signal, Computed } from '@pyreon/reactivity'
1
+ import type { Computed, Signal } from '@pyreon/reactivity'
2
2
 
3
3
  /** A nested dictionary of translation strings. */
4
4
  export type TranslationDictionary = {