@i18n-micro/utils 1.0.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.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +14 -0
  3. package/dist/accept-language.cjs +1 -0
  4. package/dist/accept-language.d.cts +3 -0
  5. package/dist/accept-language.d.ts +3 -0
  6. package/dist/accept-language.mjs +22 -0
  7. package/dist/active-locales.cjs +1 -0
  8. package/dist/active-locales.d.cts +4 -0
  9. package/dist/active-locales.d.ts +4 -0
  10. package/dist/active-locales.mjs +14 -0
  11. package/dist/build.cjs +1 -0
  12. package/dist/build.d.cts +14 -0
  13. package/dist/build.d.ts +14 -0
  14. package/dist/build.mjs +86 -0
  15. package/dist/cache-control.cjs +1 -0
  16. package/dist/cache-control.d.cts +33 -0
  17. package/dist/cache-control.d.ts +33 -0
  18. package/dist/cache-control.mjs +56 -0
  19. package/dist/cookie.cjs +1 -0
  20. package/dist/cookie.d.cts +24 -0
  21. package/dist/cookie.d.ts +24 -0
  22. package/dist/cookie.mjs +25 -0
  23. package/dist/deep-merge.cjs +1 -0
  24. package/dist/deep-merge.d.cts +17 -0
  25. package/dist/deep-merge.d.ts +17 -0
  26. package/dist/deep-merge.mjs +23 -0
  27. package/dist/merge-source.cjs +1 -0
  28. package/dist/merge-source.d.cts +22 -0
  29. package/dist/merge-source.d.ts +22 -0
  30. package/dist/merge-source.mjs +51 -0
  31. package/dist/parse-path.cjs +1 -0
  32. package/dist/parse-path.d.cts +35 -0
  33. package/dist/parse-path.d.ts +35 -0
  34. package/dist/parse-path.mjs +41 -0
  35. package/dist/payload-config.cjs +1 -0
  36. package/dist/payload-config.d.cts +35 -0
  37. package/dist/payload-config.d.ts +35 -0
  38. package/dist/payload-config.mjs +59 -0
  39. package/dist/payload-fetch.cjs +1 -0
  40. package/dist/payload-fetch.d.cts +11 -0
  41. package/dist/payload-fetch.d.ts +11 -0
  42. package/dist/payload-fetch.mjs +28 -0
  43. package/dist/payload-stats.cjs +1 -0
  44. package/dist/payload-stats.d.cts +2 -0
  45. package/dist/payload-stats.d.ts +2 -0
  46. package/dist/payload-stats.mjs +19 -0
  47. package/dist/payload-url.cjs +1 -0
  48. package/dist/payload-url.d.cts +24 -0
  49. package/dist/payload-url.d.ts +24 -0
  50. package/dist/payload-url.mjs +24 -0
  51. package/dist/resolve-locale.cjs +1 -0
  52. package/dist/resolve-locale.d.cts +21 -0
  53. package/dist/resolve-locale.d.ts +21 -0
  54. package/dist/resolve-locale.mjs +15 -0
  55. package/dist/route-pattern.cjs +1 -0
  56. package/dist/route-pattern.d.cts +11 -0
  57. package/dist/route-pattern.d.ts +11 -0
  58. package/dist/route-pattern.mjs +20 -0
  59. package/dist/route.cjs +1 -0
  60. package/dist/route.d.cts +9 -0
  61. package/dist/route.d.ts +9 -0
  62. package/dist/route.mjs +38 -0
  63. package/dist/runtime-config.cjs +1 -0
  64. package/dist/runtime-config.d.cts +8 -0
  65. package/dist/runtime-config.d.ts +8 -0
  66. package/dist/runtime-config.mjs +69 -0
  67. package/dist/source-loader.cjs +1 -0
  68. package/dist/source-loader.d.cts +6 -0
  69. package/dist/source-loader.d.ts +6 -0
  70. package/dist/source-loader.mjs +16 -0
  71. package/package.json +246 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,14 @@
