@contractspec/lib.contracts-spec 2.4.0 → 2.5.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.
- package/dist/integrations/index.js +379 -53
- package/dist/integrations/providers/deepgram.d.ts +3 -0
- package/dist/integrations/providers/deepgram.js +129 -0
- package/dist/integrations/providers/elevenlabs.js +6 -3
- package/dist/integrations/providers/fal-image.d.ts +3 -0
- package/dist/integrations/providers/fal-image.js +122 -0
- package/dist/integrations/providers/fal.js +2 -2
- package/dist/integrations/providers/gradium.js +2 -2
- package/dist/integrations/providers/image.d.ts +85 -0
- package/dist/integrations/providers/image.js +46 -0
- package/dist/integrations/providers/index.d.ts +6 -0
- package/dist/integrations/providers/index.js +380 -54
- package/dist/integrations/providers/openai-image.d.ts +3 -0
- package/dist/integrations/providers/openai-image.js +126 -0
- package/dist/integrations/providers/openai-realtime.d.ts +3 -0
- package/dist/integrations/providers/openai-realtime.js +127 -0
- package/dist/integrations/providers/registry.js +192 -33
- package/dist/integrations/providers/voice-video-sync.d.ts +29 -0
- package/dist/integrations/providers/voice-video-sync.js +1 -0
- package/dist/integrations/providers/voice.d.ts +149 -12
- package/dist/integrations/spec.d.ts +1 -1
- package/dist/node/integrations/index.js +379 -53
- package/dist/node/integrations/providers/deepgram.js +129 -0
- package/dist/node/integrations/providers/elevenlabs.js +6 -3
- package/dist/node/integrations/providers/fal-image.js +122 -0
- package/dist/node/integrations/providers/fal.js +2 -2
- package/dist/node/integrations/providers/gradium.js +2 -2
- package/dist/node/integrations/providers/image.js +46 -0
- package/dist/node/integrations/providers/index.js +380 -54
- package/dist/node/integrations/providers/openai-image.js +126 -0
- package/dist/node/integrations/providers/openai-realtime.js +127 -0
- package/dist/node/integrations/providers/registry.js +192 -33
- package/dist/node/integrations/providers/voice-video-sync.js +0 -0
- package/dist/node/translations/i18n-factory.js +229 -0
- package/dist/node/translations/index.js +64 -4
- package/dist/translations/i18n-factory.d.ts +90 -0
- package/dist/translations/i18n-factory.js +229 -0
- package/dist/translations/index.d.ts +1 -0
- package/dist/translations/index.js +64 -4
- package/package.json +88 -4
|
File without changes
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
7
|
+
var __toCommonJS = (from) => {
|
|
8
|
+
var entry = __moduleCache.get(from), desc;
|
|
9
|
+
if (entry)
|
|
10
|
+
return entry;
|
|
11
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
13
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
14
|
+
get: () => from[key],
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
}));
|
|
17
|
+
__moduleCache.set(from, entry);
|
|
18
|
+
return entry;
|
|
19
|
+
};
|
|
20
|
+
var __export = (target, all) => {
|
|
21
|
+
for (var name in all)
|
|
22
|
+
__defProp(target, name, {
|
|
23
|
+
get: all[name],
|
|
24
|
+
enumerable: true,
|
|
25
|
+
configurable: true,
|
|
26
|
+
set: (newValue) => all[name] = () => newValue
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
30
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
31
|
+
|
|
32
|
+
// src/translations/registry.ts
|
|
33
|
+
class TranslationRegistry {
|
|
34
|
+
specs = new Map;
|
|
35
|
+
latestByLocale = new Map;
|
|
36
|
+
locales = new Set;
|
|
37
|
+
domains = new Set;
|
|
38
|
+
constructor(items) {
|
|
39
|
+
if (items) {
|
|
40
|
+
for (const spec of items) {
|
|
41
|
+
this.register(spec);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
register(spec) {
|
|
46
|
+
const fullKey = this.makeKey(spec.meta.key, spec.meta.version, spec.locale);
|
|
47
|
+
this.specs.set(fullKey, spec);
|
|
48
|
+
const localeKey = `${spec.meta.key}:${spec.locale}`;
|
|
49
|
+
const existing = this.latestByLocale.get(localeKey);
|
|
50
|
+
if (!existing || this.isNewerVersion(spec.meta.version, existing.meta.version)) {
|
|
51
|
+
this.latestByLocale.set(localeKey, spec);
|
|
52
|
+
}
|
|
53
|
+
this.locales.add(spec.locale);
|
|
54
|
+
this.domains.add(spec.meta.domain);
|
|
55
|
+
}
|
|
56
|
+
get(key, version, locale) {
|
|
57
|
+
return this.specs.get(this.makeKey(key, version, locale));
|
|
58
|
+
}
|
|
59
|
+
getLatest(key, locale) {
|
|
60
|
+
return this.latestByLocale.get(`${key}:${locale}`);
|
|
61
|
+
}
|
|
62
|
+
getMessage(specKey, messageKey, locale, version) {
|
|
63
|
+
const spec = version ? this.get(specKey, version, locale) : this.getLatest(specKey, locale);
|
|
64
|
+
if (!spec)
|
|
65
|
+
return;
|
|
66
|
+
return spec.messages[messageKey];
|
|
67
|
+
}
|
|
68
|
+
getWithFallback(specKey, messageKey, locale, fallbackLocale, version) {
|
|
69
|
+
const spec = version ? this.get(specKey, version, locale) : this.getLatest(specKey, locale);
|
|
70
|
+
if (spec) {
|
|
71
|
+
const message = spec.messages[messageKey];
|
|
72
|
+
if (message) {
|
|
73
|
+
return { spec, message, locale, fromFallback: false };
|
|
74
|
+
}
|
|
75
|
+
fallbackLocale = fallbackLocale ?? spec.fallback;
|
|
76
|
+
}
|
|
77
|
+
if (fallbackLocale && fallbackLocale !== locale) {
|
|
78
|
+
const fallbackSpec = version ? this.get(specKey, version, fallbackLocale) : this.getLatest(specKey, fallbackLocale);
|
|
79
|
+
if (fallbackSpec) {
|
|
80
|
+
const message = fallbackSpec.messages[messageKey];
|
|
81
|
+
if (message) {
|
|
82
|
+
return {
|
|
83
|
+
spec: fallbackSpec,
|
|
84
|
+
message,
|
|
85
|
+
locale: fallbackLocale,
|
|
86
|
+
fromFallback: true
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
getValue(specKey, messageKey, locale, fallback) {
|
|
94
|
+
const result = this.getWithFallback(specKey, messageKey, locale);
|
|
95
|
+
return result?.message.value ?? fallback ?? messageKey;
|
|
96
|
+
}
|
|
97
|
+
listLocales(specKey) {
|
|
98
|
+
const locales = [];
|
|
99
|
+
for (const [key, spec] of this.specs.entries()) {
|
|
100
|
+
if (key.startsWith(`${specKey}:`)) {
|
|
101
|
+
if (!locales.includes(spec.locale)) {
|
|
102
|
+
locales.push(spec.locale);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return locales;
|
|
107
|
+
}
|
|
108
|
+
list() {
|
|
109
|
+
return [...this.specs.values()];
|
|
110
|
+
}
|
|
111
|
+
listByLocale(locale) {
|
|
112
|
+
return [...this.specs.values()].filter((s) => s.locale === locale);
|
|
113
|
+
}
|
|
114
|
+
listByDomain(domain) {
|
|
115
|
+
return [...this.specs.values()].filter((s) => s.meta.domain === domain);
|
|
116
|
+
}
|
|
117
|
+
has(key, locale, version) {
|
|
118
|
+
if (version) {
|
|
119
|
+
return this.specs.has(this.makeKey(key, version, locale));
|
|
120
|
+
}
|
|
121
|
+
return this.latestByLocale.has(`${key}:${locale}`);
|
|
122
|
+
}
|
|
123
|
+
getLocales() {
|
|
124
|
+
return this.locales;
|
|
125
|
+
}
|
|
126
|
+
getDomains() {
|
|
127
|
+
return this.domains;
|
|
128
|
+
}
|
|
129
|
+
getStats() {
|
|
130
|
+
let totalMessages = 0;
|
|
131
|
+
for (const spec of this.specs.values()) {
|
|
132
|
+
totalMessages += Object.keys(spec.messages).length;
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
totalSpecs: this.specs.size,
|
|
136
|
+
locales: [...this.locales],
|
|
137
|
+
domains: [...this.domains],
|
|
138
|
+
totalMessages
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
clear() {
|
|
142
|
+
this.specs.clear();
|
|
143
|
+
this.latestByLocale.clear();
|
|
144
|
+
this.locales.clear();
|
|
145
|
+
this.domains.clear();
|
|
146
|
+
}
|
|
147
|
+
makeKey(key, version, locale) {
|
|
148
|
+
return `${key}:${version}:${locale}`;
|
|
149
|
+
}
|
|
150
|
+
isNewerVersion(a, b) {
|
|
151
|
+
const parseVersion = (v) => {
|
|
152
|
+
const parts = v.split(".").map(Number);
|
|
153
|
+
return {
|
|
154
|
+
major: parts[0] ?? 0,
|
|
155
|
+
minor: parts[1] ?? 0,
|
|
156
|
+
patch: parts[2] ?? 0
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
const va = parseVersion(a);
|
|
160
|
+
const vb = parseVersion(b);
|
|
161
|
+
if (va.major !== vb.major)
|
|
162
|
+
return va.major > vb.major;
|
|
163
|
+
if (va.minor !== vb.minor)
|
|
164
|
+
return va.minor > vb.minor;
|
|
165
|
+
return va.patch > vb.patch;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/translations/i18n-factory.ts
|
|
170
|
+
var DEFAULT_LOCALE = "en";
|
|
171
|
+
var SUPPORTED_LOCALES = ["en", "fr", "es"];
|
|
172
|
+
function resolveLocale(optionsLocale, runtimeLocale) {
|
|
173
|
+
const raw = runtimeLocale ?? optionsLocale ?? DEFAULT_LOCALE;
|
|
174
|
+
if (isSupportedLocale(raw))
|
|
175
|
+
return raw;
|
|
176
|
+
const base = raw.split("-")[0];
|
|
177
|
+
if (base && isSupportedLocale(base))
|
|
178
|
+
return base;
|
|
179
|
+
return DEFAULT_LOCALE;
|
|
180
|
+
}
|
|
181
|
+
function isSupportedLocale(locale) {
|
|
182
|
+
return SUPPORTED_LOCALES.includes(locale);
|
|
183
|
+
}
|
|
184
|
+
function interpolate(template, params) {
|
|
185
|
+
if (!params)
|
|
186
|
+
return template;
|
|
187
|
+
return template.replace(/\{(\w+)\}/g, (match, key) => {
|
|
188
|
+
if (key in params)
|
|
189
|
+
return String(params[key]);
|
|
190
|
+
return match;
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
function createI18nFactory(config) {
|
|
194
|
+
let sharedRegistry = null;
|
|
195
|
+
function getRegistry() {
|
|
196
|
+
if (!sharedRegistry) {
|
|
197
|
+
sharedRegistry = new TranslationRegistry(config.catalogs);
|
|
198
|
+
}
|
|
199
|
+
return sharedRegistry;
|
|
200
|
+
}
|
|
201
|
+
const factory = {
|
|
202
|
+
create(optionsLocale, runtimeLocale) {
|
|
203
|
+
const locale = resolveLocale(optionsLocale, runtimeLocale);
|
|
204
|
+
const registry = getRegistry();
|
|
205
|
+
return {
|
|
206
|
+
locale,
|
|
207
|
+
t(key, params) {
|
|
208
|
+
const raw = registry.getValue(config.specKey, key, locale, key);
|
|
209
|
+
return interpolate(raw, params);
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
},
|
|
213
|
+
getDefault() {
|
|
214
|
+
return factory.create(DEFAULT_LOCALE);
|
|
215
|
+
},
|
|
216
|
+
resetRegistry() {
|
|
217
|
+
sharedRegistry = null;
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
return factory;
|
|
221
|
+
}
|
|
222
|
+
export {
|
|
223
|
+
resolveLocale,
|
|
224
|
+
isSupportedLocale,
|
|
225
|
+
interpolate,
|
|
226
|
+
createI18nFactory,
|
|
227
|
+
SUPPORTED_LOCALES,
|
|
228
|
+
DEFAULT_LOCALE
|
|
229
|
+
};
|
|
@@ -28,9 +28,6 @@ var __export = (target, all) => {
|
|
|
28
28
|
};
|
|
29
29
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
30
30
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
31
|
-
// src/translations/spec.ts
|
|
32
|
-
var defineTranslation = (spec) => spec;
|
|
33
|
-
|
|
34
31
|
// src/translations/registry.ts
|
|
35
32
|
class TranslationRegistry {
|
|
36
33
|
specs = new Map;
|
|
@@ -168,6 +165,63 @@ class TranslationRegistry {
|
|
|
168
165
|
}
|
|
169
166
|
}
|
|
170
167
|
|
|
168
|
+
// src/translations/i18n-factory.ts
|
|
169
|
+
var DEFAULT_LOCALE = "en";
|
|
170
|
+
var SUPPORTED_LOCALES = ["en", "fr", "es"];
|
|
171
|
+
function resolveLocale(optionsLocale, runtimeLocale) {
|
|
172
|
+
const raw = runtimeLocale ?? optionsLocale ?? DEFAULT_LOCALE;
|
|
173
|
+
if (isSupportedLocale(raw))
|
|
174
|
+
return raw;
|
|
175
|
+
const base = raw.split("-")[0];
|
|
176
|
+
if (base && isSupportedLocale(base))
|
|
177
|
+
return base;
|
|
178
|
+
return DEFAULT_LOCALE;
|
|
179
|
+
}
|
|
180
|
+
function isSupportedLocale(locale) {
|
|
181
|
+
return SUPPORTED_LOCALES.includes(locale);
|
|
182
|
+
}
|
|
183
|
+
function interpolate(template, params) {
|
|
184
|
+
if (!params)
|
|
185
|
+
return template;
|
|
186
|
+
return template.replace(/\{(\w+)\}/g, (match, key) => {
|
|
187
|
+
if (key in params)
|
|
188
|
+
return String(params[key]);
|
|
189
|
+
return match;
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
function createI18nFactory(config) {
|
|
193
|
+
let sharedRegistry = null;
|
|
194
|
+
function getRegistry() {
|
|
195
|
+
if (!sharedRegistry) {
|
|
196
|
+
sharedRegistry = new TranslationRegistry(config.catalogs);
|
|
197
|
+
}
|
|
198
|
+
return sharedRegistry;
|
|
199
|
+
}
|
|
200
|
+
const factory = {
|
|
201
|
+
create(optionsLocale, runtimeLocale) {
|
|
202
|
+
const locale = resolveLocale(optionsLocale, runtimeLocale);
|
|
203
|
+
const registry = getRegistry();
|
|
204
|
+
return {
|
|
205
|
+
locale,
|
|
206
|
+
t(key, params) {
|
|
207
|
+
const raw = registry.getValue(config.specKey, key, locale, key);
|
|
208
|
+
return interpolate(raw, params);
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
},
|
|
212
|
+
getDefault() {
|
|
213
|
+
return factory.create(DEFAULT_LOCALE);
|
|
214
|
+
},
|
|
215
|
+
resetRegistry() {
|
|
216
|
+
sharedRegistry = null;
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
return factory;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// src/translations/spec.ts
|
|
223
|
+
var defineTranslation = (spec) => spec;
|
|
224
|
+
|
|
171
225
|
// src/translations/validation.ts
|
|
172
226
|
function validateTranslationSpec(spec) {
|
|
173
227
|
const issues = [];
|
|
@@ -524,10 +578,16 @@ export {
|
|
|
524
578
|
validateTranslationSpec,
|
|
525
579
|
validateTranslationRegistry,
|
|
526
580
|
validateICUFormat,
|
|
581
|
+
resolveLocale,
|
|
582
|
+
isSupportedLocale,
|
|
583
|
+
interpolate,
|
|
527
584
|
findMissingTranslations,
|
|
528
585
|
findAllMissingTranslations,
|
|
529
586
|
defineTranslation,
|
|
587
|
+
createI18nFactory,
|
|
530
588
|
assertTranslationSpecValid,
|
|
531
589
|
TranslationValidationError,
|
|
532
|
-
TranslationRegistry
|
|
590
|
+
TranslationRegistry,
|
|
591
|
+
SUPPORTED_LOCALES,
|
|
592
|
+
DEFAULT_LOCALE
|
|
533
593
|
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic i18n factory for ContractSpec packages.
|
|
3
|
+
*
|
|
4
|
+
* Eliminates the boilerplate duplicated across package-level
|
|
5
|
+
* i18n/messages.ts files by extracting the common interpolation,
|
|
6
|
+
* registry management, locale resolution, and t() wiring.
|
|
7
|
+
*
|
|
8
|
+
* @module translations/i18n-factory
|
|
9
|
+
*/
|
|
10
|
+
import type { TranslationSpec } from './spec';
|
|
11
|
+
/** Default locale when none is specified. */
|
|
12
|
+
export declare const DEFAULT_LOCALE = "en";
|
|
13
|
+
/** Supported locales shipped with ContractSpec packages. */
|
|
14
|
+
export declare const SUPPORTED_LOCALES: readonly ["en", "fr", "es"];
|
|
15
|
+
/** A locale included in the default set. */
|
|
16
|
+
export type SupportedLocale = (typeof SUPPORTED_LOCALES)[number];
|
|
17
|
+
/**
|
|
18
|
+
* Resolve the effective locale from two optional overrides.
|
|
19
|
+
*
|
|
20
|
+
* Priority: `runtimeLocale > optionsLocale > DEFAULT_LOCALE`.
|
|
21
|
+
* Falls back to base language (e.g., `"fr-CA"` -> `"fr"`) when needed.
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveLocale(optionsLocale?: string, runtimeLocale?: string): string;
|
|
24
|
+
/** Check whether a string is a supported locale. */
|
|
25
|
+
export declare function isSupportedLocale(locale: string): locale is SupportedLocale;
|
|
26
|
+
/**
|
|
27
|
+
* Simple placeholder interpolation.
|
|
28
|
+
*
|
|
29
|
+
* Replaces `{key}` tokens with values from the params map.
|
|
30
|
+
* Does NOT handle full ICU (plurals, selects) — only simple
|
|
31
|
+
* string/number substitution.
|
|
32
|
+
*/
|
|
33
|
+
export declare function interpolate(template: string, params?: Record<string, string | number>): string;
|
|
34
|
+
/**
|
|
35
|
+
* A package-scoped i18n instance.
|
|
36
|
+
*
|
|
37
|
+
* @typeParam K - Union type of valid message keys for the package
|
|
38
|
+
*/
|
|
39
|
+
export interface I18nInstance<K extends string = string> {
|
|
40
|
+
/** Translate a message key with optional placeholder interpolation. */
|
|
41
|
+
t(key: K | string, params?: Record<string, string | number>): string;
|
|
42
|
+
/** The effective locale being used. */
|
|
43
|
+
readonly locale: string;
|
|
44
|
+
}
|
|
45
|
+
/** Configuration for `createI18nFactory`. */
|
|
46
|
+
export interface I18nFactoryConfig {
|
|
47
|
+
/** The spec key used to register translations (e.g., `"ai-agent.messages"`). */
|
|
48
|
+
specKey: string;
|
|
49
|
+
/** Translation catalogs to register (typically `[en, fr, es]`). */
|
|
50
|
+
catalogs: TranslationSpec[];
|
|
51
|
+
}
|
|
52
|
+
/** The object returned by `createI18nFactory`. */
|
|
53
|
+
export interface I18nFactory<K extends string = string> {
|
|
54
|
+
/** Create an i18n instance for a given locale. */
|
|
55
|
+
create(optionsLocale?: string, runtimeLocale?: string): I18nInstance<K>;
|
|
56
|
+
/** Create a default (English) i18n instance. */
|
|
57
|
+
getDefault(): I18nInstance<K>;
|
|
58
|
+
/** Reset the shared registry (useful for testing). */
|
|
59
|
+
resetRegistry(): void;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Create a package-scoped i18n factory.
|
|
63
|
+
*
|
|
64
|
+
* Replaces the ~100 lines of boilerplate previously duplicated
|
|
65
|
+
* in every package's `i18n/messages.ts`.
|
|
66
|
+
*
|
|
67
|
+
* @typeParam K - The package's message key union type
|
|
68
|
+
* @param config - Spec key and translation catalogs
|
|
69
|
+
* @returns An I18nFactory with `create()`, `getDefault()`, and `resetRegistry()`
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* import { createI18nFactory } from '@contractspec/lib.contracts-spec/translations';
|
|
74
|
+
* import type { AgentMessageKey } from './keys';
|
|
75
|
+
* import { enMessages } from './catalogs/en';
|
|
76
|
+
* import { frMessages } from './catalogs/fr';
|
|
77
|
+
* import { esMessages } from './catalogs/es';
|
|
78
|
+
*
|
|
79
|
+
* const factory = createI18nFactory<AgentMessageKey>({
|
|
80
|
+
* specKey: 'ai-agent.messages',
|
|
81
|
+
* catalogs: [enMessages, frMessages, esMessages],
|
|
82
|
+
* });
|
|
83
|
+
*
|
|
84
|
+
* export type AgentI18n = I18nInstance<AgentMessageKey>;
|
|
85
|
+
* export const createAgentI18n = factory.create;
|
|
86
|
+
* export const getDefaultI18n = factory.getDefault;
|
|
87
|
+
* export const resetI18nRegistry = factory.resetRegistry;
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare function createI18nFactory<K extends string = string>(config: I18nFactoryConfig): I18nFactory<K>;
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
7
|
+
var __toCommonJS = (from) => {
|
|
8
|
+
var entry = __moduleCache.get(from), desc;
|
|
9
|
+
if (entry)
|
|
10
|
+
return entry;
|
|
11
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
13
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
14
|
+
get: () => from[key],
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
}));
|
|
17
|
+
__moduleCache.set(from, entry);
|
|
18
|
+
return entry;
|
|
19
|
+
};
|
|
20
|
+
var __export = (target, all) => {
|
|
21
|
+
for (var name in all)
|
|
22
|
+
__defProp(target, name, {
|
|
23
|
+
get: all[name],
|
|
24
|
+
enumerable: true,
|
|
25
|
+
configurable: true,
|
|
26
|
+
set: (newValue) => all[name] = () => newValue
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
30
|
+
var __require = import.meta.require;
|
|
31
|
+
|
|
32
|
+
// src/translations/registry.ts
|
|
33
|
+
class TranslationRegistry {
|
|
34
|
+
specs = new Map;
|
|
35
|
+
latestByLocale = new Map;
|
|
36
|
+
locales = new Set;
|
|
37
|
+
domains = new Set;
|
|
38
|
+
constructor(items) {
|
|
39
|
+
if (items) {
|
|
40
|
+
for (const spec of items) {
|
|
41
|
+
this.register(spec);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
register(spec) {
|
|
46
|
+
const fullKey = this.makeKey(spec.meta.key, spec.meta.version, spec.locale);
|
|
47
|
+
this.specs.set(fullKey, spec);
|
|
48
|
+
const localeKey = `${spec.meta.key}:${spec.locale}`;
|
|
49
|
+
const existing = this.latestByLocale.get(localeKey);
|
|
50
|
+
if (!existing || this.isNewerVersion(spec.meta.version, existing.meta.version)) {
|
|
51
|
+
this.latestByLocale.set(localeKey, spec);
|
|
52
|
+
}
|
|
53
|
+
this.locales.add(spec.locale);
|
|
54
|
+
this.domains.add(spec.meta.domain);
|
|
55
|
+
}
|
|
56
|
+
get(key, version, locale) {
|
|
57
|
+
return this.specs.get(this.makeKey(key, version, locale));
|
|
58
|
+
}
|
|
59
|
+
getLatest(key, locale) {
|
|
60
|
+
return this.latestByLocale.get(`${key}:${locale}`);
|
|
61
|
+
}
|
|
62
|
+
getMessage(specKey, messageKey, locale, version) {
|
|
63
|
+
const spec = version ? this.get(specKey, version, locale) : this.getLatest(specKey, locale);
|
|
64
|
+
if (!spec)
|
|
65
|
+
return;
|
|
66
|
+
return spec.messages[messageKey];
|
|
67
|
+
}
|
|
68
|
+
getWithFallback(specKey, messageKey, locale, fallbackLocale, version) {
|
|
69
|
+
const spec = version ? this.get(specKey, version, locale) : this.getLatest(specKey, locale);
|
|
70
|
+
if (spec) {
|
|
71
|
+
const message = spec.messages[messageKey];
|
|
72
|
+
if (message) {
|
|
73
|
+
return { spec, message, locale, fromFallback: false };
|
|
74
|
+
}
|
|
75
|
+
fallbackLocale = fallbackLocale ?? spec.fallback;
|
|
76
|
+
}
|
|
77
|
+
if (fallbackLocale && fallbackLocale !== locale) {
|
|
78
|
+
const fallbackSpec = version ? this.get(specKey, version, fallbackLocale) : this.getLatest(specKey, fallbackLocale);
|
|
79
|
+
if (fallbackSpec) {
|
|
80
|
+
const message = fallbackSpec.messages[messageKey];
|
|
81
|
+
if (message) {
|
|
82
|
+
return {
|
|
83
|
+
spec: fallbackSpec,
|
|
84
|
+
message,
|
|
85
|
+
locale: fallbackLocale,
|
|
86
|
+
fromFallback: true
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
getValue(specKey, messageKey, locale, fallback) {
|
|
94
|
+
const result = this.getWithFallback(specKey, messageKey, locale);
|
|
95
|
+
return result?.message.value ?? fallback ?? messageKey;
|
|
96
|
+
}
|
|
97
|
+
listLocales(specKey) {
|
|
98
|
+
const locales = [];
|
|
99
|
+
for (const [key, spec] of this.specs.entries()) {
|
|
100
|
+
if (key.startsWith(`${specKey}:`)) {
|
|
101
|
+
if (!locales.includes(spec.locale)) {
|
|
102
|
+
locales.push(spec.locale);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return locales;
|
|
107
|
+
}
|
|
108
|
+
list() {
|
|
109
|
+
return [...this.specs.values()];
|
|
110
|
+
}
|
|
111
|
+
listByLocale(locale) {
|
|
112
|
+
return [...this.specs.values()].filter((s) => s.locale === locale);
|
|
113
|
+
}
|
|
114
|
+
listByDomain(domain) {
|
|
115
|
+
return [...this.specs.values()].filter((s) => s.meta.domain === domain);
|
|
116
|
+
}
|
|
117
|
+
has(key, locale, version) {
|
|
118
|
+
if (version) {
|
|
119
|
+
return this.specs.has(this.makeKey(key, version, locale));
|
|
120
|
+
}
|
|
121
|
+
return this.latestByLocale.has(`${key}:${locale}`);
|
|
122
|
+
}
|
|
123
|
+
getLocales() {
|
|
124
|
+
return this.locales;
|
|
125
|
+
}
|
|
126
|
+
getDomains() {
|
|
127
|
+
return this.domains;
|
|
128
|
+
}
|
|
129
|
+
getStats() {
|
|
130
|
+
let totalMessages = 0;
|
|
131
|
+
for (const spec of this.specs.values()) {
|
|
132
|
+
totalMessages += Object.keys(spec.messages).length;
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
totalSpecs: this.specs.size,
|
|
136
|
+
locales: [...this.locales],
|
|
137
|
+
domains: [...this.domains],
|
|
138
|
+
totalMessages
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
clear() {
|
|
142
|
+
this.specs.clear();
|
|
143
|
+
this.latestByLocale.clear();
|
|
144
|
+
this.locales.clear();
|
|
145
|
+
this.domains.clear();
|
|
146
|
+
}
|
|
147
|
+
makeKey(key, version, locale) {
|
|
148
|
+
return `${key}:${version}:${locale}`;
|
|
149
|
+
}
|
|
150
|
+
isNewerVersion(a, b) {
|
|
151
|
+
const parseVersion = (v) => {
|
|
152
|
+
const parts = v.split(".").map(Number);
|
|
153
|
+
return {
|
|
154
|
+
major: parts[0] ?? 0,
|
|
155
|
+
minor: parts[1] ?? 0,
|
|
156
|
+
patch: parts[2] ?? 0
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
const va = parseVersion(a);
|
|
160
|
+
const vb = parseVersion(b);
|
|
161
|
+
if (va.major !== vb.major)
|
|
162
|
+
return va.major > vb.major;
|
|
163
|
+
if (va.minor !== vb.minor)
|
|
164
|
+
return va.minor > vb.minor;
|
|
165
|
+
return va.patch > vb.patch;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/translations/i18n-factory.ts
|
|
170
|
+
var DEFAULT_LOCALE = "en";
|
|
171
|
+
var SUPPORTED_LOCALES = ["en", "fr", "es"];
|
|
172
|
+
function resolveLocale(optionsLocale, runtimeLocale) {
|
|
173
|
+
const raw = runtimeLocale ?? optionsLocale ?? DEFAULT_LOCALE;
|
|
174
|
+
if (isSupportedLocale(raw))
|
|
175
|
+
return raw;
|
|
176
|
+
const base = raw.split("-")[0];
|
|
177
|
+
if (base && isSupportedLocale(base))
|
|
178
|
+
return base;
|
|
179
|
+
return DEFAULT_LOCALE;
|
|
180
|
+
}
|
|
181
|
+
function isSupportedLocale(locale) {
|
|
182
|
+
return SUPPORTED_LOCALES.includes(locale);
|
|
183
|
+
}
|
|
184
|
+
function interpolate(template, params) {
|
|
185
|
+
if (!params)
|
|
186
|
+
return template;
|
|
187
|
+
return template.replace(/\{(\w+)\}/g, (match, key) => {
|
|
188
|
+
if (key in params)
|
|
189
|
+
return String(params[key]);
|
|
190
|
+
return match;
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
function createI18nFactory(config) {
|
|
194
|
+
let sharedRegistry = null;
|
|
195
|
+
function getRegistry() {
|
|
196
|
+
if (!sharedRegistry) {
|
|
197
|
+
sharedRegistry = new TranslationRegistry(config.catalogs);
|
|
198
|
+
}
|
|
199
|
+
return sharedRegistry;
|
|
200
|
+
}
|
|
201
|
+
const factory = {
|
|
202
|
+
create(optionsLocale, runtimeLocale) {
|
|
203
|
+
const locale = resolveLocale(optionsLocale, runtimeLocale);
|
|
204
|
+
const registry = getRegistry();
|
|
205
|
+
return {
|
|
206
|
+
locale,
|
|
207
|
+
t(key, params) {
|
|
208
|
+
const raw = registry.getValue(config.specKey, key, locale, key);
|
|
209
|
+
return interpolate(raw, params);
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
},
|
|
213
|
+
getDefault() {
|
|
214
|
+
return factory.create(DEFAULT_LOCALE);
|
|
215
|
+
},
|
|
216
|
+
resetRegistry() {
|
|
217
|
+
sharedRegistry = null;
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
return factory;
|
|
221
|
+
}
|
|
222
|
+
export {
|
|
223
|
+
resolveLocale,
|
|
224
|
+
isSupportedLocale,
|
|
225
|
+
interpolate,
|
|
226
|
+
createI18nFactory,
|
|
227
|
+
SUPPORTED_LOCALES,
|
|
228
|
+
DEFAULT_LOCALE
|
|
229
|
+
};
|