🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@i18n-micro/core

Package Overview
Dependencies
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@i18n-micro/core - npm Package Compare versions

Comparing version
1.3.4
to
1.3.8
+20
dist/reactive-store.d.ts
/**
* Shared reactive state for framework i18n adapters (subscribe / getSnapshot / notify).
*/
export interface ReactiveI18nStoreOptions {
locale: string;
fallbackLocale?: string;
route?: string;
}
export interface ReactiveI18nStore {
subscribe(listener: () => void): () => void;
getSnapshot(): string;
getLocale(): string;
setLocale(locale: string): void;
getFallbackLocale(): string;
setFallbackLocale(locale: string): void;
getRoute(): string;
setRoute(routeName: string): void;
notify(): void;
}
export declare function createReactiveI18nStore(options: ReactiveI18nStoreOptions): ReactiveI18nStore;
+62
-4
import { CleanTranslation, MissingHandler, Params, PluralFunc, TranslationKey, Translations } from '@i18n-micro/types';
import { FormatService } from './format-service';
import { FormatService, DateTimeFormatsConfig, NumberFormatsConfig } from './format-service';
import { TranslationStorage, useTranslationHelper } from './translation';

@@ -10,2 +10,6 @@ export interface BaseI18nOptions {

getCustomMissingHandler?: () => MissingHandler | null;
/** Named number formats per locale (Vue I18n-compatible). */
numberFormats?: NumberFormatsConfig;
/** Named datetime formats per locale (Vue I18n-compatible `datetimeFormats`). */
datetimeFormats?: DateTimeFormatsConfig;
}

@@ -25,2 +29,7 @@ /**

getCustomMissingHandler?: () => MissingHandler | null;
/**
* Set on the server when the SSR payload should carry only the keys the render
* actually used. `null` on the client and in `chunk` mode, so the lookup path
* stays a plain property read.
*/
constructor(options?: BaseI18nOptions);

@@ -56,2 +65,22 @@ /**

/**
* Two live layers as one tree, via {@link mergeTranslationLayers}.
*
* Used when the hot path keeps two objects instead of merging them — the fallback locale,
* or the Nuxt page-transition layer — so the dump answers what `t()` answers.
*/
protected resolveTranslationTree(lower: Record<string, unknown>, upper: Record<string, unknown>): Translations;
/**
* Dump of what `t()` can resolve right now for the active locale and route.
*
* Live tree, not a clone — read-only; mutate via {@link setTranslation} / merge helpers.
* When a second layer is live (fallback locale, Nuxt transition hot-reload), walks both
* through {@link resolveTranslationTree} so the dump matches `t()`.
*/
resolveTranslations(routeContext?: unknown): Translations;
/**
* Called after {@link setTranslation} changes the dictionary. Adapters override it to
* bump whatever their reactivity is built on.
*/
protected onTranslationsChanged(): void;
/**
* Context passed to missing-key handlers.

@@ -64,2 +93,7 @@ */

/**
* Dev-only client `console.warn`, gated by `missingWarn`.
* Shared by missing translations and missing named formats.
*/
protected warnDev(message: string): void;
/**
* Warn or invoke handler when translation is missing.

@@ -69,2 +103,7 @@ */

/**
* Warn when a named number/datetime format key is missing.
* Falls back to default Intl options (visible in dev via {@link warnDev}).
*/
protected warnMissingFormat(kind: 'number' | 'datetime', key: string, locale: string): void;
/**
* Get translation for a key

@@ -82,9 +121,15 @@ */

