@i18n-micro/core 1.3.11 → 1.3.14

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.
package/README.md CHANGED
@@ -16,6 +16,18 @@ or
16
16
  yarn add @i18n-micro/core
17
17
  ```
18
18
 
19
+ ### `BaseI18n.extend`
20
+
21
+ Attach framework-specific helpers onto any i18n instance (used by `@i18n-micro/vitepress` for path methods):
22
+
23
+ ```ts
24
+ i18n.extend({
25
+ localizePath(path: string, locale: string) {
26
+ /* … */
27
+ },
28
+ })
29
+ ```
30
+
19
31
  ## Usage
20
32
 
21
33
  This package provides several utilities for managing translations, formatting, and routing:
package/dist/base.d.ts CHANGED
@@ -161,4 +161,9 @@ export declare abstract class BaseI18n {
161
161
  * Subclasses can override addRouteTranslations to add reactivity
162
162
  */
163
163
  loadRouteTranslationsCore(locale: string, routeName: string, translations: Translations, merge: boolean): void;
164
+ /**
165
+ * Attach framework-specific helpers onto this instance (`localizePath`, …).
166
+ * Mutates `this` and returns it typed with the extra methods.
167
+ */
168
+ extend<M extends Record<string, unknown>>(methods: M & ThisType<this & M>): this & M;
164
169
  }
@@ -0,0 +1 @@
1
+ export { buildInspectorState, buildInspectorTree, countTranslationKeys, decodeInspectorPath, encodeInspectorPath, flattenTranslationNode, getByInspectorPath, parseInspectorNodeId, type BuildInspectorTreeOptions, type I18nDevtoolsInspectorNode, type I18nDevtoolsStateSnapshot, } from './devtools';
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const k={label:"Active",textColor:16777215,backgroundColor:4372611,tooltip:"Current locale and route context"},A="root",m="active",g="locale|",f="chunk|",i="key|",d=e=>e!==null&&typeof e=="object"&&!Array.isArray(e);function T(e){return typeof e=="string"?JSON.stringify(e):e===null?"null":e===void 0?"undefined":typeof e=="object"?Array.isArray(e)?`[Array(${e.length})]`:"{…}":String(e)}function h(e,t,n,o){return e===n&&t===o?[k]:void 0}function $(e,t){const n=`${t}:`,o=new Set;for(const c of e.translations.keys())c.startsWith(n)&&o.add(c.slice(n.length)||"index");return[...o].sort()}function _(e,t){const n=new Set(t.map(o=>o.code));for(const o of e.translations.keys()){const c=o.split(":")[0];c&&n.add(c)}return[...n].sort()}function b(e){return e.map(t=>encodeURIComponent(t)).join("/")}function v(e){return e?e.split("/").map(t=>decodeURIComponent(t)):[]}function N(e,t){let n=e;for(const o of t){if(!d(n)||!Object.prototype.hasOwnProperty.call(n,o))return;n=n[o]}return n}function C(e){if(!e||e===A)return{kind:"root"};if(e===m)return{kind:"active"};if(e.startsWith(g))return{kind:"locale",locale:e.slice(g.length)};if(e.startsWith(f)){const[t="",n="index"]=e.slice(f.length).split("|");return{kind:"chunk",locale:t,routeName:n}}if(e.startsWith(i)){const t=e.slice(i.length).split("|"),n=t[0]??"",o=t[1]??"index",c=t.slice(2).join("|");return{kind:"key",locale:n,routeName:o,path:c,segments:v(c)}}return{kind:"root"}}function y(e,t,n){return{...n,id:`${i}${e}|${t}|${n.id.slice(i.length)}`}}function u(e,t=[]){const n=t.length===0?e:N(e,t);return d(n)?Object.keys(n).filter(o=>o!=="__proto__").map(o=>{const c=[...t,o],r=n[o],a=d(r);return{id:`${i}${b(c)}`,label:a?o:`${o}: ${T(r)}`,children:a?[]:void 0}}).sort((o,c)=>o.label.localeCompare(c.label)):[]}function L(e){const t=C(e.nodeId),n=e.activeLocale,o=e.activeRouteName||"index";if(t.kind==="root"){const c=_(e.storage,e.configuredLocales),r=[{id:m,label:`Active (${n}:${o})`,tags:[k]}];for(const a of c){const l=e.configuredLocales.find(s=>s.code===a),p=$(e.storage,a);r.push({id:`${g}${a}`,label:l?.displayName?`${a} (${l.displayName})`:a,tags:a===n?[{...k,tooltip:"Active locale"}]:void 0});for(const s of p)r.push({id:`${f}${a}|${s}`,label:`${a}:${s}`,tags:h(a,s,n,o)})}return r}if(t.kind==="active")return u(e.activeTranslations??{}).map(c=>y(n,o,c));if(t.kind==="locale"&&t.locale){const c=t.locale;return $(e.storage,c).map(r=>({id:`${f}${c}|${r}`,label:r,children:[],tags:h(c,r,n,o)}))}if(t.kind==="chunk"&&t.locale){const c=t.locale,r=t.routeName||"index",a=e.storage.translations.get(`${c}:${r}`);return u(a??{}).map(l=>y(c,r,l))}if(t.kind==="key"&&t.locale){const c=t.locale,r=t.routeName||"index",a=e.storage.translations.get(`${c}:${r}`),l=t.segments??[],s=n===c&&o===r?e.activeTranslations??a??{}:a??{};return u(s,l).map(I=>y(c,r,I))}return[]}function P(e){return{Context:[{key:"locale",value:e.locale},{key:"routeName",value:e.routeName},{key:"strategy",value:e.strategy??"—"},{key:"defaultLocale",value:e.defaultLocale??"—"},{key:"fallbackLocale",value:e.fallbackLocale??"—"},{key:"cachedChunks",value:e.cachedChunks}],Locales:e.locales.map(t=>({key:t.code,value:t.displayName??t.code,editable:!1}))}}function x(e){if(!e||typeof e!="object")return 0;const t=new Set,n=(o,c="")=>{for(const r of Object.keys(o)){if(r==="__proto__")continue;const a=c?`${c}.${r}`:r;t.add(a);const l=o[r];d(l)&&n(l,a)}};return n(e),t.size}exports.buildInspectorState=P;exports.buildInspectorTree=L;exports.countTranslationKeys=x;exports.decodeInspectorPath=v;exports.encodeInspectorPath=b;exports.flattenTranslationNode=u;exports.getByInspectorPath=N;exports.parseInspectorNodeId=C;
@@ -0,0 +1,55 @@
1
+ import { Locale, Translations } from '@i18n-micro/types';
2
+ import { TranslationStorage } from './translation';
3
+ export interface I18nDevtoolsInspectorNode {
4
+ id: string;
5
+ label: string;
6
+ children?: I18nDevtoolsInspectorNode[];
7
+ tags?: Array<{
8
+ label: string;
9
+ textColor: number;
10
+ backgroundColor: number;
11
+ tooltip?: string;
12
+ }>;
13
+ }
14
+ export interface I18nDevtoolsStateSnapshot {
15
+ locale: string;
16
+ routeName: string;
17
+ strategy?: string;
18
+ defaultLocale?: string;
19
+ fallbackLocale?: string;
20
+ cachedChunks: number;
21
+ locales: Array<{
22
+ code: string;
23
+ displayName?: string;
24
+ disabled?: boolean;
25
+ }>;
26
+ }
27
+ export interface BuildInspectorTreeOptions {
28
+ nodeId: string;
29
+ storage: TranslationStorage;
30
+ configuredLocales: Locale[];
31
+ activeLocale: string;
32
+ activeRouteName: string;
33
+ activeTranslations?: Record<string, unknown>;
34
+ }
35
+ /**
36
+ * Encode path segments so a literal key `"a.b"` and nested path `a → b` get distinct node IDs.
37
+ */
38
+ export declare function encodeInspectorPath(segments: string[]): string;
39
+ export declare function decodeInspectorPath(encoded: string): string[];
40
+ export declare function getByInspectorPath(obj: Record<string, unknown>, segments: string[]): unknown;
41
+ export declare function parseInspectorNodeId(nodeId: string): {
42
+ kind: 'root' | 'active' | 'locale' | 'chunk' | 'key';
43
+ locale?: string;
44
+ routeName?: string;
45
+ path?: string;
46
+ segments?: string[];
47
+ };
48
+ export declare function flattenTranslationNode(obj: Record<string, unknown>, parentSegments?: string[]): I18nDevtoolsInspectorNode[];
49
+ export declare function buildInspectorTree(options: BuildInspectorTreeOptions): I18nDevtoolsInspectorNode[];
50
+ export declare function buildInspectorState(snapshot: I18nDevtoolsStateSnapshot): Record<string, Array<{
51
+ key: string;
52
+ value: unknown;
53
+ editable?: boolean;
54
+ }>>;
55
+ export declare function countTranslationKeys(translations: Translations | Record<string, unknown> | undefined): number;
@@ -0,0 +1,55 @@
1
+ import { Locale, Translations } from '@i18n-micro/types';
2
+ import { TranslationStorage } from './translation';
3
+ export interface I18nDevtoolsInspectorNode {
4
+ id: string;
5
+ label: string;
6
+ children?: I18nDevtoolsInspectorNode[];
7
+ tags?: Array<{
8
+ label: string;
9
+ textColor: number;
10
+ backgroundColor: number;
11
+ tooltip?: string;
12
+ }>;
13
+ }
14
+ export interface I18nDevtoolsStateSnapshot {
15
+ locale: string;
16
+ routeName: string;
17
+ strategy?: string;
18
+ defaultLocale?: string;
19
+ fallbackLocale?: string;
20
+ cachedChunks: number;
21
+ locales: Array<{
22
+ code: string;
23
+ displayName?: string;
24
+ disabled?: boolean;
25
+ }>;
26
+ }
27
+ export interface BuildInspectorTreeOptions {
28
+ nodeId: string;
29
+ storage: TranslationStorage;
30
+ configuredLocales: Locale[];
31
+ activeLocale: string;
32
+ activeRouteName: string;
33
+ activeTranslations?: Record<string, unknown>;
34
+ }
35
+ /**
36
+ * Encode path segments so a literal key `"a.b"` and nested path `a → b` get distinct node IDs.
37
+ */
38
+ export declare function encodeInspectorPath(segments: string[]): string;
39
+ export declare function decodeInspectorPath(encoded: string): string[];
40
+ export declare function getByInspectorPath(obj: Record<string, unknown>, segments: string[]): unknown;
41
+ export declare function parseInspectorNodeId(nodeId: string): {
42
+ kind: 'root' | 'active' | 'locale' | 'chunk' | 'key';
43
+ locale?: string;
44
+ routeName?: string;
45
+ path?: string;
46
+ segments?: string[];
47
+ };
48
+ export declare function flattenTranslationNode(obj: Record<string, unknown>, parentSegments?: string[]): I18nDevtoolsInspectorNode[];
49
+ export declare function buildInspectorTree(options: BuildInspectorTreeOptions): I18nDevtoolsInspectorNode[];
50
+ export declare function buildInspectorState(snapshot: I18nDevtoolsStateSnapshot): Record<string, Array<{
51
+ key: string;
52
+ value: unknown;
53
+ editable?: boolean;
54
+ }>>;
55
+ export declare function countTranslationKeys(translations: Translations | Record<string, unknown> | undefined): number;
@@ -0,0 +1,159 @@
1
+ const y = {
2
+ label: "Active",
3
+ textColor: 16777215,
4
+ backgroundColor: 4372611,
5
+ tooltip: "Current locale and route context"
6
+ }, b = "root", p = "active", g = "locale|", u = "chunk|", s = "key|", f = (e) => e !== null && typeof e == "object" && !Array.isArray(e);
7
+ function N(e) {
8
+ return typeof e == "string" ? JSON.stringify(e) : e === null ? "null" : e === void 0 ? "undefined" : typeof e == "object" ? Array.isArray(e) ? `[Array(${e.length})]` : "{…}" : String(e);
9
+ }
10
+ function m(e, t, n, o) {
11
+ return e === n && t === o ? [y] : void 0;
12
+ }
13
+ function h(e, t) {
14
+ const n = `${t}:`, o = /* @__PURE__ */ new Set();
15
+ for (const c of e.translations.keys())
16
+ c.startsWith(n) && o.add(c.slice(n.length) || "index");
17
+ return [...o].sort();
18
+ }
19
+ function C(e, t) {
20
+ const n = new Set(t.map((o) => o.code));
21
+ for (const o of e.translations.keys()) {
22
+ const c = o.split(":")[0];
23
+ c && n.add(c);
24
+ }
25
+ return [...n].sort();
26
+ }
27
+ function A(e) {
28
+ return e.map((t) => encodeURIComponent(t)).join("/");
29
+ }
30
+ function _(e) {
31
+ return e ? e.split("/").map((t) => decodeURIComponent(t)) : [];
32
+ }
33
+ function x(e, t) {
34
+ let n = e;
35
+ for (const o of t) {
36
+ if (!f(n) || !Object.prototype.hasOwnProperty.call(n, o)) return;
37
+ n = n[o];
38
+ }
39
+ return n;
40
+ }
41
+ function L(e) {
42
+ if (!e || e === b) return { kind: "root" };
43
+ if (e === p) return { kind: "active" };
44
+ if (e.startsWith(g))
45
+ return { kind: "locale", locale: e.slice(g.length) };
46
+ if (e.startsWith(u)) {
47
+ const [t = "", n = "index"] = e.slice(u.length).split("|");
48
+ return { kind: "chunk", locale: t, routeName: n };
49
+ }
50
+ if (e.startsWith(s)) {
51
+ const t = e.slice(s.length).split("|"), n = t[0] ?? "", o = t[1] ?? "index", c = t.slice(2).join("|");
52
+ return { kind: "key", locale: n, routeName: o, path: c, segments: _(c) };
53
+ }
54
+ return { kind: "root" };
55
+ }
56
+ function d(e, t, n) {
57
+ return {
58
+ ...n,
59
+ id: `${s}${e}|${t}|${n.id.slice(s.length)}`
60
+ };
61
+ }
62
+ function k(e, t = []) {
63
+ const n = t.length === 0 ? e : x(e, t);
64
+ return f(n) ? Object.keys(n).filter((o) => o !== "__proto__").map((o) => {
65
+ const c = [...t, o], r = n[o], a = f(r);
66
+ return {
67
+ id: `${s}${A(c)}`,
68
+ label: a ? o : `${o}: ${N(r)}`,
69
+ children: a ? [] : void 0
70
+ };
71
+ }).sort((o, c) => o.label.localeCompare(c.label)) : [];
72
+ }
73
+ function O(e) {
74
+ const t = L(e.nodeId), n = e.activeLocale, o = e.activeRouteName || "index";
75
+ if (t.kind === "root") {
76
+ const c = C(e.storage, e.configuredLocales), r = [
77
+ {
78
+ id: p,
79
+ label: `Active (${n}:${o})`,
80
+ tags: [y]
81
+ }
82
+ ];
83
+ for (const a of c) {
84
+ const l = e.configuredLocales.find((i) => i.code === a), $ = h(e.storage, a);
85
+ r.push({
86
+ id: `${g}${a}`,
87
+ label: l?.displayName ? `${a} (${l.displayName})` : a,
88
+ tags: a === n ? [{ ...y, tooltip: "Active locale" }] : void 0
89
+ });
90
+ for (const i of $)
91
+ r.push({
92
+ id: `${u}${a}|${i}`,
93
+ label: `${a}:${i}`,
94
+ tags: m(a, i, n, o)
95
+ });
96
+ }
97
+ return r;
98
+ }
99
+ if (t.kind === "active")
100
+ return k(e.activeTranslations ?? {}).map((c) => d(n, o, c));
101
+ if (t.kind === "locale" && t.locale) {
102
+ const c = t.locale;
103
+ return h(e.storage, c).map((r) => ({
104
+ id: `${u}${c}|${r}`,
105
+ label: r,
106
+ children: [],
107
+ tags: m(c, r, n, o)
108
+ }));
109
+ }
110
+ if (t.kind === "chunk" && t.locale) {
111
+ const c = t.locale, r = t.routeName || "index", a = e.storage.translations.get(`${c}:${r}`);
112
+ return k(a ?? {}).map((l) => d(c, r, l));
113
+ }
114
+ if (t.kind === "key" && t.locale) {
115
+ const c = t.locale, r = t.routeName || "index", a = e.storage.translations.get(`${c}:${r}`), l = t.segments ?? [], i = n === c && o === r ? e.activeTranslations ?? a ?? {} : a ?? {};
116
+ return k(i, l).map((v) => d(c, r, v));
117
+ }
118
+ return [];
119
+ }
120
+ function T(e) {
121
+ return {
122
+ Context: [
123
+ { key: "locale", value: e.locale },
124
+ { key: "routeName", value: e.routeName },
125
+ { key: "strategy", value: e.strategy ?? "—" },
126
+ { key: "defaultLocale", value: e.defaultLocale ?? "—" },
127
+ { key: "fallbackLocale", value: e.fallbackLocale ?? "—" },
128
+ { key: "cachedChunks", value: e.cachedChunks }
129
+ ],
130
+ Locales: e.locales.map((t) => ({
131
+ key: t.code,
132
+ value: t.displayName ?? t.code,
133
+ editable: !1
134
+ }))
135
+ };
136
+ }
137
+ function E(e) {
138
+ if (!e || typeof e != "object") return 0;
139
+ const t = /* @__PURE__ */ new Set(), n = (o, c = "") => {
140
+ for (const r of Object.keys(o)) {
141
+ if (r === "__proto__") continue;
142
+ const a = c ? `${c}.${r}` : r;
143
+ t.add(a);
144
+ const l = o[r];
145
+ f(l) && n(l, a);
146
+ }
147
+ };
148
+ return n(e), t.size;
149
+ }
150
+ export {
151
+ T as buildInspectorState,
152
+ O as buildInspectorTree,
153
+ E as countTranslationKeys,
154
+ _ as decodeInspectorPath,
155
+ A as encodeInspectorPath,
156
+ k as flattenTranslationNode,
157
+ x as getByInspectorPath,
158
+ L as parseInspectorNodeId
159
+ };
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "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:c,seconds:h}of o){const u=Math.floor(n/h);if(u>=1)return s.format(-u,c)}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&&t.plural!==i.defaultPlural?(a,r,s,n,o)=>t.plural(a,r,s,n,o)??i.defaultPlural(a,r,s,n,o):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=(c,h,u)=>this.t(c,h,u);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;
1
+ "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:c,seconds:h}of o){const u=Math.floor(n/h);if(u>=1)return s.format(-u,c)}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&&t.plural!==i.defaultPlural?(a,r,s,n,o)=>t.plural(a,r,s,n,o)??i.defaultPlural(a,r,s,n,o):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=(c,h,u)=>this.t(c,h,u);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)}extend(t){return Object.assign(this,t)}}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;
package/dist/index.mjs CHANGED
@@ -332,6 +332,13 @@ class w {
332
332
  loadRouteTranslationsCore(t, e, s, r) {
333
333
  r ? this.helper.mergeTranslation(t, e, s, !0) : this.helper.loadPageTranslations(t, e, s);
334
334
  }
335
+ /**
336
+ * Attach framework-specific helpers onto this instance (`localizePath`, …).
337
+ * Mutates `this` and returns it typed with the extra methods.
338
+ */
339
+ extend(t) {
340
+ return Object.assign(this, t);
341
+ }
335
342
  }
336
343
  function L(o) {
337
344
  let t = o.locale, e = o.fallbackLocale ?? o.locale, s = o.route ?? "index", r = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@i18n-micro/core",
3
- "version": "1.3.11",
3
+ "version": "1.3.14",
4
4
  "description": "Core utilities for translations, formatting, and locale routing in Nuxt I18n Micro.",
5
5
  "keywords": [
6
6
  "formatting",
@@ -64,13 +64,28 @@
64
64
  },
65
65
  "default": "./dist/helpers.mjs"
66
66
  },
67
+ "./devtools": {
68
+ "production": {
69
+ "types": "./dist/devtools.d.ts",
70
+ "default": "./dist/devtools.mjs"
71
+ },
72
+ "import": {
73
+ "types": "./dist/devtools.d.ts",
74
+ "default": "./dist/devtools.mjs"
75
+ },
76
+ "require": {
77
+ "types": "./dist/devtools.d.cts",
78
+ "default": "./dist/devtools.cjs"
79
+ },
80
+ "default": "./dist/devtools.mjs"
81
+ },
67
82
  "./package.json": "./package.json"
68
83
  },
69
84
  "publishConfig": {
70
85
  "access": "public"
71
86
  },
72
87
  "dependencies": {
73
- "@i18n-micro/types": "^1.2.10"
88
+ "@i18n-micro/types": "^1.2.11"
74
89
  },
75
90
  "devDependencies": {
76
91
  "publint": "^0.3.17",