1
+ # @i18n-micro/utils
2
+
3
+ Framework-agnostic utilities for Nuxt I18n Micro. Import only what you need:
4
+
5
+ ```ts
6
+ import { deepMergeTranslations } from '@i18n-micro/utils/deep-merge'
7
+ import { mergeSourceTranslations } from '@i18n-micro/utils/merge-source'
8
+ import { findAllowedLocalesForRoute } from '@i18n-micro/utils/route'
9
+ import { extractBaseRoutePattern } from '@i18n-micro/utils/route-pattern'
10
+ import { resolveI18nConfigWithRuntimeOverrides } from '@i18n-micro/utils/runtime-config'
11
+ import { preMergeLocales } from '@i18n-micro/utils/build'
12
+ ```
13
+
14
+ No Vue, Nuxt, or Nitro dependencies. `sideEffects: false` for tree-shaking friendly bundlers.
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function c(e){return e?e.split(",").map(t=>{const[n]=t.split(";");return(n??"").trim()}).filter(t=>t.length>0):[]}function g(e,t){const n=c(e);for(const r of n){const a=r.toLowerCase(),s=a.split("-")[0],o=t.find(u=>u.toLowerCase()===a||u.toLowerCase()===s);if(o)return o}return null}function i(e,t,n,r,a){return!n||t?e:g(r,a)??e}exports.applyAutoDetectLanguage=i;exports.detectLocaleFromAcceptLanguage=g;exports.parseAcceptLanguage=c;
@@ -0,0 +1,3 @@
1
+ export declare function parseAcceptLanguage(header: string | undefined): string[];
2
+ export declare function detectLocaleFromAcceptLanguage(header: string | undefined, validLocales: string[]): string | null;
3
+ export declare function applyAutoDetectLanguage(locale: string, hasExplicitPreference: boolean, autoDetectLanguage: boolean | undefined, acceptLanguageHeader: string | undefined, validLocales: string[]): string;
@@ -0,0 +1,3 @@
1
+ export declare function parseAcceptLanguage(header: string | undefined): string[];
2
+ export declare function detectLocaleFromAcceptLanguage(header: string | undefined, validLocales: string[]): string | null;
3
+ export declare function applyAutoDetectLanguage(locale: string, hasExplicitPreference: boolean, autoDetectLanguage: boolean | undefined, acceptLanguageHeader: string | undefined, validLocales: string[]): string;
@@ -0,0 +1,22 @@
1
+ function s(t) {
2
+ return t ? t.split(",").map((n) => {
3
+ const [e] = n.split(";");
4
+ return (e ?? "").trim();
5
+ }).filter((n) => n.length > 0) : [];
6
+ }
7
+ function g(t, n) {
8
+ const e = s(t);
9
+ for (const o of e) {
10
+ const r = o.toLowerCase(), c = r.split("-")[0], a = n.find((u) => u.toLowerCase() === r || u.toLowerCase() === c);
11
+ if (a) return a;
12
+ }
13
+ return null;
14
+ }
15
+ function i(t, n, e, o, r) {
16
+ return !e || n ? t : g(o, r) ?? t;
17
+ }
18
+ export {
19
+ i as applyAutoDetectLanguage,
20
+ g as detectLocaleFromAcceptLanguage,
21
+ s as parseAcceptLanguage
22
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function l(e){return(e??[]).filter(o=>!o.disabled)}function t(e){return l(e).map(o=>o.code)}function a(e,o){return l(e).some(n=>n.code===o)}exports.getEnabledLocaleCodes=t;exports.getEnabledLocales=l;exports.isEnabledLocale=a;
@@ -0,0 +1,4 @@
1
+ import { Locale } from '@i18n-micro/types';
2
+ export declare function getEnabledLocales(locales?: Locale[] | null): Locale[];
3
+ export declare function getEnabledLocaleCodes(locales?: Locale[] | null): string[];
4
+ export declare function isEnabledLocale(locales: Locale[] | null | undefined, code: string): boolean;
@@ -0,0 +1,4 @@
1
+ import { Locale } from '@i18n-micro/types';
2
+ export declare function getEnabledLocales(locales?: Locale[] | null): Locale[];
3
+ export declare function getEnabledLocaleCodes(locales?: Locale[] | null): string[];
4
+ export declare function isEnabledLocale(locales: Locale[] | null | undefined, code: string): boolean;
@@ -0,0 +1,14 @@
1
+ function o(e) {
2
+ return (e ?? []).filter((n) => !n.disabled);
3
+ }
4
+ function a(e) {
5
+ return o(e).map((n) => n.code);
6
+ }
7
+ function c(e, n) {
8
+ return o(e).some((t) => t.code === n);
9
+ }
10
+ export {
11
+ a as getEnabledLocaleCodes,
12
+ o as getEnabledLocales,
13
+ c as isEnabledLocale
14
+ };
package/dist/build.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("node:fs"),i=require("node:path"),b=require("globby"),M=require("./deep-merge.cjs");async function x(h,w,c,p,S,r){t.existsSync(c)&&t.rmSync(c,{recursive:!0,force:!0}),t.mkdirSync(c,{recursive:!0});const f=h.map(e=>i.join(e,w)),d=new Set;for(const e of f){if(!t.existsSync(e))continue;(await b.globby("**/*.json",{cwd:e})).forEach(n=>d.add(n))}const u=new Map;for(const e of d){let o={};for(const n of f){const s=i.join(n,e);if(t.existsSync(s))try{o=M.deepMergeTranslationsRecursive(o,JSON.parse(t.readFileSync(s,"utf-8")))}catch{}}u.set(e,o)}const y=new Map,l=new Map;for(const[e,o]of u){const n=i.dirname(e),s=e.slice(e.lastIndexOf("/")+1).replace(".json","");n==="."?y.set(s,o):(l.has(n)||l.set(n,new Map),l.get(n).set(s,o))}const j=new Set(p.map(e=>e.code)),m=e=>{for(const o of p){const n=[S,o.fallbackLocale,o.code].filter(a=>!!a&&j.has(a)).filter((a,g,v)=>v.indexOf(a)===g);if(n.length<=1)continue;let s={};for(const a of n){const g=e.get(a);g&&(s=M.deepMergeTranslationsRecursive(s,g))}e.set(o.code,s)}};m(y);for(const e of l.values())m(e);if(r||l.size===0){const e=new Map;for(const[o,n]of y)e.set(o,{...n});l.set("pages/index",e)}else for(const[,e]of l)for(const[o,n]of y){const s=e.get(o);e.set(o,s?M.deepMergeTranslations(n,s):{...n})}for(const[e,o]of l)for(const[n,s]of o){const a=i.join(c,e,`${n}.json`);t.mkdirSync(i.dirname(a),{recursive:!0}),t.writeFileSync(a,JSON.stringify(s))}}async function P(h,w,c){t.existsSync(c)&&t.rmSync(c,{recursive:!0,force:!0}),t.mkdirSync(c,{recursive:!0});const p=h.map(r=>i.join(r,w)),S=new Set;for(const r of p){if(!t.existsSync(r))continue;(await b.globby("**/*.json",{cwd:r})).forEach(d=>S.add(d))}for(const r of S){let f={};for(const u of p){const y=i.join(u,r);if(t.existsSync(y))try{f=M.deepMergeTranslationsRecursive(f,JSON.parse(t.readFileSync(y,"utf-8")))}catch{}}const d=i.join(c,r);t.mkdirSync(i.dirname(d),{recursive:!0}),t.writeFileSync(d,JSON.stringify(f))}}exports.buildTranslationSourceLayers=P;exports.preMergeLocales=x;
@@ -0,0 +1,14 @@
1
+ export interface PreMergeLocaleInfo {
2
+ code: string;
3
+ fallbackLocale?: string;
4
+ }
5
+ /**
6
+ * Pre-merge all translation files at build time.
7
+ *
8
+ * Output: flat directory with structure pages/{routeName}/{locale}.json
9
+ */
10
+ export declare function preMergeLocales(rootDirs: string[], translationDirName: string, outputDir: string, locales: PreMergeLocaleInfo[], globalFallbackLocale?: string, disablePageLocales?: boolean): Promise<void>;
11
+ /**
12
+ * Merge translation layers at build time but keep the source directory shape.
13
+ */
14
+ export declare function buildTranslationSourceLayers(rootDirs: string[], translationDirName: string, outputDir: string): Promise<void>;
@@ -0,0 +1,14 @@
1
+ export interface PreMergeLocaleInfo {
2
+ code: string;
3
+ fallbackLocale?: string;
4
+ }
5
+ /**
6
+ * Pre-merge all translation files at build time.
7
+ *
8
+ * Output: flat directory with structure pages/{routeName}/{locale}.json
9
+ */
10
+ export declare function preMergeLocales(rootDirs: string[], translationDirName: string, outputDir: string, locales: PreMergeLocaleInfo[], globalFallbackLocale?: string, disablePageLocales?: boolean): Promise<void>;
11
+ /**
12
+ * Merge translation layers at build time but keep the source directory shape.
13
+ */
14
+ export declare function buildTranslationSourceLayers(rootDirs: string[], translationDirName: string, outputDir: string): Promise<void>;
package/dist/build.mjs ADDED
@@ -0,0 +1,86 @@
1
+ import P, { existsSync as d, mkdirSync as u, readFileSync as O, writeFileSync as b } from "node:fs";
2
+ import { join as p, dirname as S } from "node:path";
3
+ import { globby as j } from "globby";
4
+ import { deepMergeTranslationsRecursive as v, deepMergeTranslations as J } from "./deep-merge.mjs";
5
+ async function z(w, M, c, y, g, s) {
6
+ d(c) && P.rmSync(c, { recursive: !0, force: !0 }), u(c, { recursive: !0 });
7
+ const f = w.map((e) => p(e, M)), l = /* @__PURE__ */ new Set();
8
+ for (const e of f) {
9
+ if (!d(e)) continue;
10
+ (await j("**/*.json", { cwd: e })).forEach((t) => l.add(t));
11
+ }
12
+ const h = /* @__PURE__ */ new Map();
13
+ for (const e of l) {
14
+ let o = {};
15
+ for (const t of f) {
16
+ const n = p(t, e);
17
+ if (d(n))
18
+ try {
19
+ o = v(o, JSON.parse(O(n, "utf-8")));
20
+ } catch {
21
+ }
22
+ }
23
+ h.set(e, o);
24
+ }
25
+ const i = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map();
26
+ for (const [e, o] of h) {
27
+ const t = S(e), n = e.slice(e.lastIndexOf("/") + 1).replace(".json", "");
28
+ t === "." ? i.set(n, o) : (r.has(t) || r.set(t, /* @__PURE__ */ new Map()), r.get(t).set(n, o));
29
+ }
30
+ const F = new Set(y.map((e) => e.code)), x = (e) => {
31
+ for (const o of y) {
32
+ const t = [g, o.fallbackLocale, o.code].filter((a) => !!a && F.has(a)).filter((a, m, k) => k.indexOf(a) === m);
33
+ if (t.length <= 1) continue;
34
+ let n = {};
35
+ for (const a of t) {
36
+ const m = e.get(a);
37
+ m && (n = v(n, m));
38
+ }
39
+ e.set(o.code, n);
40
+ }
41
+ };
42
+ x(i);
43
+ for (const e of r.values())
44
+ x(e);
45
+ if (s || r.size === 0) {
46
+ const e = /* @__PURE__ */ new Map();
47
+ for (const [o, t] of i)
48
+ e.set(o, { ...t });
49
+ r.set("pages/index", e);
50
+ } else
51
+ for (const [, e] of r)
52
+ for (const [o, t] of i) {
53
+ const n = e.get(o);
54
+ e.set(o, n ? J(t, n) : { ...t });
55
+ }
56
+ for (const [e, o] of r)
57
+ for (const [t, n] of o) {
58
+ const a = p(c, e, `${t}.json`);
59
+ u(S(a), { recursive: !0 }), b(a, JSON.stringify(n));
60
+ }
61
+ }
62
+ async function C(w, M, c) {
63
+ d(c) && P.rmSync(c, { recursive: !0, force: !0 }), u(c, { recursive: !0 });
64
+ const y = w.map((s) => p(s, M)), g = /* @__PURE__ */ new Set();
65
+ for (const s of y) {
66
+ if (!d(s)) continue;
67
+ (await j("**/*.json", { cwd: s })).forEach((l) => g.add(l));
68
+ }
69
+ for (const s of g) {
70
+ let f = {};
71
+ for (const h of y) {
72
+ const i = p(h, s);
73
+ if (d(i))
74
+ try {
75
+ f = v(f, JSON.parse(O(i, "utf-8")));
76
+ } catch {
77
+ }
78
+ }
79
+ const l = p(c, s);
80
+ u(S(l), { recursive: !0 }), b(l, JSON.stringify(f));
81
+ }
82
+ }
83
+ export {
84
+ C as buildTranslationSourceLayers,
85
+ z as preMergeLocales
86
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class s{constructor(t){this.cache=new Map,this.expiry=new Map,this.maxSize=0,this.ttlMs=0,t&&this.configure(t)}configure(t){this.maxSize=t.maxSize??0,this.ttlMs=(t.ttl??0)*1e3,this.ttlMs===0&&this.expiry.clear()}get(t){const e=this.cache.get(t);if(e!==void 0){if(this.ttlMs>0){const i=this.expiry.get(t);if(i&&Date.now()>i){this.delete(t);return}this.expiry.set(t,Date.now()+this.ttlMs)}return this.cache.delete(t),this.cache.set(t,e),e}}has(t){if(!this.cache.has(t))return!1;if(this.ttlMs>0){const e=this.expiry.get(t);if(e&&Date.now()>e)return this.delete(t),!1}return!0}set(t,e){if(this.cache.has(t))this.cache.delete(t);else if(this.maxSize>0&&this.cache.size>=this.maxSize){const i=this.cache.keys().next().value;i!==void 0&&this.delete(i)}this.cache.set(t,e),this.ttlMs>0&&this.expiry.set(t,Date.now()+this.ttlMs)}delete(t){return this.expiry.delete(t),this.cache.delete(t)}clear(){this.cache.clear(),this.expiry.clear()}keys(){return this.cache.keys()}get size(){return this.cache.size}}exports.CacheControl=s;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * CacheControl — O(1) LRU cache with optional sliding TTL.
3
+ *
4
+ * Map is created internally — no external references, no desync risk.
5
+ *
6
+ * Performance:
7
+ * get — O(1) (lazy TTL check + LRU reorder via Map delete/set)
8
+ * set — O(1) (LRU eviction via Map.keys().next())
9
+ * has — O(1) (lazy TTL eviction)
10
+ *
11
+ * Eviction: LRU (Least Recently Used) based on native Map insertion order.
12
+ */
13
+ export interface CacheControlOptions {
14
+ maxSize?: number;
15
+ /** TTL in seconds (0 = no expiration) */
16
+ ttl?: number;
17
+ }
18
+ export declare class CacheControl<T> {
19
+ private readonly cache;
20
+ private readonly expiry;
21
+ private maxSize;
22
+ private ttlMs;
23
+ constructor(options?: CacheControlOptions);
24
+ /** Update limits at runtime. Last call wins. */
25
+ configure(options: CacheControlOptions): void;
26
+ get(key: string): T | undefined;
27
+ has(key: string): boolean;
28
+ set(key: string, value: T): void;
29
+ delete(key: string): boolean;
30
+ clear(): void;
31
+ keys(): IterableIterator<string>;
32
+ get size(): number;
33
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * CacheControl — O(1) LRU cache with optional sliding TTL.
3
+ *
4
+ * Map is created internally — no external references, no desync risk.
5
+ *
6
+ * Performance:
7
+ * get — O(1) (lazy TTL check + LRU reorder via Map delete/set)
8
+ * set — O(1) (LRU eviction via Map.keys().next())
9
+ * has — O(1) (lazy TTL eviction)
10
+ *
11
+ * Eviction: LRU (Least Recently Used) based on native Map insertion order.
12
+ */
13
+ export interface CacheControlOptions {
14
+ maxSize?: number;
15
+ /** TTL in seconds (0 = no expiration) */
16
+ ttl?: number;
17
+ }
18
+ export declare class CacheControl<T> {
19
+ private readonly cache;
20
+ private readonly expiry;
21
+ private maxSize;
22
+ private ttlMs;
23
+ constructor(options?: CacheControlOptions);
24
+ /** Update limits at runtime. Last call wins. */
25
+ configure(options: CacheControlOptions): void;
26
+ get(key: string): T | undefined;
27
+ has(key: string): boolean;
28
+ set(key: string, value: T): void;
29
+ delete(key: string): boolean;
30
+ clear(): void;
31
+ keys(): IterableIterator<string>;
32
+ get size(): number;
33
+ }
@@ -0,0 +1,56 @@
1
+ class h {
2
+ constructor(t) {
3
+ this.cache = /* @__PURE__ */ new Map(), this.expiry = /* @__PURE__ */ new Map(), this.maxSize = 0, this.ttlMs = 0, t && this.configure(t);
4
+ }
5
+ /** Update limits at runtime. Last call wins. */
6
+ configure(t) {
7
+ this.maxSize = t.maxSize ?? 0, this.ttlMs = (t.ttl ?? 0) * 1e3, this.ttlMs === 0 && this.expiry.clear();
8
+ }
9
+ get(t) {
10
+ const e = this.cache.get(t);
11
+ if (e !== void 0) {
12
+ if (this.ttlMs > 0) {
13
+ const i = this.expiry.get(t);
14
+ if (i && Date.now() > i) {
15
+ this.delete(t);
16
+ return;
17
+ }
18
+ this.expiry.set(t, Date.now() + this.ttlMs);
19
+ }
20
+ return this.cache.delete(t), this.cache.set(t, e), e;
21
+ }
22
+ }
23
+ has(t) {
24
+ if (!this.cache.has(t)) return !1;
25
+ if (this.ttlMs > 0) {
26
+ const e = this.expiry.get(t);
27
+ if (e && Date.now() > e)
28
+ return this.delete(t), !1;
29
+ }
30
+ return !0;
31
+ }
32
+ set(t, e) {
33
+ if (this.cache.has(t))
34
+ this.cache.delete(t);
35
+ else if (this.maxSize > 0 && this.cache.size >= this.maxSize) {
36
+ const i = this.cache.keys().next().value;
37
+ i !== void 0 && this.delete(i);
38
+ }
39
+ this.cache.set(t, e), this.ttlMs > 0 && this.expiry.set(t, Date.now() + this.ttlMs);
40
+ }
41
+ delete(t) {
42
+ return this.expiry.delete(t), this.cache.delete(t);
43
+ }
44
+ clear() {
45
+ this.cache.clear(), this.expiry.clear();
46
+ }
47
+ keys() {
48
+ return this.cache.keys();
49
+ }
50
+ get size() {
51
+ return this.cache.size;
52
+ }
53
+ }
54
+ export {
55
+ h as CacheControl
56
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t="user-locale",a="hash-locale",o=3600*24*365;function l(e){return e.localeCookie===null?null:e.localeCookie||t}function n(e){return e.hashMode?a:null}function i(){const e=new Date;return e.setTime(e.getTime()+o*1e3),{expires:e,maxAge:o,path:"/",watch:!0,sameSite:"lax"}}exports.DEFAULT_COOKIE_MAX_AGE=o;exports.DEFAULT_COOKIE_NAME=t;exports.DEFAULT_HASH_COOKIE_NAME=a;exports.getHashCookieName=n;exports.getLocaleCookieName=l;exports.getLocaleCookieOptions=i;
@@ -0,0 +1,24 @@
1
+ import { ModuleOptionsExtend } from '@i18n-micro/types';
2
+ export declare const DEFAULT_COOKIE_NAME = "user-locale";
3
+ export declare const DEFAULT_HASH_COOKIE_NAME = "hash-locale";
4
+ export declare const DEFAULT_COOKIE_MAX_AGE: number;
5
+ /**
6
+ * Returns cookie name from config.
7
+ * If localeCookie === null, returns null (cookies disabled).
8
+ */
9
+ export declare function getLocaleCookieName(config: ModuleOptionsExtend): string | null;
10
+ /**
11
+ * Returns hash cookie name when hashMode is enabled.
12
+ * Returns null when hashMode is false.
13
+ */
14
+ export declare function getHashCookieName(config: ModuleOptionsExtend): string | null;
15
+ /**
16
+ * Returns standard options for locale/hash cookies.
17
+ */
18
+ export declare function getLocaleCookieOptions(): {
19
+ expires: Date;
20
+ maxAge: number;
21
+ path: string;
22
+ watch: boolean;
23
+ sameSite: "lax";
24
+ };
@@ -0,0 +1,24 @@
1
+ import { ModuleOptionsExtend } from '@i18n-micro/types';
2
+ export declare const DEFAULT_COOKIE_NAME = "user-locale";
3
+ export declare const DEFAULT_HASH_COOKIE_NAME = "hash-locale";
4
+ export declare const DEFAULT_COOKIE_MAX_AGE: number;
5
+ /**
6
+ * Returns cookie name from config.
7
+ * If localeCookie === null, returns null (cookies disabled).
8
+ */
9
+ export declare function getLocaleCookieName(config: ModuleOptionsExtend): string | null;
10
+ /**
11
+ * Returns hash cookie name when hashMode is enabled.
12
+ * Returns null when hashMode is false.
13
+ */
14
+ export declare function getHashCookieName(config: ModuleOptionsExtend): string | null;
15
+ /**
16
+ * Returns standard options for locale/hash cookies.
17
+ */
18
+ export declare function getLocaleCookieOptions(): {
19
+ expires: Date;
20
+ maxAge: number;
21
+ path: string;
22
+ watch: boolean;
23
+ sameSite: "lax";
24
+ };
@@ -0,0 +1,25 @@
1
+ const o = "user-locale", t = "hash-locale", n = 31536e3;
2
+ function a(e) {
3
+ return e.localeCookie === null ? null : e.localeCookie || o;
4
+ }
5
+ function l(e) {
6
+ return e.hashMode ? t : null;
7
+ }
8
+ function A() {
9
+ const e = /* @__PURE__ */ new Date();
10
+ return e.setTime(e.getTime() + 31536e3 * 1e3), {
11
+ expires: e,
12
+ maxAge: 31536e3,
13
+ path: "/",
14
+ watch: !0,
15
+ sameSite: "lax"
16
+ };
17
+ }
18
+ export {
19
+ n as DEFAULT_COOKIE_MAX_AGE,
20
+ o as DEFAULT_COOKIE_NAME,
21
+ t as DEFAULT_HASH_COOKIE_NAME,
22
+ l as getHashCookieName,
23
+ a as getLocaleCookieName,
24
+ A as getLocaleCookieOptions
25
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function i(s,o){const t={...s};for(const e in o){if(e==="__proto__"||e==="constructor")continue;const r=o[e],n=t[e];r!==null&&typeof r=="object"&&!Array.isArray(r)&&n!==null&&typeof n=="object"&&!Array.isArray(n)?t[e]={...n,...r}:t[e]=r}return t}function c(s,o){if(!s||Object.keys(s).length===0)return{...o};const t={...s};for(const e in o){if(e==="__proto__"||e==="constructor")continue;const r=o[e],n=t[e];r&&typeof r=="object"&&!Array.isArray(r)&&n&&typeof n=="object"&&!Array.isArray(n)?t[e]=c(n,r):t[e]=r}return t}exports.deepMergeTranslations=i;exports.deepMergeTranslationsRecursive=c;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Optimized deep merge for translation objects (2-level depth).
3
+ *
4
+ * Regular shallow spread `{ ...old, ...new }` overwrites nested objects entirely:
5
+ * { common: { fromA: "A" } } + { common: { fromB: "B" } } => { common: { fromB: "B" } }
6
+ *
7
+ * This function preserves sibling keys inside nested objects:
8
+ * { common: { fromA: "A" } } + { common: { fromB: "B" } } => { common: { fromA: "A", fromB: "B" } }
9
+ *
10
+ * Performance: only iterates top-level keys of `source`; inner merge is a single spread.
11
+ *
12
+ * Limitation: only merges 2 levels deep. At level 3+, source overwrites target.
13
+ * For 99% of i18n files (Section → Key → Value), this is sufficient.
14
+ */
15
+ export declare function deepMergeTranslations(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown>;
16
+ /** Recursive deep merge for build-time layer merging. */
17
+ export declare function deepMergeTranslationsRecursive(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown>;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Optimized deep merge for translation objects (2-level depth).
3
+ *
4
+ * Regular shallow spread `{ ...old, ...new }` overwrites nested objects entirely:
5
+ * { common: { fromA: "A" } } + { common: { fromB: "B" } } => { common: { fromB: "B" } }
6
+ *
7
+ * This function preserves sibling keys inside nested objects:
8
+ * { common: { fromA: "A" } } + { common: { fromB: "B" } } => { common: { fromA: "A", fromB: "B" } }
9
+ *
10
+ * Performance: only iterates top-level keys of `source`; inner merge is a single spread.
11
+ *
12
+ * Limitation: only merges 2 levels deep. At level 3+, source overwrites target.
13
+ * For 99% of i18n files (Section → Key → Value), this is sufficient.
14
+ */
15
+ export declare function deepMergeTranslations(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown>;
16
+ /** Recursive deep merge for build-time layer merging. */
17
+ export declare function deepMergeTranslationsRecursive(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown>;
@@ -0,0 +1,23 @@
1
+ function i(s, e) {
2
+ const o = { ...s };
3
+ for (const t in e) {
4
+ if (t === "__proto__" || t === "constructor") continue;
5
+ const r = e[t], n = o[t];
6
+ r !== null && typeof r == "object" && !Array.isArray(r) && n !== null && typeof n == "object" && !Array.isArray(n) ? o[t] = { ...n, ...r } : o[t] = r;
7
+ }
8
+ return o;
9
+ }
10
+ function c(s, e) {
11
+ if (!s || Object.keys(s).length === 0) return { ...e };
12
+ const o = { ...s };
13
+ for (const t in e) {
14
+ if (t === "__proto__" || t === "constructor") continue;
15
+ const r = e[t], n = o[t];
16
+ r && typeof r == "object" && !Array.isArray(r) && n && typeof n == "object" && !Array.isArray(n) ? o[t] = c(n, r) : o[t] = r;
17
+ }
18
+ return o;
19
+ }
20
+ export {
21
+ i as deepMergeTranslations,
22
+ c as deepMergeTranslationsRecursive
23
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("./deep-merge.cjs");function i(e,a,r){const n=new Set(a.map(o=>o.code)),l=a.find(o=>o.code===e);return[r,l?.fallbackLocale,e].filter(o=>!!o&&n.has(o)).filter((o,g,f)=>f.indexOf(o)===g)}function b(e,a,r){let n={};for(const l of e)n=c.deepMergeTranslations(n,a(r(l)));return n}async function t(e,a,r){let n={};for(const l of e){const o=await a(r(l));n=c.deepMergeTranslations(n,o)}return n}function s(e,a){return a?"index":e||"index"}function u(e){return`${e}.json`}function d(e,a){return`pages/${s(e)}/${a}.json`}function m(e){return`assets:i18n:${e.replace(/\//g,":")}`}async function S(e){const a=s(e.pageName,e.disablePageLocales),r=i(e.locale,e.locales,e.globalFallbackLocale),n=await t(r,e.readLocaleFile,u),l=await t(r,e.readLocaleFile,o=>d(a,o));return c.deepMergeTranslations(n,l)}function F(e){return(e??[]).map(a=>typeof a=="string"?{code:a}:{code:a.code,fallbackLocale:a.fallbackLocale})}exports.buildFallbackLocaleChain=i;exports.buildSourcePagePath=d;exports.buildSourceRootPath=u;exports.mergeSourceTranslations=S;exports.mergeTranslationsFromFallbackChain=b;exports.mergeTranslationsFromFallbackChainAsync=t;exports.normalizeConfiguredLocales=F;exports.resolveSourcePageName=s;exports.toSourceStorageKey=m;
@@ -0,0 +1,22 @@
1
+ import { Locale } from '@i18n-micro/types';
2
+ export interface SourceLocaleInfo {
3
+ code: string;
4
+ fallbackLocale?: string;
5
+ }
6
+ export interface MergeSourceTranslationsInput {
7
+ locale: string;
8
+ pageName: string;
9
+ locales: SourceLocaleInfo[];
10
+ globalFallbackLocale?: string;
11
+ disablePageLocales?: boolean;
12
+ readLocaleFile: (relativePath: string) => Record<string, unknown> | Promise<Record<string, unknown>>;
13
+ }
14
+ export declare function buildFallbackLocaleChain(locale: string, locales: SourceLocaleInfo[], globalFallbackLocale?: string): string[];
15
+ export declare function mergeTranslationsFromFallbackChain(chain: string[], readLocaleFile: (relativePath: string) => Record<string, unknown>, relativePathForLocale: (localeCode: string) => string): Record<string, unknown>;
16
+ export declare function mergeTranslationsFromFallbackChainAsync(chain: string[], readLocaleFile: (relativePath: string) => Record<string, unknown> | Promise<Record<string, unknown>>, relativePathForLocale: (localeCode: string) => string): Promise<Record<string, unknown>>;
17
+ export declare function resolveSourcePageName(pageName: string, disablePageLocales?: boolean): string;
18
+ export declare function buildSourceRootPath(localeCode: string): string;
19
+ export declare function buildSourcePagePath(pageName: string, localeCode: string): string;
20
+ export declare function toSourceStorageKey(relativePath: string): string;
21
+ export declare function mergeSourceTranslations(input: MergeSourceTranslationsInput): Promise<Record<string, unknown>>;
22
+ export declare function normalizeConfiguredLocales(locales: Array<string | Locale> | undefined): SourceLocaleInfo[];
@@ -0,0 +1,22 @@
1
+ import { Locale } from '@i18n-micro/types';
2
+ export interface SourceLocaleInfo {
3
+ code: string;
4
+ fallbackLocale?: string;
5
+ }
6
+ export interface MergeSourceTranslationsInput {
7
+ locale: string;
8
+ pageName: string;
9
+ locales: SourceLocaleInfo[];
10
+ globalFallbackLocale?: string;
11
+ disablePageLocales?: boolean;
12
+ readLocaleFile: (relativePath: string) => Record<string, unknown> | Promise<Record<string, unknown>>;
13
+ }
14
+ export declare function buildFallbackLocaleChain(locale: string, locales: SourceLocaleInfo[], globalFallbackLocale?: string): string[];
15
+ export declare function mergeTranslationsFromFallbackChain(chain: string[], readLocaleFile: (relativePath: string) => Record<string, unknown>, relativePathForLocale: (localeCode: string) => string): Record<string, unknown>;
16
+ export declare function mergeTranslationsFromFallbackChainAsync(chain: string[], readLocaleFile: (relativePath: string) => Record<string, unknown> | Promise<Record<string, unknown>>, relativePathForLocale: (localeCode: string) => string): Promise<Record<string, unknown>>;
17
+ export declare function resolveSourcePageName(pageName: string, disablePageLocales?: boolean): string;
18
+ export declare function buildSourceRootPath(localeCode: string): string;
19
+ export declare function buildSourcePagePath(pageName: string, localeCode: string): string;
20
+ export declare function toSourceStorageKey(relativePath: string): string;
21
+ export declare function mergeSourceTranslations(input: MergeSourceTranslationsInput): Promise<Record<string, unknown>>;
22
+ export declare function normalizeConfiguredLocales(locales: Array<string | Locale> | undefined): SourceLocaleInfo[];
@@ -0,0 +1,51 @@
1
+ import { deepMergeTranslations as t } from "./deep-merge.mjs";
2
+ function u(e, a, r) {
3
+ const n = new Set(a.map((o) => o.code)), c = a.find((o) => o.code === e);
4
+ return [r, c?.fallbackLocale, e].filter((o) => !!o && n.has(o)).filter((o, i, f) => f.indexOf(o) === i);
5
+ }
6
+ function b(e, a, r) {
7
+ let n = {};
8
+ for (const c of e)
9
+ n = t(n, a(r(c)));
10
+ return n;
11
+ }
12
+ async function l(e, a, r) {
13
+ let n = {};
14
+ for (const c of e) {
15
+ const o = await a(r(c));
16
+ n = t(n, o);
17
+ }
18
+ return n;
19
+ }
20
+ function s(e, a) {
21
+ return a ? "index" : e || "index";
22
+ }
23
+ function d(e) {
24
+ return `${e}.json`;
25
+ }
26
+ function g(e, a) {
27
+ return `pages/${s(e)}/${a}.json`;
28
+ }
29
+ function L(e) {
30
+ return `assets:i18n:${e.replace(/\//g, ":")}`;
31
+ }
32
+ async function k(e) {
33
+ const a = s(e.pageName, e.disablePageLocales), r = u(e.locale, e.locales, e.globalFallbackLocale), n = await l(r, e.readLocaleFile, d), c = await l(r, e.readLocaleFile, (o) => g(a, o));
34
+ return t(n, c);
35
+ }
36
+ function C(e) {
37
+ return (e ?? []).map(
38
+ (a) => typeof a == "string" ? { code: a } : { code: a.code, fallbackLocale: a.fallbackLocale }
39
+ );
40
+ }
41
+ export {
42
+ u as buildFallbackLocaleChain,
43
+ g as buildSourcePagePath,
44
+ d as buildSourceRootPath,
45
+ k as mergeSourceTranslations,
46
+ b as mergeTranslationsFromFallbackChain,
47
+ l as mergeTranslationsFromFallbackChainAsync,
48
+ C as normalizeConfiguredLocales,
49
+ s as resolveSourcePageName,
50
+ L as toSourceStorageKey
51
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("./deep-merge.cjs");function n(e){const t=e.replace(/\\/g,"/");if(!t.endsWith(".json"))return{type:"ignore"};if(t.startsWith("pages/")){const r=t.match(/^pages\/(.+)\/([^/]+)\.json$/);if(!r?.[1]||!r[2])return{type:"ignore"};const o=s(r[1].split("/"));return o?{type:"page",pageName:o,locale:r[2]}:{type:"ignore"}}const a=t.match(/^([^/]+)\.json$/);return a?.[1]?{type:"root",locale:a[1]}:{type:"ignore"}}function i(e,t=!1){const a=n(e);return t&&a.type==="page"?{type:"root",locale:a.locale}:a}function s(e){return e.length===0?null:e.join("-")}function u(e,t,a,r=!1){const o=i(t,r);if(o.type==="page"){const l=e.routes[o.pageName]??(e.routes[o.pageName]={});l[o.locale]=a;return}o.type==="root"&&(e.root[o.locale]=a)}function c(e,t){return p.deepMergeTranslations(e??{},t)}exports.classifyTranslationRelativePath=i;exports.mergeRouteTranslationsWithRoot=c;exports.pagePathSegmentsToRouteName=s;exports.parseTranslationRelativePath=n;exports.storeLoadedTranslationFile=u;
@@ -0,0 +1,35 @@
1
+ export type ParsedTranslationRelativePath = {
2
+ type: 'page';
3
+ pageName: string;
4
+ locale: string;
5
+ } | {
6
+ type: 'root';
7
+ locale: string;
8
+ } | {
9
+ type: 'ignore';
10
+ };
11
+ export interface TranslationFileBuckets<T = Record<string, unknown>> {
12
+ root: Record<string, T>;
13
+ routes: Record<string, Record<string, T>>;
14
+ }
15
+ /**
16
+ * Parse a translation file path relative to the locales root.
17
+ * Examples: `en.json`, `pages/about/en.json`, `pages/user/profile/en.json`
18
+ */
19
+ export declare function parseTranslationRelativePath(relativePath: string): ParsedTranslationRelativePath;
20
+ /**
21
+ * Classify a translation path, optionally treating page files as root-level translations.
22
+ */
23
+ export declare function classifyTranslationRelativePath(relativePath: string, disablePageLocales?: boolean): ParsedTranslationRelativePath;
24
+ /**
25
+ * Convert nested page path segments to a route name (e.g. `user/profile` → `user-profile`).
26
+ */
27
+ export declare function pagePathSegmentsToRouteName(segments: string[]): string | null;
28
+ /**
29
+ * Store a loaded translation file in root or route buckets based on its relative path.
30
+ */
31
+ export declare function storeLoadedTranslationFile<T extends Record<string, unknown>>(buckets: TranslationFileBuckets<T>, relativePath: string, translations: T, disablePageLocales?: boolean): void;
32
+ /**
33
+ * Merge route-specific translations on top of root translations.
34
+ */
35
+ export declare function mergeRouteTranslationsWithRoot<T extends Record<string, unknown>>(rootTranslations: T | undefined, routeTranslations: T): T;