/**
* Format number
* Format number.
* Supports Vue I18n-style named formats: `tn(1000, 'currency')`.
*/
tn(value: number, options?: Intl.NumberFormatOptions): string;
tn(value: number, key: string, overrides?: Intl.NumberFormatOptions): string;
tn(value: number, key: string, locale: string, overrides?: Intl.NumberFormatOptions): string;
/**
* Format date
* Format date.
* Supports Vue I18n-style named formats: `td(date, 'short')`.
*/
td(value: Date | number | string, options?: Intl.DateTimeFormatOptions): string;
td(value: Date | number | string, key: string, overrides?: Intl.DateTimeFormatOptions): string;
td(value: Date | number | string, key: string, locale: string, overrides?: Intl.DateTimeFormatOptions): string;
/**

@@ -99,5 +144,18 @@ * Format relative time

/**
* Clear cache
* Replace the value at `key` — a subtree, a string, a number, anything.
*
* `set` and not `merge`: `setTranslation('aaa', { fff: 'ggg' })` leaves `aaa` holding only
* `fff`, and `setTranslation('aaa', 'fff')` leaves a string where the subtree was. Use
* `mergeTranslations` when the existing siblings should survive.
*
* Writes to the active locale and route, so the change is visible to `t()` immediately and
* lives exactly as long as the chunk it belongs to.
*/
setTranslation(key: TranslationKey, value: unknown): void;
/**
* Clear translation + formatter caches
*/
clearCache(): void;
private resolveNumberFormatArgs;
private resolveDateTimeFormatArgs;
/**

@@ -104,0 +162,0 @@ * Core translation loading logic (without reactivity)

@@ -0,2 +1,32 @@

export type NumberFormatsConfig = Record<string, Record<string, Intl.NumberFormatOptions>>;
export type DateTimeFormatsConfig = Record<string, Record<string, Intl.DateTimeFormatOptions>>;
export interface FormatServiceOptions {
numberFormats?: NumberFormatsConfig;
/** Vue I18n-compatible name (`datetimeFormats`). */
datetimeFormats?: DateTimeFormatsConfig;
}
/**
* Shared Intl formatters with:
* - Map cache keyed by locale + options (avoids `new Intl.*Format` on every call)
* - Named formats (`numberFormats` / `datetimeFormats`) for Vue I18n-compatible `$tn(n, 'currency')`
*/
export declare class FormatService {
private numberFormats;
private datetimeFormats;
private numberCache;
private dateCache;
private relativeCache;
constructor(options?: FormatServiceOptions);
setNumberFormats(formats: NumberFormatsConfig): void;
setDateTimeFormats(formats: DateTimeFormatsConfig): void;
getNumberFormats(): NumberFormatsConfig;
getDateTimeFormats(): DateTimeFormatsConfig;
clearCache(): void;
/** Resolve a named number format for a locale (exact match, then language subtag). */
resolveNumberFormat(locale: string, key: string): Intl.NumberFormatOptions | undefined;
/** Resolve a named datetime format for a locale (exact match, then language subtag). */
resolveDateTimeFormat(locale: string, key: string): Intl.DateTimeFormatOptions | undefined;
getNumberFormatter(locale: string, options?: Intl.NumberFormatOptions): Intl.NumberFormat;
getDateTimeFormatter(locale: string, options?: Intl.DateTimeFormatOptions): Intl.DateTimeFormat;
getRelativeTimeFormatter(locale: string, options?: Intl.RelativeTimeFormatOptions): Intl.RelativeTimeFormat;
formatNumber(value: number, locale: string, options?: Intl.NumberFormatOptions): string;

@@ -3,0 +33,0 @@ formatDate(value: Date | number | string, locale: string, options?: Intl.DateTimeFormatOptions): string;

+1
-1

@@ -1,1 +0,1 @@

export { defaultPlural, getByPath, hasTranslationValue, interpolate, isNoPrefixStrategy, isPrefixAndDefaultStrategy, isPrefixExceptDefaultStrategy, isPrefixStrategy, mergeTranslationChunk, resolveTranslation, translationCacheKey, withPrefixStrategy, type MergeTranslationChunkOptions, } from './helpers';
export { defaultPlural, getByPath, hasTranslationValue, interpolate, isNoPrefixStrategy, isPrefixAndDefaultStrategy, isPrefixExceptDefaultStrategy, isPrefixStrategy, collectTranslationPaths, mergeTranslationChunk, mergeTranslationLayers, resolveTranslation, setTranslationAtKey, translationCacheKey, withPrefixStrategy, type MergeTranslationChunkOptions, } from './helpers';

@@ -1,1 +0,1 @@

"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=/\{(\w+)\}/g,c="index";function d(t,r){return`${t}:${r||c}`}function f(t,r){if(t==null)return null;const n=a(t,r);return n===void 0?null:n}function g(t,r){return f(t,r)!==null}function y(t,r,n){return Object.keys(t).length===0?r:n?.preserveExisting?Object.assign({},r,t):Object.assign({},t,r)}function x(t,r){return!r||t.indexOf("{")===-1?t:t.replace(s,(n,e)=>{const i=r[e];return i!==void 0?String(i):`{${e}}`})}function a(t,r){if(t==null||typeof r!="string"||r.length===0)return;if(Object.prototype.hasOwnProperty.call(t,r))return t[r];if(!r.includes("."))return;const n=r.split(".");let e=t;for(const i of n){if(e==null||typeof e!="object")return;const u=e;if(!Object.prototype.hasOwnProperty.call(u,i))return;e=u[i]}return e}function p(t){return t==="prefix"||t==="prefix_and_default"}function P(t){return t==="no_prefix"}function v(t){return t==="prefix"}function S(t){return t==="prefix_except_default"}function h(t){return t==="prefix_and_default"}const _=(t,r,n,e,i)=>{const u=i(t,n);if(!u)return null;const l=u.toString().split("|");if(l.length===0)return null;const o=r<l.length?l[r]:l[l.length-1];return o?o.trim().replace("{count}",r.toString()):null};exports.defaultPlural=_;exports.getByPath=a;exports.hasTranslationValue=g;exports.interpolate=x;exports.isNoPrefixStrategy=P;exports.isPrefixAndDefaultStrategy=h;exports.isPrefixExceptDefaultStrategy=S;exports.isPrefixStrategy=v;exports.mergeTranslationChunk=y;exports.resolveTranslation=f;exports.translationCacheKey=d;exports.withPrefixStrategy=p;
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=/\{(\w+)\}/g,v="index";function x(t,n){return`${t}:${n||v}`}function u(t,n){if(t==null)return null;const o=_(t,n);return o===void 0?null:o}function P(t,n){return u(t,n)!==null}function T(t,n,o){return Object.keys(t).length===0?n:o?.preserveExisting?a(n,t):a(t,n)}const c=t=>t!==null&&typeof t=="object"&&!Array.isArray(t);function a(t,n){const o={...t};for(const e of Object.keys(n)){if(e==="__proto__")continue;const r=n[e],i=o[e];o[e]=c(r)&&c(i)?a(i,r):r}return o}function O(t,n){return!n||t.indexOf("{")===-1?t:t.replace(h,(o,e)=>{const r=n[e];return r!==void 0?String(r):`{${e}}`})}function _(t,n){if(t==null||typeof n!="string"||n.length===0)return;if(Object.prototype.hasOwnProperty.call(t,n))return t[n];if(!n.includes("."))return;const o=n.split(".");let e=t;for(const r of o){if(e==null||typeof e!="object")return;const i=e;if(!Object.prototype.hasOwnProperty.call(i,r))return;e=i[r]}return e}function S(t,n,o){if(typeof n!="string"||n.length===0)return t;if(Object.prototype.hasOwnProperty.call(t,n)||!n.includes("."))return n==="__proto__"?t:{...t,[n]:o};const e=n.split(".");if(e.some(s=>s==="__proto__"))return t;const r={...t};let i=r;for(const s of e.slice(0,-1)){const l=i[s],f=c(l)?{...l}:{};i[s]=f,i=f}return i[e[e.length-1]]=o,r}function b(t,n){const o=y(t,n),e={};return d(t,n,"",e),Object.keys(e).length===0?o:{...o,...e}}function y(t,n){const o={...t};for(const e of Object.keys(n)){if(e==="__proto__")continue;const r=n[e];if(r==null)continue;const i=o[e];o[e]=c(r)&&c(i)?y(i,r):r}return o}function d(t,n,o,e){for(const r of Object.keys(t)){if(r==="__proto__")continue;const i=t[r];if(!c(i))continue;const s=o?`${o}.${r}`:r,l=n[r];c(l)?d(i,l,s,e):l!=null&&g(i,s,e)}}function g(t,n,o){for(const e of Object.keys(t)){if(e==="__proto__")continue;const r=t[e],i=`${n}.${e}`;c(r)?g(r,i,o):o[i]=r}}function p(t,n,o=""){for(const e of Object.keys(t)){if(e==="__proto__")continue;const r=o?`${o}.${e}`:e;n.add(r);const i=t[e];c(i)&&p(i,n,r)}}function $(t){return t==="prefix"||t==="prefix_and_default"}function m(t){return t==="no_prefix"}function A(t){return t==="prefix"}function E(t){return t==="prefix_except_default"}function j(t){return t==="prefix_and_default"}const k=(t,n,o,e,r)=>{const i=r(t,o);if(!i)return null;const s=i.toString().split("|");if(s.length===0)return null;const l=n<s.length?s[n]:s[s.length-1];return l?l.trim().replace("{count}",n.toString()):null};exports.collectTranslationPaths=p;exports.defaultPlural=k;exports.getByPath=_;exports.hasTranslationValue=P;exports.interpolate=O;exports.isNoPrefixStrategy=m;exports.isPrefixAndDefaultStrategy=j;exports.isPrefixExceptDefaultStrategy=E;exports.isPrefixStrategy=A;exports.mergeTranslationChunk=T;exports.mergeTranslationLayers=b;exports.resolveTranslation=u;exports.setTranslationAtKey=S;exports.translationCacheKey=x;exports.withPrefixStrategy=$;

@@ -9,5 +9,47 @@ import { Params, PluralFunc, Strategies } from '@i18n-micro/types';

}
/**
* Merge two translation chunks, descending into nested objects.
*
* `Object.assign` is wrong here, and quietly so: chunks are trees, so a shallow merge of
* `{ nav: { about, home } }` with `{ nav: { extra } }` replaces the whole `nav` subtree
* and loses `about` and `home`. Nothing throws — the keys simply resolve to themselves
* later, which is the raw-key render the loader exists to prevent.
*
* Written here rather than reusing `@i18n-micro/utils/deep-merge`: that package carries
* build-time dependencies, and `core` is installed by every consumer at runtime.
*/
export declare function mergeTranslationChunk(existing: Record<string, unknown>, incoming: Record<string, unknown>, options?: MergeTranslationChunkOptions): Record<string, unknown>;
export declare function interpolate(template: string, params: Params): string;
export declare function getByPath(obj: Record<string, unknown> | null | undefined, path: string): unknown;
/**
* A translation tree with `key` set to `value`, whatever either of them is.
*
* Replaces rather than merges: `set('aaa', { x: 1 })` on `{ aaa: { bbb: 'ccc' } }` leaves
* `aaa` holding only `x`, and `set('aaa', 'text')` leaves a string where a subtree was.
* Merging is what `mergeTranslationChunk` is for.
*
* The tree is not mutated — only the nodes along the path are copied, so the call costs the
* depth of the key and not the size of the dictionary, and callers holding the old tree
* (a frozen SSR chunk, a rendered snapshot) keep seeing what they had.
*
* Key resolution mirrors {@link getByPath}: an existing flat key wins over the dotted path,
* so a dictionary written as `{ 'a.b': 'x' }` is updated in place rather than gaining a
* nested `a.b` that `t('a.b')` would never read.
*/
export declare function setTranslationAtKey(tree: Record<string, unknown>, key: string, value: unknown): Record<string, unknown>;
/**
* Two live lookup layers as one tree, shaped the way a single layer already is.
*
* `upper` wins, exactly as a per-key fallthrough does, so the result answers every key the
* two layers together can answer — with one exception that a tree cannot express: where
* `upper` holds a scalar and `lower` holds an object at the same path, `t('a')` reads the
* scalar while `t('a.b')` still reaches into `lower`. Those descendants come back as flat
* dotted keys, which is what `getByPath` looks at first anyway.
*
* The alternative — resolving every collected path one at a time — returned a different
* shape depending on whether a second layer happened to be live, and repeated each nested
* leaf as a flat key beside the object holding it.
*/
export declare function mergeTranslationLayers(lower: Record<string, unknown>, upper: Record<string, unknown>): Record<string, unknown>;
export declare function collectTranslationPaths(obj: Record<string, unknown>, paths: Set<string>, prefix?: string): void;
export declare function withPrefixStrategy(strategy: Strategies): strategy is "prefix" | "prefix_and_default";

@@ -14,0 +56,0 @@ export declare function isNoPrefixStrategy(strategy: Strategies): strategy is "no_prefix";

@@ -9,5 +9,47 @@ import { Params, PluralFunc, Strategies } from '@i18n-micro/types';

}
/**
* Merge two translation chunks, descending into nested objects.
*
* `Object.assign` is wrong here, and quietly so: chunks are trees, so a shallow merge of
* `{ nav: { about, home } }` with `{ nav: { extra } }` replaces the whole `nav` subtree
* and loses `about` and `home`. Nothing throws — the keys simply resolve to themselves
* later, which is the raw-key render the loader exists to prevent.
*
* Written here rather than reusing `@i18n-micro/utils/deep-merge`: that package carries
* build-time dependencies, and `core` is installed by every consumer at runtime.
*/
export declare function mergeTranslationChunk(existing: Record<string, unknown>, incoming: Record<string, unknown>, options?: MergeTranslationChunkOptions): Record<string, unknown>;
export declare function interpolate(template: string, params: Params): string;
export declare function getByPath(obj: Record<string, unknown> | null | undefined, path: string): unknown;
/**
* A translation tree with `key` set to `value`, whatever either of them is.
*
* Replaces rather than merges: `set('aaa', { x: 1 })` on `{ aaa: { bbb: 'ccc' } }` leaves
* `aaa` holding only `x`, and `set('aaa', 'text')` leaves a string where a subtree was.
* Merging is what `mergeTranslationChunk` is for.
*
* The tree is not mutated — only the nodes along the path are copied, so the call costs the
* depth of the key and not the size of the dictionary, and callers holding the old tree
* (a frozen SSR chunk, a rendered snapshot) keep seeing what they had.
*
* Key resolution mirrors {@link getByPath}: an existing flat key wins over the dotted path,
* so a dictionary written as `{ 'a.b': 'x' }` is updated in place rather than gaining a
* nested `a.b` that `t('a.b')` would never read.
*/
export declare function setTranslationAtKey(tree: Record<string, unknown>, key: string, value: unknown): Record<string, unknown>;
/**
* Two live lookup layers as one tree, shaped the way a single layer already is.
*
* `upper` wins, exactly as a per-key fallthrough does, so the result answers every key the
* two layers together can answer — with one exception that a tree cannot express: where
* `upper` holds a scalar and `lower` holds an object at the same path, `t('a')` reads the
* scalar while `t('a.b')` still reaches into `lower`. Those descendants come back as flat
* dotted keys, which is what `getByPath` looks at first anyway.
*
* The alternative — resolving every collected path one at a time — returned a different
* shape depending on whether a second layer happened to be live, and repeated each nested
* leaf as a flat key beside the object holding it.
*/
export declare function mergeTranslationLayers(lower: Record<string, unknown>, upper: Record<string, unknown>): Record<string, unknown>;
export declare function collectTranslationPaths(obj: Record<string, unknown>, paths: Set<string>, prefix?: string): void;
export declare function withPrefixStrategy(strategy: Strategies): strategy is "prefix" | "prefix_and_default";

@@ -14,0 +56,0 @@ export declare function isNoPrefixStrategy(strategy: Strategies): strategy is "no_prefix";

@@ -1,74 +0,141 @@

const f = /\{(\w+)\}/g, c = "index";
function d(r, t) {
return `${r}:${t || c}`;
const p = /\{(\w+)\}/g, y = "index";
function O(t, n) {
return `${t}:${n || y}`;
}
function s(r, t) {
if (r == null) return null;
const e = a(r, t);
return e === void 0 ? null : e;
function g(t, n) {
if (t == null) return null;
const o = v(t, n);
return o === void 0 ? null : o;
}
function p(r, t) {
return s(r, t) !== null;
function x(t, n) {
return g(t, n) !== null;
}
function g(r, t, e) {
return Object.keys(r).length === 0 ? t : e?.preserveExisting ? Object.assign({}, t, r) : Object.assign({}, r, t);
function T(t, n, o) {
return Object.keys(t).length === 0 ? n : o?.preserveExisting ? l(n, t) : l(t, n);
}
function x(r, t) {
return !t || r.indexOf("{") === -1 ? r : r.replace(f, (e, n) => {
const i = t[n];
return i !== void 0 ? String(i) : `{${n}}`;
const f = (t) => t !== null && typeof t == "object" && !Array.isArray(t);
function l(t, n) {
const o = { ...t };
for (const e of Object.keys(n)) {
if (e === "__proto__") continue;
const r = n[e], i = o[e];
o[e] = f(r) && f(i) ? l(i, r) : r;
}
return o;
}
function P(t, n) {
return !n || t.indexOf("{") === -1 ? t : t.replace(p, (o, e) => {
const r = n[e];
return r !== void 0 ? String(r) : `{${e}}`;
});
}
function a(r, t) {
if (r == null || typeof t != "string" || t.length === 0) return;
if (Object.prototype.hasOwnProperty.call(r, t))
return r[t];
if (!t.includes(".")) return;
const e = t.split(".");
let n = r;
for (const i of e) {
if (n == null || typeof n != "object") return;
const u = n;
if (!Object.prototype.hasOwnProperty.call(u, i)) return;
n = u[i];
function v(t, n) {
if (t == null || typeof n != "string" || n.length === 0) return;
if (Object.prototype.hasOwnProperty.call(t, n))
return t[n];
if (!n.includes(".")) return;
const o = n.split(".");
let e = t;
for (const r of o) {
if (e == null || typeof e != "object") return;
const i = e;
if (!Object.prototype.hasOwnProperty.call(i, r)) return;
e = i[r];
}
return n;
return e;
}
function v(r) {
return r === "prefix" || r === "prefix_and_default";
function b(t, n, o) {
if (typeof n != "string" || n.length === 0) return t;
if (Object.prototype.hasOwnProperty.call(t, n) || !n.includes("."))
return n === "__proto__" ? t : { ...t, [n]: o };
const e = n.split(".");
if (e.some((c) => c === "__proto__")) return t;
const r = { ...t };
let i = r;
for (const c of e.slice(0, -1)) {
const s = i[c], u = f(s) ? { ...s } : {};
i[c] = u, i = u;
}
return i[e[e.length - 1]] = o, r;
}
function y(r) {
return r === "no_prefix";
function S(t, n) {
const o = a(t, n), e = {};
return _(t, n, "", e), Object.keys(e).length === 0 ? o : { ...o, ...e };
}
function _(r) {
return r === "prefix";
function a(t, n) {
const o = { ...t };
for (const e of Object.keys(n)) {
if (e === "__proto__") continue;
const r = n[e];
if (r == null) continue;
const i = o[e];
o[e] = f(r) && f(i) ? a(i, r) : r;
}
return o;
}
function O(r) {
return r === "prefix_except_default";
function _(t, n, o, e) {
for (const r of Object.keys(t)) {
if (r === "__proto__") continue;
const i = t[r];
if (!f(i)) continue;
const c = o ? `${o}.${r}` : r, s = n[r];
f(s) ? _(i, s, c, e) : s != null && d(i, c, e);
}
}
function P(r) {
return r === "prefix_and_default";
function d(t, n, o) {
for (const e of Object.keys(t)) {
if (e === "__proto__") continue;
const r = t[e], i = `${n}.${e}`;
f(r) ? d(r, i, o) : o[i] = r;
}
}
const S = (r, t, e, n, i) => {
const u = i(r, e);
if (!u)
function h(t, n, o = "") {
for (const e of Object.keys(t)) {
if (e === "__proto__") continue;
const r = o ? `${o}.${e}` : e;
n.add(r);
const i = t[e];
f(i) && h(i, n, r);
}
}
function $(t) {
return t === "prefix" || t === "prefix_and_default";
}
function E(t) {
return t === "no_prefix";
}
function j(t) {
return t === "prefix";
}
function k(t) {
return t === "prefix_except_default";
}
function w(t) {
return t === "prefix_and_default";
}
const A = (t, n, o, e, r) => {
const i = r(t, o);
if (!i)
return null;
const l = u.toString().split("|");
if (l.length === 0) return null;
const o = t < l.length ? l[t] : l[l.length - 1];
return o ? o.trim().replace("{count}", t.toString()) : null;
const c = i.toString().split("|");
if (c.length === 0) return null;
const s = n < c.length ? c[n] : c[c.length - 1];
return s ? s.trim().replace("{count}", n.toString()) : null;
};
export {
S as defaultPlural,
a as getByPath,
p as hasTranslationValue,
x as interpolate,
y as isNoPrefixStrategy,
P as isPrefixAndDefaultStrategy,
O as isPrefixExceptDefaultStrategy,
_ as isPrefixStrategy,
g as mergeTranslationChunk,
s as resolveTranslation,
d as translationCacheKey,
v as withPrefixStrategy
h as collectTranslationPaths,
A as defaultPlural,
v as getByPath,
x as hasTranslationValue,
P as interpolate,
E as isNoPrefixStrategy,
w as isPrefixAndDefaultStrategy,
k as isPrefixExceptDefaultStrategy,
j as isPrefixStrategy,
T as mergeTranslationChunk,
S as mergeTranslationLayers,
g as resolveTranslation,
b as setTranslationAtKey,
O as translationCacheKey,
$ as withPrefixStrategy
};

@@ -1,1 +0,1 @@

"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("./helpers.cjs");class g{formatNumber(t,e,r){return new Intl.NumberFormat(e,r).format(t)}formatDate(t,e,r){const s=new Date(t);return Number.isNaN(s.getTime())?"Invalid Date":new Intl.DateTimeFormat(e,r).format(s)}formatRelativeTime(t,e,r){const s=new Date(t),n=new Intl.RelativeTimeFormat(e,r);if(Number.isNaN(s.getTime()))return n.format(0,"second");const i=Math.floor((Date.now()-s.getTime())/1e3),o=[{unit:"year",seconds:31536e3},{unit:"month",seconds:2592e3},{unit:"day",seconds:86400},{unit:"hour",seconds:3600},{unit:"minute",seconds:60},{unit:"second",seconds:1}];for(const{unit:u,seconds:h}of o){const l=Math.floor(i/h);if(l>=1)return n.format(-l,u)}return n.format(0,"second")}}function f(c){const t=c?.translations??new Map;return{hasCache(e,r){return t.has(a.translationCacheKey(e,r))},getCache(e,r){return t.get(a.translationCacheKey(e,r))},setCache(e,r,s){},hasTranslation(e,r){for(const[s,n]of t)if(s.startsWith(`${e}:`)&&a.getByPath(n,r)!==void 0)return!0;return!1},hasPageTranslation(e,r){return t.has(a.translationCacheKey(e,r))},getTranslation(e,r,s){const n=t.get(a.translationCacheKey(e,r));return n?a.resolveTranslation(n,s):null},loadTranslations(e,r,s="index"){const n=a.translationCacheKey(e,s),i=t.get(n);i?Object.assign(i,r):t.set(n,{...r})},setTranslations(e,r,s="index"){t.set(a.translationCacheKey(e,s),r)},loadPageTranslations(e,r,s){const n=a.translationCacheKey(e,r),i=t.get(n);!i||Object.keys(i).length===0?t.set(n,{...s}):Object.assign(i,s)},mergeTranslation(e,r,s,n=!1){const i=a.translationCacheKey(e,r),o=t.get(i);o?Object.assign(o,s):t.set(i,{...s})},clearCache(){t.clear()}}}class m{constructor(t={}){this.formatter=new g,this.helper=f(t.storage),this.formatter=new g,this.pluralFunc=t.plural||a.defaultPlural,this.missingWarn=t.missingWarn??!0,this.missingHandler=t.missingHandler,this.getCustomMissingHandler=t.getCustomMissingHandler}touch(){}resolveRouteName(t){return typeof t=="string"?t:this.getRoute()}resolveLookup(t,e){const r=this.getLocale(),s=this.resolveRouteName(e);let n=this.helper.getTranslation(r,s,String(t));if(n===null){const i=this.getFallbackLocale();r!==i&&(n=this.helper.getTranslation(i,s,String(t)))}return n}resolveHas(t,e){const r=this.getLocale(),s=this.resolveRouteName(e);return this.helper.getTranslation(r,s,String(t))!==null}getMissingContext(t){return{locale:this.getLocale(),routeName:this.resolveRouteName(t)}}warnMissing(t,e){const{locale:r,routeName:s}=this.getMissingContext(e),n=this.getCustomMissingHandler?.();if(n){n(r,String(t),s);return}if(this.missingHandler){this.missingHandler(r,String(t),s);return}this.missingWarn&&process.env.NODE_ENV!=="production"&&typeof window<"u"&&console.warn(`Not found '${t}' key in '${r}' locale messages for route '${s}'.`)}t(t,e,r,s){if(!t)return"";this.touch();const n=this.resolveLookup(t,s);return n==null?(this.warnMissing(t,s),r===void 0?t:r||t):typeof n!="string"||!e?n:a.interpolate(n,e)}ts(t,e,r,s){return this.t(t,e,r,s)?.toString()??r??t}tc(t,e,r){this.touch();const{count:s,...n}=typeof e=="number"?{count:e}:e;if(s===void 0)return r??t;const i=(u,h,l)=>this.t(u,h,l);return this.pluralFunc(t,Number.parseInt(s.toString(),10),n,this.getLocale(),i)??r??t}tn(t,e){return this.touch(),this.formatter.formatNumber(t,this.getLocale(),e)}td(t,e){return this.touch(),this.formatter.formatDate(t,this.getLocale(),e)}tdr(t,e){return this.touch(),this.formatter.formatRelativeTime(t,this.getLocale(),e)}has(t,e){return this.touch(),this.resolveHas(t,e)}clearCache(){this.helper.clearCache()}loadTranslationsCore(t,e,r,s="index"){r?this.helper.mergeTranslation(t,s,e,!0):this.helper.setTranslations(t,e,s)}loadRouteTranslationsCore(t,e,r,s){s?this.helper.mergeTranslation(t,e,r,!0):this.helper.loadPageTranslations(t,e,r)}}exports.defaultPlural=a.defaultPlural;exports.getByPath=a.getByPath;exports.hasTranslationValue=a.hasTranslationValue;exports.interpolate=a.interpolate;exports.isNoPrefixStrategy=a.isNoPrefixStrategy;exports.isPrefixAndDefaultStrategy=a.isPrefixAndDefaultStrategy;exports.isPrefixExceptDefaultStrategy=a.isPrefixExceptDefaultStrategy;exports.isPrefixStrategy=a.isPrefixStrategy;exports.mergeTranslationChunk=a.mergeTranslationChunk;exports.resolveTranslation=a.resolveTranslation;exports.translationCacheKey=a.translationCacheKey;exports.withPrefixStrategy=a.withPrefixStrategy;exports.BaseI18n=m;exports.FormatService=g;exports.useTranslationHelper=f;
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("./helpers.cjs");function d(l){if(!l)return"";const t=Object.keys(l).sort();if(t.length===0)return"";const e={};for(const a of t)e[a]=l[a];return JSON.stringify(e)}function m(l,t){const e=d(t);return e?`${l}\0${e}`:l}class g{constructor(t={}){this.numberCache=new Map,this.dateCache=new Map,this.relativeCache=new Map,this.numberFormats=t.numberFormats??{},this.datetimeFormats=t.datetimeFormats??{}}setNumberFormats(t){this.numberFormats=t,this.numberCache.clear()}setDateTimeFormats(t){this.datetimeFormats=t,this.dateCache.clear()}getNumberFormats(){return this.numberFormats}getDateTimeFormats(){return this.datetimeFormats}clearCache(){this.numberCache.clear(),this.dateCache.clear(),this.relativeCache.clear()}resolveNumberFormat(t,e){return this.numberFormats[t]?.[e]??this.numberFormats[t.split("-")[0]]?.[e]}resolveDateTimeFormat(t,e){return this.datetimeFormats[t]?.[e]??this.datetimeFormats[t.split("-")[0]]?.[e]}getNumberFormatter(t,e){const a=m(t,e);let r=this.numberCache.get(a);return r||(r=new Intl.NumberFormat(t,e),this.numberCache.set(a,r)),r}getDateTimeFormatter(t,e){const a=m(t,e);let r=this.dateCache.get(a);return r||(r=new Intl.DateTimeFormat(t,e),this.dateCache.set(a,r)),r}getRelativeTimeFormatter(t,e){const a=m(t,e);let r=this.relativeCache.get(a);return r||(r=new Intl.RelativeTimeFormat(t,e),this.relativeCache.set(a,r)),r}formatNumber(t,e,a){return this.getNumberFormatter(e,a).format(t)}formatDate(t,e,a){const r=new Date(t);return Number.isNaN(r.getTime())?"Invalid Date":this.getDateTimeFormatter(e,a).format(r)}formatRelativeTime(t,e,a){const r=new Date(t),s=this.getRelativeTimeFormatter(e,a);if(Number.isNaN(r.getTime()))return s.format(0,"second");const n=Math.floor((Date.now()-r.getTime())/1e3),o=[{unit:"year",seconds:31536e3},{unit:"month",seconds:2592e3},{unit:"day",seconds:86400},{unit:"hour",seconds:3600},{unit:"minute",seconds:60},{unit:"second",seconds:1}];for(const{unit:h,seconds:u}of o){const c=Math.floor(n/u);if(c>=1)return s.format(-c,h)}return s.format(0,"second")}}function f(l){const t=l?.translations??new Map;return{hasCache(e,a){return t.has(i.translationCacheKey(e,a))},getCache(e,a){return t.get(i.translationCacheKey(e,a))},setCache(e,a,r){},hasTranslation(e,a){for(const[r,s]of t)if(r.startsWith(`${e}:`)&&i.getByPath(s,a)!==void 0)return!0;return!1},hasPageTranslation(e,a){return t.has(i.translationCacheKey(e,a))},getTranslation(e,a,r){const s=t.get(i.translationCacheKey(e,a));return s?i.resolveTranslation(s,r):null},loadTranslations(e,a,r="index"){const s=i.translationCacheKey(e,r),n=t.get(s);n?Object.assign(n,a):t.set(s,{...a})},setTranslations(e,a,r="index"){t.set(i.translationCacheKey(e,r),a)},loadPageTranslations(e,a,r){const s=i.translationCacheKey(e,a),n=t.get(s);!n||Object.keys(n).length===0?t.set(s,{...r}):Object.assign(n,r)},mergeTranslation(e,a,r,s=!1){const n=i.translationCacheKey(e,a),o=t.get(n);o?Object.assign(o,r):t.set(n,{...r})},clearCache(){t.clear()}}}class T{constructor(t={}){this.formatter=new g,this.helper=f(t.storage);const e={numberFormats:t.numberFormats,datetimeFormats:t.datetimeFormats};this.formatter=new g(e),this.pluralFunc=t.plural||i.defaultPlural,this.missingWarn=t.missingWarn??!0,this.missingHandler=t.missingHandler,this.getCustomMissingHandler=t.getCustomMissingHandler}touch(){}resolveRouteName(t){return typeof t=="string"?t:this.getRoute()}resolveLookup(t,e){const a=this.getLocale(),r=this.resolveRouteName(e),s=this.helper.getTranslation(a,r,String(t));if(s!==null)return s;const n=this.getFallbackLocale();return a!==n?this.helper.getTranslation(n,r,String(t)):null}resolveHas(t,e){const a=this.getLocale(),r=this.resolveRouteName(e);return this.helper.getTranslation(a,r,String(t))!==null}resolveTranslationTree(t,e){return i.mergeTranslationLayers(t,e)}resolveTranslations(t){this.touch();const e=this.getLocale(),a=this.resolveRouteName(t),r=this.helper.getCache(e,a)??{},s=this.getFallbackLocale();if(s===e)return r;const n=this.helper.getCache(s,a);return n?this.resolveTranslationTree(n,r):r}onTranslationsChanged(){}getMissingContext(t){return{locale:this.getLocale(),routeName:this.resolveRouteName(t)}}warnDev(t){this.missingWarn&&process.env.NODE_ENV!=="production"&&(typeof window>"u"||console.warn(t))}warnMissing(t,e){const{locale:a,routeName:r}=this.getMissingContext(e),s=this.getCustomMissingHandler?.();if(s){s(a,String(t),r);return}if(this.missingHandler){this.missingHandler(a,String(t),r);return}this.warnDev(`Not found '${t}' key in '${a}' locale messages for route '${r}'.`)}warnMissingFormat(t,e,a){this.warnDev(`Not found '${e}' ${t} format in '${a}' locale. Falling back to default Intl options.`)}t(t,e,a,r){if(!t)return"";this.touch();const s=this.resolveLookup(t,r);return s==null?(this.warnMissing(t,r),a===void 0?t:a||t):typeof s!="string"||!e?s:i.interpolate(s,e)}ts(t,e,a,r){return this.t(t,e,a,r)?.toString()??a??t}tc(t,e,a){this.touch();const{count:r,...s}=typeof e=="number"?{count:e}:e;if(r===void 0)return a??t;const n=(h,u,c)=>this.t(h,u,c);return this.pluralFunc(t,Number.parseInt(r.toString(),10),s,this.getLocale(),n)??a??t}tn(t,e,a,r){this.touch();const s=this.resolveNumberFormatArgs(e,a,r);return this.formatter.formatNumber(t,s.locale,s.options)}td(t,e,a,r){this.touch();const s=this.resolveDateTimeFormatArgs(e,a,r);return this.formatter.formatDate(t,s.locale,s.options)}tdr(t,e){return this.touch(),this.formatter.formatRelativeTime(t,this.getLocale(),e)}has(t,e){return this.touch(),this.resolveHas(t,e)}setTranslation(t,e){const a=this.getLocale(),r=this.getRoute(),s=this.helper.getCache(a,r)??{};this.helper.setTranslations(a,i.setTranslationAtKey(s,String(t),e),r),this.onTranslationsChanged()}clearCache(){this.helper.clearCache(),this.formatter.clearCache()}resolveNumberFormatArgs(t,e,a){if(typeof t!="string")return{locale:this.getLocale(),options:t};let r=this.getLocale(),s;typeof e=="string"?(r=e,s=a):s=e;const n=this.formatter.resolveNumberFormat(r,t);return n||this.warnMissingFormat("number",t,r),!n&&!s?{locale:r,options:void 0}:{locale:r,options:n?{...n,...s}:s}}resolveDateTimeFormatArgs(t,e,a){if(typeof t!="string")return{locale:this.getLocale(),options:t};let r=this.getLocale(),s;typeof e=="string"?(r=e,s=a):s=e;const n=this.formatter.resolveDateTimeFormat(r,t);return n||this.warnMissingFormat("datetime",t,r),!n&&!s?{locale:r,options:void 0}:{locale:r,options:n?{...n,...s}:s}}loadTranslationsCore(t,e,a,r="index"){a?this.helper.mergeTranslation(t,r,e,!0):this.helper.setTranslations(t,e,r)}loadRouteTranslationsCore(t,e,a,r){r?this.helper.mergeTranslation(t,e,a,!0):this.helper.loadPageTranslations(t,e,a)}}function b(l){let t=l.locale,e=l.fallbackLocale??l.locale,a=l.route??"index",r=0;const s=new Set,n=()=>{r++,s.forEach(o=>o())};return{subscribe(o){return s.add(o),()=>s.delete(o)},getSnapshot(){return`${t}:${a}:${r}`},getLocale(){return t},setLocale(o){t!==o&&(t=o,n())},getFallbackLocale(){return e},setFallbackLocale(o){e!==o&&(e=o,n())},getRoute(){return a},setRoute(o){a!==o&&(a=o,n())},notify:n}}exports.collectTranslationPaths=i.collectTranslationPaths;exports.defaultPlural=i.defaultPlural;exports.getByPath=i.getByPath;exports.hasTranslationValue=i.hasTranslationValue;exports.interpolate=i.interpolate;exports.isNoPrefixStrategy=i.isNoPrefixStrategy;exports.isPrefixAndDefaultStrategy=i.isPrefixAndDefaultStrategy;exports.isPrefixExceptDefaultStrategy=i.isPrefixExceptDefaultStrategy;exports.isPrefixStrategy=i.isPrefixStrategy;exports.mergeTranslationChunk=i.mergeTranslationChunk;exports.mergeTranslationLayers=i.mergeTranslationLayers;exports.resolveTranslation=i.resolveTranslation;exports.setTranslationAtKey=i.setTranslationAtKey;exports.translationCacheKey=i.translationCacheKey;exports.withPrefixStrategy=i.withPrefixStrategy;exports.BaseI18n=T;exports.FormatService=g;exports.createReactiveI18nStore=b;exports.useTranslationHelper=f;
import { BaseI18n, BaseI18nOptions } from './base';
import { FormatService } from './format-service';
import { defaultPlural, getByPath, hasTranslationValue, interpolate, isNoPrefixStrategy, isPrefixAndDefaultStrategy, isPrefixExceptDefaultStrategy, isPrefixStrategy, mergeTranslationChunk, resolveTranslation, translationCacheKey, withPrefixStrategy, MergeTranslationChunkOptions } from './helpers';
import { FormatService, DateTimeFormatsConfig, FormatServiceOptions, NumberFormatsConfig } from './format-service';
import { defaultPlural, getByPath, hasTranslationValue, interpolate, isNoPrefixStrategy, isPrefixAndDefaultStrategy, isPrefixExceptDefaultStrategy, isPrefixStrategy, collectTranslationPaths, mergeTranslationChunk, mergeTranslationLayers, resolveTranslation, setTranslationAtKey, translationCacheKey, withPrefixStrategy, MergeTranslationChunkOptions } from './helpers';
import { TranslationStorage, useTranslationHelper } from './translation';
export { useTranslationHelper, interpolate, getByPath, hasTranslationValue, mergeTranslationChunk, resolveTranslation, translationCacheKey, withPrefixStrategy, isNoPrefixStrategy, isPrefixStrategy, isPrefixExceptDefaultStrategy, isPrefixAndDefaultStrategy, defaultPlural, FormatService, BaseI18n, type MergeTranslationChunkOptions, type TranslationStorage, type BaseI18nOptions, };
import { createReactiveI18nStore, ReactiveI18nStore } from './reactive-store';
export { useTranslationHelper, interpolate, getByPath, hasTranslationValue, collectTranslationPaths, mergeTranslationChunk, mergeTranslationLayers, resolveTranslation, setTranslationAtKey, translationCacheKey, withPrefixStrategy, isNoPrefixStrategy, isPrefixStrategy, isPrefixExceptDefaultStrategy, isPrefixAndDefaultStrategy, defaultPlural, FormatService, BaseI18n, createReactiveI18nStore, type MergeTranslationChunkOptions, type TranslationStorage, type BaseI18nOptions, type ReactiveI18nStore, type NumberFormatsConfig, type DateTimeFormatsConfig, type FormatServiceOptions, };
import { BaseI18n, BaseI18nOptions } from './base';
import { FormatService } from './format-service';
import { defaultPlural, getByPath, hasTranslationValue, interpolate, isNoPrefixStrategy, isPrefixAndDefaultStrategy, isPrefixExceptDefaultStrategy, isPrefixStrategy, mergeTranslationChunk, resolveTranslation, translationCacheKey, withPrefixStrategy, MergeTranslationChunkOptions } from './helpers';
import { FormatService, DateTimeFormatsConfig, FormatServiceOptions, NumberFormatsConfig } from './format-service';
import { defaultPlural, getByPath, hasTranslationValue, interpolate, isNoPrefixStrategy, isPrefixAndDefaultStrategy, isPrefixExceptDefaultStrategy, isPrefixStrategy, collectTranslationPaths, mergeTranslationChunk, mergeTranslationLayers, resolveTranslation, setTranslationAtKey, translationCacheKey, withPrefixStrategy, MergeTranslationChunkOptions } from './helpers';
import { TranslationStorage, useTranslationHelper } from './translation';
export { useTranslationHelper, interpolate, getByPath, hasTranslationValue, mergeTranslationChunk, resolveTranslation, translationCacheKey, withPrefixStrategy, isNoPrefixStrategy, isPrefixStrategy, isPrefixExceptDefaultStrategy, isPrefixAndDefaultStrategy, defaultPlural, FormatService, BaseI18n, type MergeTranslationChunkOptions, type TranslationStorage, type BaseI18nOptions, };
import { createReactiveI18nStore, ReactiveI18nStore } from './reactive-store';
export { useTranslationHelper, interpolate, getByPath, hasTranslationValue, collectTranslationPaths, mergeTranslationChunk, mergeTranslationLayers, resolveTranslation, setTranslationAtKey, translationCacheKey, withPrefixStrategy, isNoPrefixStrategy, isPrefixStrategy, isPrefixExceptDefaultStrategy, isPrefixAndDefaultStrategy, defaultPlural, FormatService, BaseI18n, createReactiveI18nStore, type MergeTranslationChunkOptions, type TranslationStorage, type BaseI18nOptions, type ReactiveI18nStore, type NumberFormatsConfig, type DateTimeFormatsConfig, type FormatServiceOptions, };

@@ -1,16 +0,70 @@

import { translationCacheKey as a, resolveTranslation as f, getByPath as m, defaultPlural as d, interpolate as v } from "./helpers.mjs";
import { hasTranslationValue as w, isNoPrefixStrategy as x, isPrefixAndDefaultStrategy as S, isPrefixExceptDefaultStrategy as D, isPrefixStrategy as H, mergeTranslationChunk as L, withPrefixStrategy as M } from "./helpers.mjs";
class g {
import { translationCacheKey as l, resolveTranslation as g, getByPath as d, defaultPlural as b, mergeTranslationLayers as F, interpolate as T, setTranslationAtKey as v } from "./helpers.mjs";
import { collectTranslationPaths as x, hasTranslationValue as y, isNoPrefixStrategy as R, isPrefixAndDefaultStrategy as M, isPrefixExceptDefaultStrategy as $, isPrefixStrategy as H, mergeTranslationChunk as P, withPrefixStrategy as k } from "./helpers.mjs";
function C(o) {
if (!o) return "";
const t = Object.keys(o).sort();
if (t.length === 0) return "";
const e = {};
for (const s of t)
e[s] = o[s];
return JSON.stringify(e);
}
function m(o, t) {
const e = C(t);
return e ? `${o}\0${e}` : o;
}
class f {
constructor(t = {}) {
this.numberCache = /* @__PURE__ */ new Map(), this.dateCache = /* @__PURE__ */ new Map(), this.relativeCache = /* @__PURE__ */ new Map(), this.numberFormats = t.numberFormats ?? {}, this.datetimeFormats = t.datetimeFormats ?? {};
}
setNumberFormats(t) {
this.numberFormats = t, this.numberCache.clear();
}
setDateTimeFormats(t) {
this.datetimeFormats = t, this.dateCache.clear();
}
getNumberFormats() {
return this.numberFormats;
}
getDateTimeFormats() {
return this.datetimeFormats;
}
clearCache() {
this.numberCache.clear(), this.dateCache.clear(), this.relativeCache.clear();
}
/** Resolve a named number format for a locale (exact match, then language subtag). */
resolveNumberFormat(t, e) {
return this.numberFormats[t]?.[e] ?? this.numberFormats[t.split("-")[0]]?.[e];
}
/** Resolve a named datetime format for a locale (exact match, then language subtag). */
resolveDateTimeFormat(t, e) {
return this.datetimeFormats[t]?.[e] ?? this.datetimeFormats[t.split("-")[0]]?.[e];
}
getNumberFormatter(t, e) {
const s = m(t, e);
let r = this.numberCache.get(s);
return r || (r = new Intl.NumberFormat(t, e), this.numberCache.set(s, r)), r;
}
getDateTimeFormatter(t, e) {
const s = m(t, e);
let r = this.dateCache.get(s);
return r || (r = new Intl.DateTimeFormat(t, e), this.dateCache.set(s, r)), r;
}
getRelativeTimeFormatter(t, e) {
const s = m(t, e);
let r = this.relativeCache.get(s);
return r || (r = new Intl.RelativeTimeFormat(t, e), this.relativeCache.set(s, r)), r;
}
formatNumber(t, e, s) {
return new Intl.NumberFormat(e, s).format(t);
return this.getNumberFormatter(e, s).format(t);
}
formatDate(t, e, s) {
const r = new Date(t);
return Number.isNaN(r.getTime()) ? "Invalid Date" : new Intl.DateTimeFormat(e, s).format(r);
return Number.isNaN(r.getTime()) ? "Invalid Date" : this.getDateTimeFormatter(e, s).format(r);
}
formatRelativeTime(t, e, s) {
const r = new Date(t), n = new Intl.RelativeTimeFormat(e, s);
const r = new Date(t), a = this.getRelativeTimeFormatter(e, s);
if (Number.isNaN(r.getTime()))
return n.format(0, "second");
const i = Math.floor((Date.now() - r.getTime()) / 1e3), o = [
return a.format(0, "second");
const n = Math.floor((Date.now() - r.getTime()) / 1e3), i = [
{ unit: "year", seconds: 31536e3 },

@@ -23,18 +77,18 @@ { unit: "month", seconds: 2592e3 },

];
for (const { unit: u, seconds: h } of o) {
const l = Math.floor(i / h);
if (l >= 1)
return n.format(-l, u);
for (const { unit: h, seconds: u } of i) {
const c = Math.floor(n / u);
if (c >= 1)
return a.format(-c, h);
}
return n.format(0, "second");
return a.format(0, "second");
}
}
function T(c) {
const t = c?.translations ?? /* @__PURE__ */ new Map();
function p(o) {
const t = o?.translations ?? /* @__PURE__ */ new Map();
return {
hasCache(e, s) {
return t.has(a(e, s));
return t.has(l(e, s));
},
getCache(e, s) {
return t.get(a(e, s));
return t.get(l(e, s));
},

@@ -44,4 +98,4 @@ setCache(e, s, r) {

hasTranslation(e, s) {
for (const [r, n] of t)
if (r.startsWith(`${e}:`) && m(n, s) !== void 0)
for (const [r, a] of t)
if (r.startsWith(`${e}:`) && d(a, s) !== void 0)
return !0;

@@ -51,22 +105,22 @@ return !1;

hasPageTranslation(e, s) {
return t.has(a(e, s));
return t.has(l(e, s));
},
getTranslation(e, s, r) {
const n = t.get(a(e, s));
return n ? f(n, r) : null;
const a = t.get(l(e, s));
return a ? g(a, r) : null;
},
loadTranslations(e, s, r = "index") {
const n = a(e, r), i = t.get(n);
i ? Object.assign(i, s) : t.set(n, { ...s });
const a = l(e, r), n = t.get(a);
n ? Object.assign(n, s) : t.set(a, { ...s });
},
setTranslations(e, s, r = "index") {
t.set(a(e, r), s);
t.set(l(e, r), s);
},
loadPageTranslations(e, s, r) {
const n = a(e, s), i = t.get(n);
!i || Object.keys(i).length === 0 ? t.set(n, { ...r }) : Object.assign(i, r);
const a = l(e, s), n = t.get(a);
!n || Object.keys(n).length === 0 ? t.set(a, { ...r }) : Object.assign(n, r);
},
mergeTranslation(e, s, r, n = !1) {
const i = a(e, s), o = t.get(i);
o ? Object.assign(o, r) : t.set(i, { ...r });
mergeTranslation(e, s, r, a = !1) {
const n = l(e, s), i = t.get(n);
i ? Object.assign(i, r) : t.set(n, { ...r });
},

@@ -78,5 +132,15 @@ clearCache() {

}
class N {
class w {
/**
* Set on the server when the SSR payload should carry only the keys the render
* actually used. `null` on the client and in `chunk` mode, so the lookup path
* stays a plain property read.
*/
constructor(t = {}) {
this.formatter = new g(), this.helper = T(t.storage), this.formatter = new g(), this.pluralFunc = t.plural || d, this.missingWarn = t.missingWarn ?? !0, this.missingHandler = t.missingHandler, this.getCustomMissingHandler = t.getCustomMissingHandler;
this.formatter = new f(), this.helper = p(t.storage);
const e = {
numberFormats: t.numberFormats,
datetimeFormats: t.datetimeFormats
};
this.formatter = new f(e), this.pluralFunc = t.plural || b, this.missingWarn = t.missingWarn ?? !0, this.missingHandler = t.missingHandler, this.getCustomMissingHandler = t.getCustomMissingHandler;
}

@@ -99,9 +163,6 @@ // --- Protected hooks (subclasses may override) ---

resolveLookup(t, e) {
const s = this.getLocale(), r = this.resolveRouteName(e);
let n = this.helper.getTranslation(s, r, String(t));
if (n === null) {
const i = this.getFallbackLocale();
s !== i && (n = this.helper.getTranslation(i, r, String(t)));
}
return n;
const s = this.getLocale(), r = this.resolveRouteName(e), a = this.helper.getTranslation(s, r, String(t));
if (a !== null) return a;
const n = this.getFallbackLocale();
return s !== n ? this.helper.getTranslation(n, r, String(t)) : null;
}

@@ -116,2 +177,31 @@ /**

/**
* Two live layers as one tree, via {@link mergeTranslationLayers}.
*
* Used when the hot path keeps two objects instead of merging them — the fallback locale,
* or the Nuxt page-transition layer — so the dump answers what `t()` answers.
*/
resolveTranslationTree(t, e) {
return F(t, e);
}
/**
* Dump of what `t()` can resolve right now for the active locale and route.
*
* Live tree, not a clone — read-only; mutate via {@link setTranslation} / merge helpers.
* When a second layer is live (fallback locale, Nuxt transition hot-reload), walks both
* through {@link resolveTranslationTree} so the dump matches `t()`.
*/
resolveTranslations(t) {
this.touch();
const e = this.getLocale(), s = this.resolveRouteName(t), r = this.helper.getCache(e, s) ?? {}, a = this.getFallbackLocale();
if (a === e) return r;
const n = this.helper.getCache(a, s);
return n ? this.resolveTranslationTree(n, r) : r;
}
/**
* Called after {@link setTranslation} changes the dictionary. Adapters override it to
* bump whatever their reactivity is built on.
*/
onTranslationsChanged() {
}
/**
* Context passed to missing-key handlers.

@@ -123,8 +213,15 @@ */

/**
* Dev-only client `console.warn`, gated by `missingWarn`.
* Shared by missing translations and missing named formats.
*/
warnDev(t) {
this.missingWarn && process.env.NODE_ENV !== "production" && (typeof window > "u" || console.warn(t));
}
/**
* Warn or invoke handler when translation is missing.
*/
warnMissing(t, e) {
const { locale: s, routeName: r } = this.getMissingContext(e), n = this.getCustomMissingHandler?.();
if (n) {
n(s, String(t), r);
const { locale: s, routeName: r } = this.getMissingContext(e), a = this.getCustomMissingHandler?.();
if (a) {
a(s, String(t), r);
return;

@@ -136,4 +233,11 @@ }

}
this.missingWarn && process.env.NODE_ENV !== "production" && typeof window < "u" && console.warn(`Not found '${t}' key in '${s}' locale messages for route '${r}'.`);
this.warnDev(`Not found '${t}' key in '${s}' locale messages for route '${r}'.`);
}
/**
* Warn when a named number/datetime format key is missing.
* Falls back to default Intl options (visible in dev via {@link warnDev}).
*/
warnMissingFormat(t, e, s) {
this.warnDev(`Not found '${e}' ${t} format in '${s}' locale. Falling back to default Intl options.`);
}
// --- Public methods (implemented in base class) ---

@@ -146,4 +250,4 @@ /**

this.touch();
const n = this.resolveLookup(t, r);
return n == null ? (this.warnMissing(t, r), s === void 0 ? t : s || t) : typeof n != "string" || !e ? n : v(n, e);
const a = this.resolveLookup(t, r);
return a == null ? (this.warnMissing(t, r), s === void 0 ? t : s || t) : typeof a != "string" || !e ? a : T(a, e);
}

@@ -161,19 +265,17 @@ /**

this.touch();
const { count: r, ...n } = typeof e == "number" ? { count: e } : e;
const { count: r, ...a } = typeof e == "number" ? { count: e } : e;
if (r === void 0)
return s ?? t;
const i = (u, h, l) => this.t(u, h, l);
return this.pluralFunc(t, Number.parseInt(r.toString(), 10), n, this.getLocale(), i) ?? s ?? t;
const n = (h, u, c) => this.t(h, u, c);
return this.pluralFunc(t, Number.parseInt(r.toString(), 10), a, this.getLocale(), n) ?? s ?? t;
}
/**
* Format number
*/
tn(t, e) {
return this.touch(), this.formatter.formatNumber(t, this.getLocale(), e);
tn(t, e, s, r) {
this.touch();
const a = this.resolveNumberFormatArgs(e, s, r);
return this.formatter.formatNumber(t, a.locale, a.options);
}
/**
* Format date
*/
td(t, e) {
return this.touch(), this.formatter.formatDate(t, this.getLocale(), e);
td(t, e, s, r) {
this.touch();
const a = this.resolveDateTimeFormatArgs(e, s, r);
return this.formatter.formatDate(t, a.locale, a.options);
}

@@ -193,7 +295,37 @@ /**

/**
* Clear cache
* Replace the value at `key` — a subtree, a string, a number, anything.
*
* `set` and not `merge`: `setTranslation('aaa', { fff: 'ggg' })` leaves `aaa` holding only
* `fff`, and `setTranslation('aaa', 'fff')` leaves a string where the subtree was. Use
* `mergeTranslations` when the existing siblings should survive.
*
* Writes to the active locale and route, so the change is visible to `t()` immediately and
* lives exactly as long as the chunk it belongs to.
*/
setTranslation(t, e) {
const s = this.getLocale(), r = this.getRoute(), a = this.helper.getCache(s, r) ?? {};
this.helper.setTranslations(s, v(a, String(t), e), r), this.onTranslationsChanged();
}
/**
* Clear translation + formatter caches
*/
clearCache() {
this.helper.clearCache();
this.helper.clearCache(), this.formatter.clearCache();
}
resolveNumberFormatArgs(t, e, s) {
if (typeof t != "string")
return { locale: this.getLocale(), options: t };
let r = this.getLocale(), a;
typeof e == "string" ? (r = e, a = s) : a = e;
const n = this.formatter.resolveNumberFormat(r, t);
return n || this.warnMissingFormat("number", t, r), !n && !a ? { locale: r, options: void 0 } : { locale: r, options: n ? { ...n, ...a } : a };
}
resolveDateTimeFormatArgs(t, e, s) {
if (typeof t != "string")
return { locale: this.getLocale(), options: t };
let r = this.getLocale(), a;
typeof e == "string" ? (r = e, a = s) : a = e;
const n = this.formatter.resolveDateTimeFormat(r, t);
return n || this.warnMissingFormat("datetime", t, r), !n && !a ? { locale: r, options: void 0 } : { locale: r, options: n ? { ...n, ...a } : a };
}
// --- Public methods (for subclasses to use) ---

@@ -215,18 +347,55 @@ /**

}
function L(o) {
let t = o.locale, e = o.fallbackLocale ?? o.locale, s = o.route ?? "index", r = 0;
const a = /* @__PURE__ */ new Set(), n = () => {
r++, a.forEach((i) => i());
};
return {
subscribe(i) {
return a.add(i), () => a.delete(i);
},
getSnapshot() {
return `${t}:${s}:${r}`;
},
getLocale() {
return t;
},
setLocale(i) {
t !== i && (t = i, n());
},
getFallbackLocale() {
return e;
},
setFallbackLocale(i) {
e !== i && (e = i, n());
},
getRoute() {
return s;
},
setRoute(i) {
s !== i && (s = i, n());
},
notify: n
};
}
export {
N as BaseI18n,
g as FormatService,
d as defaultPlural,
m as getByPath,
w as hasTranslationValue,
v as interpolate,
x as isNoPrefixStrategy,
S as isPrefixAndDefaultStrategy,
D as isPrefixExceptDefaultStrategy,
w as BaseI18n,
f as FormatService,
x as collectTranslationPaths,
L as createReactiveI18nStore,
b as defaultPlural,
d as getByPath,
y as hasTranslationValue,
T as interpolate,
R as isNoPrefixStrategy,
M as isPrefixAndDefaultStrategy,
$ as isPrefixExceptDefaultStrategy,
H as isPrefixStrategy,
L as mergeTranslationChunk,
f as resolveTranslation,
a as translationCacheKey,
T as useTranslationHelper,
M as withPrefixStrategy
P as mergeTranslationChunk,
F as mergeTranslationLayers,
g as resolveTranslation,
v as setTranslationAtKey,
l as translationCacheKey,
p as useTranslationHelper,
k as withPrefixStrategy
};
{
"name": "@i18n-micro/core",
"version": "1.3.4",
"version": "1.3.8",
"description": "Core utilities for translations, formatting, and locale routing in Nuxt I18n Micro.",

@@ -73,9 +73,9 @@ "keywords": [

"dependencies": {
"@i18n-micro/types": "1.2.6"
"@i18n-micro/types": "1.2.7"
},
"devDependencies": {
"publint": "^0.3.17",
"vite": "^7.3.1",
"vite": "^7.3.6",
"vite-plugin-dts": "^4.5.4",
"vitest": "^3.2.4"
"vitest": "^4.1.10"
},

@@ -88,6 +88,6 @@ "engines": {

"check:package": "publint",
"test": "jest",
"test:perf": "jest --config jest.perf.config.cjs",
"test": "vitest run",
"test:perf": "vitest run --config vitest.perf.config.ts",
"test:dist": "vitest run --config vitest.dist.config.ts"
}
}