@let-value/translate 1.1.2 → 1.1.6-beta.1
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/index.cjs +53 -85
- package/dist/index.d.cts.map +1 -1
- package/dist/{index.d.ts → index.d.mts} +1 -1
- package/dist/index.d.mts.map +1 -0
- package/dist/{index.js → index.mjs} +51 -59
- package/dist/index.mjs.map +1 -0
- package/package.json +38 -33
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,32 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __copyProps = (to, from, except, desc) => {
|
|
9
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
-
key = keys[i];
|
|
11
|
-
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
-
get: ((k) => from[k]).bind(null, key),
|
|
13
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
-
value: mod,
|
|
20
|
-
enumerable: true
|
|
21
|
-
}) : target, mod));
|
|
22
|
-
|
|
23
|
-
//#endregion
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
24
2
|
let plural_forms = require("plural-forms");
|
|
25
|
-
plural_forms = __toESM(plural_forms);
|
|
26
|
-
|
|
27
3
|
//#region src/utils.ts
|
|
28
|
-
function assert(value, message
|
|
29
|
-
if (!value) throw new Error(message
|
|
4
|
+
function assert(value, message) {
|
|
5
|
+
if (!value) throw new Error(message || "Assertion failed");
|
|
30
6
|
}
|
|
31
7
|
function memo(fn) {
|
|
32
8
|
const cache = /* @__PURE__ */ new Map();
|
|
@@ -42,8 +18,8 @@ function substitute(text, values = []) {
|
|
|
42
18
|
const placeholders = [];
|
|
43
19
|
return text.replace(/\$\{([^}]+)\}/g, (match, placeholder) => {
|
|
44
20
|
if (/^\d+$/.test(placeholder)) {
|
|
45
|
-
const index
|
|
46
|
-
return index
|
|
21
|
+
const index = Number(placeholder);
|
|
22
|
+
return index < values.length ? String(values[index]) : match;
|
|
47
23
|
}
|
|
48
24
|
let index = placeholders.indexOf(placeholder);
|
|
49
25
|
if (index === -1) {
|
|
@@ -70,24 +46,24 @@ function normalizeTranslations(translations) {
|
|
|
70
46
|
...translations,
|
|
71
47
|
translations: {}
|
|
72
48
|
};
|
|
73
|
-
for (const [context
|
|
74
|
-
normalized.translations[context
|
|
49
|
+
for (const [context, messages] of Object.entries(translations.translations)) {
|
|
50
|
+
normalized.translations[context] = {};
|
|
75
51
|
for (const [msgid, entry] of Object.entries(messages)) {
|
|
76
52
|
const normalizedId = normalizeMessageId(msgid);
|
|
77
|
-
normalized.translations[context
|
|
53
|
+
normalized.translations[context][normalizedId] = entry;
|
|
78
54
|
}
|
|
79
55
|
}
|
|
80
56
|
return normalized;
|
|
81
57
|
}
|
|
82
58
|
const defaultPluralFunc = (n) => n !== 1 ? 1 : 0;
|
|
83
|
-
const pluralFunc = memo(function pluralFunc
|
|
59
|
+
const pluralFunc = memo(function pluralFunc(locale) {
|
|
84
60
|
try {
|
|
85
61
|
const length = Number((0, plural_forms.getNPlurals)(locale));
|
|
86
62
|
if (length === 1) return () => 0;
|
|
87
|
-
const pluralFunc
|
|
63
|
+
const pluralFunc = (0, plural_forms.getPluralFunc)(locale);
|
|
88
64
|
const forms = Array.from({ length }, (_, i) => String(i));
|
|
89
65
|
return (n) => {
|
|
90
|
-
const idx = Number(pluralFunc
|
|
66
|
+
const idx = Number(pluralFunc(n, forms));
|
|
91
67
|
if (!Number.isFinite(idx) || idx < 0) return 0;
|
|
92
68
|
if (idx >= length) return length - 1;
|
|
93
69
|
return Math.floor(idx);
|
|
@@ -121,7 +97,6 @@ function mergeTranslations(primary, ...others) {
|
|
|
121
97
|
}
|
|
122
98
|
return result;
|
|
123
99
|
}
|
|
124
|
-
|
|
125
100
|
//#endregion
|
|
126
101
|
//#region src/messages.ts
|
|
127
102
|
function buildFromTemplate(strings) {
|
|
@@ -139,18 +114,16 @@ function message(...args) {
|
|
|
139
114
|
msgstr: source
|
|
140
115
|
};
|
|
141
116
|
if (typeof source === "object" && "reduce" in source) {
|
|
142
|
-
const id
|
|
117
|
+
const id = buildFromTemplate(source);
|
|
143
118
|
return {
|
|
144
|
-
msgid: id
|
|
145
|
-
msgstr: id
|
|
119
|
+
msgid: id,
|
|
120
|
+
msgstr: id,
|
|
146
121
|
values
|
|
147
122
|
};
|
|
148
123
|
}
|
|
149
|
-
const id = source.id ?? source.message ?? "";
|
|
150
|
-
const message$1 = source.message ?? source.id ?? "";
|
|
151
124
|
return {
|
|
152
|
-
msgid: id,
|
|
153
|
-
msgstr: message
|
|
125
|
+
msgid: source.id ?? source.message ?? "",
|
|
126
|
+
msgstr: source.message ?? source.id ?? ""
|
|
154
127
|
};
|
|
155
128
|
}
|
|
156
129
|
function plural(...args) {
|
|
@@ -167,36 +140,35 @@ const basePlural = plural;
|
|
|
167
140
|
function context(...args) {
|
|
168
141
|
const [source] = args;
|
|
169
142
|
const ctx = typeof source === "string" ? source : source[0];
|
|
170
|
-
function message
|
|
143
|
+
function message(...args) {
|
|
171
144
|
return {
|
|
172
|
-
id: baseMessage(...args
|
|
145
|
+
id: baseMessage(...args),
|
|
173
146
|
context: ctx
|
|
174
147
|
};
|
|
175
148
|
}
|
|
176
|
-
function plural
|
|
149
|
+
function plural(...forms) {
|
|
177
150
|
return {
|
|
178
151
|
id: basePlural(...forms),
|
|
179
152
|
context: ctx
|
|
180
153
|
};
|
|
181
154
|
}
|
|
182
155
|
return {
|
|
183
|
-
message
|
|
184
|
-
plural
|
|
156
|
+
message,
|
|
157
|
+
plural
|
|
185
158
|
};
|
|
186
159
|
}
|
|
187
|
-
|
|
188
160
|
//#endregion
|
|
189
161
|
//#region src/translator.ts
|
|
190
|
-
function selectValues(message
|
|
191
|
-
const values = message
|
|
162
|
+
function selectValues(message, fallback) {
|
|
163
|
+
const values = message?.values;
|
|
192
164
|
if (values?.length) return values;
|
|
193
165
|
return fallback?.values;
|
|
194
166
|
}
|
|
195
167
|
function selectTemplate(preferred, fallback) {
|
|
196
168
|
return preferred?.length ? preferred : fallback;
|
|
197
169
|
}
|
|
198
|
-
function applyValues(template, message
|
|
199
|
-
const values = selectValues(message
|
|
170
|
+
function applyValues(template, message, fallback) {
|
|
171
|
+
const values = selectValues(message, fallback);
|
|
200
172
|
return values?.length ? substitute(template, values) : template;
|
|
201
173
|
}
|
|
202
174
|
function isPluralMessage(value) {
|
|
@@ -212,8 +184,8 @@ function isContextPluralMessage(value) {
|
|
|
212
184
|
const candidate = value.id;
|
|
213
185
|
return isPluralMessage(candidate);
|
|
214
186
|
}
|
|
215
|
-
function resolveTranslationModule(module
|
|
216
|
-
return "default" in module
|
|
187
|
+
function resolveTranslationModule(module) {
|
|
188
|
+
return "default" in module ? module.default : module;
|
|
217
189
|
}
|
|
218
190
|
var LocaleTranslator = class {
|
|
219
191
|
locale;
|
|
@@ -222,52 +194,49 @@ var LocaleTranslator = class {
|
|
|
222
194
|
this.locale = locale;
|
|
223
195
|
this.translations = translations ? normalizeTranslations(translations) : void 0;
|
|
224
196
|
}
|
|
225
|
-
resolveMessage = (message
|
|
226
|
-
const entry = this.translations?.translations?.[context
|
|
227
|
-
|
|
228
|
-
return applyValues(template, message$1);
|
|
197
|
+
resolveMessage = (message, context = "") => {
|
|
198
|
+
const entry = this.translations?.translations?.[context]?.[message.msgid];
|
|
199
|
+
return applyValues(selectTemplate(entry?.msgstr?.[0], message.msgstr), message);
|
|
229
200
|
};
|
|
230
|
-
resolvePluralForm = (message
|
|
231
|
-
const entry = this.translations?.translations?.[context
|
|
232
|
-
const index = pluralFunc(this.locale)(message
|
|
233
|
-
const forms = message
|
|
201
|
+
resolvePluralForm = (message, context = "") => {
|
|
202
|
+
const entry = this.translations?.translations?.[context]?.[message.forms[0].msgid];
|
|
203
|
+
const index = pluralFunc(this.locale)(message.n);
|
|
204
|
+
const forms = message.forms;
|
|
234
205
|
const selectedForm = forms[index] ?? forms[forms.length - 1];
|
|
235
206
|
const translatedForms = entry?.msgstr;
|
|
236
|
-
|
|
237
|
-
const template = selectTemplate(templateCandidate, selectedForm.msgstr);
|
|
238
|
-
return applyValues(template, selectedForm, forms[0]);
|
|
207
|
+
return applyValues(selectTemplate(translatedForms?.length ? translatedForms[index] ?? translatedForms[translatedForms.length - 1] : void 0, selectedForm.msgstr), selectedForm, forms[0]);
|
|
239
208
|
};
|
|
240
|
-
translateValue = (message
|
|
241
|
-
if (isContextPluralMessage(message
|
|
242
|
-
if (isContextMessage(message
|
|
243
|
-
if (isPluralMessage(message
|
|
244
|
-
return this.resolveMessage(message
|
|
209
|
+
translateValue = (message) => {
|
|
210
|
+
if (isContextPluralMessage(message)) return this.resolvePluralForm(message.id, message.context);
|
|
211
|
+
if (isContextMessage(message)) return this.resolveMessage(message.id, message.context);
|
|
212
|
+
if (isPluralMessage(message)) return this.resolvePluralForm(message);
|
|
213
|
+
return this.resolveMessage(message);
|
|
245
214
|
};
|
|
246
|
-
translateMessage = (args, context
|
|
215
|
+
translateMessage = (args, context) => {
|
|
247
216
|
const message$1 = message(...args);
|
|
248
|
-
return this.resolveMessage(message$1, context
|
|
217
|
+
return this.resolveMessage(message$1, context);
|
|
249
218
|
};
|
|
250
|
-
translatePlural = (args, context
|
|
251
|
-
const message
|
|
252
|
-
return this.resolvePluralForm(message
|
|
219
|
+
translatePlural = (args, context) => {
|
|
220
|
+
const message = plural(...args);
|
|
221
|
+
return this.resolvePluralForm(message, context);
|
|
253
222
|
};
|
|
254
|
-
translate = (message
|
|
255
|
-
return this.translateValue(message
|
|
223
|
+
translate = (message) => {
|
|
224
|
+
return this.translateValue(message);
|
|
256
225
|
};
|
|
257
226
|
message = (...args) => this.translateMessage(args);
|
|
258
227
|
plural = (...args) => this.translatePlural(args);
|
|
259
228
|
context = (...args) => {
|
|
260
229
|
const [source] = args;
|
|
261
|
-
const context
|
|
230
|
+
const context = typeof source === "string" ? source : source[0];
|
|
262
231
|
return {
|
|
263
|
-
message: (...args
|
|
264
|
-
plural: (...args
|
|
232
|
+
message: (...args) => this.translateMessage(args, context),
|
|
233
|
+
plural: (...args) => this.translatePlural(args, context)
|
|
265
234
|
};
|
|
266
235
|
};
|
|
267
236
|
gettext = (...args) => this.message(...args);
|
|
268
237
|
ngettext = (...args) => this.plural(...args);
|
|
269
|
-
pgettext = (context
|
|
270
|
-
npgettext = (context
|
|
238
|
+
pgettext = (context, ...args) => this.translateMessage(args, context);
|
|
239
|
+
npgettext = (context, ...args) => this.translatePlural(args, context);
|
|
271
240
|
};
|
|
272
241
|
var Translator = class {
|
|
273
242
|
parent;
|
|
@@ -327,7 +296,6 @@ var Translator = class {
|
|
|
327
296
|
return this.getLocale(key);
|
|
328
297
|
};
|
|
329
298
|
};
|
|
330
|
-
|
|
331
299
|
//#endregion
|
|
332
300
|
exports.LocaleTranslator = LocaleTranslator;
|
|
333
301
|
exports.Translator = Translator;
|
|
@@ -340,4 +308,4 @@ exports.normalizeMessageId = normalizeMessageId;
|
|
|
340
308
|
exports.normalizeTranslations = normalizeTranslations;
|
|
341
309
|
exports.plural = plural;
|
|
342
310
|
exports.pluralFunc = pluralFunc;
|
|
343
|
-
exports.substitute = substitute;
|
|
311
|
+
exports.substitute = substitute;
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/locales.ts","../src/config.ts","../src/utils.ts","../src/messages.ts","../src/translator.ts"],"
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/locales.ts","../src/config.ts","../src/utils.ts","../src/messages.ts","../src/translator.ts"],"mappings":";;;KAAY,iBAAA;;;KCEP,iBAAA;;ADFL;;;ECOI,aAAA,EAAe,iBAAA;EDPU;;;;ECYzB,OAAA,EAAS,iBAAA;EAVS;;;;EAelB,QAAA,GAAW,OAAA,CAAQ,MAAA,CAAO,iBAAA,EAAmB,iBAAA;AAAA;;;;;;;UAShC,aAAA,SAAsB,iBAAiB;;;;;KAQ5C,MAAA,GAAS,aAAa;;;KC7BtB,OAAA,QAAe,CAAA,KAAM,CAAA,gBAAiB,CAAA,EAAG,CAAA,0BAA0B,CAAA,EAAG,CAAA;AAAA,KAEtE,kBAAA,oCAAsD,CAAA,WAAY,OAAA,CAAQ,CAAA,yBAA0B,CAAA;AAAA,iBAEhG,MAAA,IAAU,KAAA,EAAO,CAAA,EAAG,OAAA,oBAA2B,KAAA,IAAS,CAAC;AAAA,iBAMzD,IAAA,eAAmB,IAAA,iBAAqB,EAAA,EAAI,CAAA,GAAI,CAAC;AAAA,iBAajD,UAAA,CAAW,IAAA,UAAc,MAAsB;AAAA,iBAmB/C,kBAAA,CAAmB,KAAa;AAAA,iBAgBhC,qBAAA,CAAsB,YAAA,EAAc,mBAAA,GAAsB,mBAAmB;AAAA,cAmBhF,UAAA,GAAU,MAAA,EAAoC,MAAM,MAAA,CAAA;AAAA,iBAmBjD,iBAAA,CACZ,OAAA,EAAS,mBAAA,KACN,MAAA,GAAS,mBAAA,kBACb,mBAAA;;;UCtGc,iBAAA;EACb,EAAA;EACA,OAAO;AAAA;AAAA,UAGM,OAAA;EACb,KAAA;EACA,MAAA;EACA,MAAA;AAAA;AAAA,UAGa,aAAA;EACb,KAAA,EAAO,OAAO;EACd,CAAA;AAAA;AAAA,UAGa,cAAA;EACb,OAAA;EACA,EAAA,EAAI,OAAO;AAAA;AAAA,UAGE,oBAAA;EACb,OAAA;EACA,EAAA,EAAI,aAAa;AAAA;AAAA,KAYT,WAAA,sBACL,EAAA,EAAI,kBAAA,CAAmB,CAAA,MACvB,UAAA,EAAY,iBAAA,KACZ,OAAA,EAAS,oBAAA,KAAyB,MAAA;AAAA,KAE7B,eAAA,yBAAwC,IAAA,EAAM,WAAA,CAAY,CAAA,MAAO,OAAA;AAAA,iBAE7D,OAAA,sBAA6B,IAAA,EAAM,WAAA,CAAY,CAAA,IAAK,OAAA;AAAA,KAiBxD,UAAA,OAAiB,KAAA,EAAO,OAAO,IAAI,CAAA;AAAA,iBAE/B,MAAA,IAAU,IAAA,EAAM,UAAA,GAAa,aAAa;AAAA,KAW9C,cAAA,OAAqB,IAAA,EAAM,UAAA,KAAe,aAAa;AAAA,KACvD,YAAA,+BAA2C,OAAA,IAAW,WAAA,CAAY,CAAA;AAAA,KAClE,WAAA,IAAe,aAAA,IAAiB,UAAU;AAAA,KAE1C,sBAAA,yBAA+C,IAAA,EAAM,WAAA,CAAY,CAAA,MAAO,cAAA;AAAA,KAExE,qBAAA,OAA4B,IAAA,EAAM,UAAA,KAAe,oBAAoB;AAAA,UAEhE,cAAA;EACb,OAAA,EAAS,sBAAA;EACT,MAAA,EAAQ,qBAAqB;AAAA;AAAA,iBAMjB,OAAA,mBAA0B,OAAA,EAAS,kBAAA,CAAmB,CAAA,IAAK,cAAA;AAAA,iBAC3D,OAAA,CAAQ,OAAA,EAAS,oBAAA,KAAyB,MAAA,YAAkB,cAAc;;;KC5ErF,iBAAA,GAAoB,mBAAA;EAAwB,OAAA,EAAS,mBAAmB;AAAA;AAAA,KACxE,iBAAA,SAA0B,OAAO,CAAC,iBAAA;AAAA,KAClC,gBAAA,GAAmB,iBAAA,GAAoB,OAAA,CAAQ,iBAAA,IAAqB,iBAAA;AAAA,KACpE,iBAAA,GAAoB,OAAA,CAAQ,MAAA,CAAO,MAAA,EAAQ,gBAAA;AAAA,KAC3C,cAAA,oBACW,CAAA,GAAI,CAAA,CAAE,CAAA,UAAW,mBAAA,GAAsB,CAAA,iBAC/C,CAAA;AAAA,KAuCH,qBAAA,GAAwB,OAAA,GAAU,aAAA,GAAgB,cAAA,GAAiB,oBAAA;AAAA,cAM3D,gBAAA;EACT,MAAA,EAAQ,MAAA;EACR,YAAA,GAAe,mBAAA;cAEH,MAAA,EAAQ,MAAA,EAAQ,YAAA,GAAe,mBAAA;EAK3C,cAAA,GAAkB,OAAA,EAAS,OAAA,EAAS,OAAA;EAMpC,iBAAA,GAAqB,OAAA,EAAS,aAAA,EAAe,OAAA;EAa7C,cAAA,GAAkB,OAAA,EAAS,qBAAA;EAgB3B,gBAAA,qBAAsC,IAAA,EAAM,WAAA,CAAY,CAAA,GAAI,OAAA;EAK5D,eAAA,GAAmB,IAAA,EAAM,UAAA,EAAY,OAAA;EAKrC,SAAA,GAAa,OAAA,EAAS,OAAA,GAAU,aAAA,GAAgB,cAAA,GAAiB,oBAAA;EAIjE,OAAA,wBAAgC,IAAA,EAAM,WAAA,CAAY,CAAA;EAClD,MAAA,MAAa,IAAA,EAAM,UAAA;EAEnB,OAAA,wBAAgC,IAAA,GAAO,kBAAA,CAAmB,CAAA,MAAO,oBAAA;mCAM/B,IAAA,EAAW,WAAA,CAAY,CAAA;sBAC/B,UAAA;EAAA;EAI1B,OAAA,wBAAgC,IAAA,EAAM,WAAA,CAAY,CAAA;EAClD,QAAA,MAAe,IAAA,EAAM,UAAA;EACrB,QAAA,uCAAgD,OAAA,EAAS,kBAAA,CAAmB,CAAA,MAAO,IAAA,EAAM,WAAA,CAAY,CAAA;EAErG,SAAA,qBAA+B,OAAA,EAAS,kBAAA,CAAmB,CAAA,MAAO,IAAA,EAAM,UAAA;AAAA;AAAA,cAI/D,UAAA,WAAqB,iBAAA,GAAoB,iBAAA;EAClD,MAAA,EAAQ,UAAA;EACR,OAAA,EAAS,OAAA,CAAQ,MAAA,CAAO,MAAA,EAAQ,iBAAA;EAChC,YAAA,EAAc,OAAA,CAAQ,MAAA,CAAO,MAAA,EAAQ,mBAAA;EACrC,OAAA,EAAS,OAAA,CAAQ,MAAA,CAAO,MAAA,EAAQ,OAAA,CAAQ,gBAAA;EACxC,WAAA,EAAa,OAAA,CAAQ,MAAA,CAAO,MAAA,EAAQ,gBAAA;cAExB,YAAA,EAAc,CAAA,EAAG,MAAA,GAAS,UAAA;EActC,UAAA,GAAoB,MAAA,EAAQ,MAAA,EAAQ,MAAA,GAAS,iBAAA,KAAoB,OAAA,CAAQ,gBAAA;EAMzE,SAAA,aAAuB,cAAA,CAAe,CAAA,GAAI,MAAA,EAAQ,CAAA,KAAI,gBAAA;EA8BtD,WAAA,mBAA+B,CAAA,EAAG,MAAA,EAAQ,CAAA,KAAC,gBAAA,GAAA,OAAA,CAAA,gBAAA;AAAA"}
|
|
@@ -127,4 +127,4 @@ declare class Translator<T extends TranslationRecord = TranslationRecord> {
|
|
|
127
127
|
}
|
|
128
128
|
//#endregion
|
|
129
129
|
export { Configuration, ContextBuilder, ContextMessage, ContextMessageFunction, ContextPluralFunction, ContextPluralMessage, IsUnion, Locale, LocaleTranslator, Message, MessageArgs, MessageDescriptor, MessageFunction, MessageInput, PluralArgs, type PluralFormsLocale, PluralFunction, PluralInput, PluralMessage, StrictStaticString, Translator, assert, context, memo, mergeTranslations, message, normalizeMessageId, normalizeTranslations, plural, pluralFunc, substitute };
|
|
130
|
-
//# sourceMappingURL=index.d.
|
|
130
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/locales.ts","../src/config.ts","../src/utils.ts","../src/messages.ts","../src/translator.ts"],"mappings":"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"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { getNPlurals, getPluralFunc } from "plural-forms";
|
|
2
|
-
|
|
3
2
|
//#region src/utils.ts
|
|
4
|
-
function assert(value, message
|
|
5
|
-
if (!value) throw new Error(message
|
|
3
|
+
function assert(value, message) {
|
|
4
|
+
if (!value) throw new Error(message || "Assertion failed");
|
|
6
5
|
}
|
|
7
6
|
function memo(fn) {
|
|
8
7
|
const cache = /* @__PURE__ */ new Map();
|
|
@@ -18,8 +17,8 @@ function substitute(text, values = []) {
|
|
|
18
17
|
const placeholders = [];
|
|
19
18
|
return text.replace(/\$\{([^}]+)\}/g, (match, placeholder) => {
|
|
20
19
|
if (/^\d+$/.test(placeholder)) {
|
|
21
|
-
const index
|
|
22
|
-
return index
|
|
20
|
+
const index = Number(placeholder);
|
|
21
|
+
return index < values.length ? String(values[index]) : match;
|
|
23
22
|
}
|
|
24
23
|
let index = placeholders.indexOf(placeholder);
|
|
25
24
|
if (index === -1) {
|
|
@@ -46,24 +45,24 @@ function normalizeTranslations(translations) {
|
|
|
46
45
|
...translations,
|
|
47
46
|
translations: {}
|
|
48
47
|
};
|
|
49
|
-
for (const [context
|
|
50
|
-
normalized.translations[context
|
|
48
|
+
for (const [context, messages] of Object.entries(translations.translations)) {
|
|
49
|
+
normalized.translations[context] = {};
|
|
51
50
|
for (const [msgid, entry] of Object.entries(messages)) {
|
|
52
51
|
const normalizedId = normalizeMessageId(msgid);
|
|
53
|
-
normalized.translations[context
|
|
52
|
+
normalized.translations[context][normalizedId] = entry;
|
|
54
53
|
}
|
|
55
54
|
}
|
|
56
55
|
return normalized;
|
|
57
56
|
}
|
|
58
57
|
const defaultPluralFunc = (n) => n !== 1 ? 1 : 0;
|
|
59
|
-
const pluralFunc = memo(function pluralFunc
|
|
58
|
+
const pluralFunc = memo(function pluralFunc(locale) {
|
|
60
59
|
try {
|
|
61
60
|
const length = Number(getNPlurals(locale));
|
|
62
61
|
if (length === 1) return () => 0;
|
|
63
|
-
const pluralFunc
|
|
62
|
+
const pluralFunc = getPluralFunc(locale);
|
|
64
63
|
const forms = Array.from({ length }, (_, i) => String(i));
|
|
65
64
|
return (n) => {
|
|
66
|
-
const idx = Number(pluralFunc
|
|
65
|
+
const idx = Number(pluralFunc(n, forms));
|
|
67
66
|
if (!Number.isFinite(idx) || idx < 0) return 0;
|
|
68
67
|
if (idx >= length) return length - 1;
|
|
69
68
|
return Math.floor(idx);
|
|
@@ -97,7 +96,6 @@ function mergeTranslations(primary, ...others) {
|
|
|
97
96
|
}
|
|
98
97
|
return result;
|
|
99
98
|
}
|
|
100
|
-
|
|
101
99
|
//#endregion
|
|
102
100
|
//#region src/messages.ts
|
|
103
101
|
function buildFromTemplate(strings) {
|
|
@@ -115,18 +113,16 @@ function message(...args) {
|
|
|
115
113
|
msgstr: source
|
|
116
114
|
};
|
|
117
115
|
if (typeof source === "object" && "reduce" in source) {
|
|
118
|
-
const id
|
|
116
|
+
const id = buildFromTemplate(source);
|
|
119
117
|
return {
|
|
120
|
-
msgid: id
|
|
121
|
-
msgstr: id
|
|
118
|
+
msgid: id,
|
|
119
|
+
msgstr: id,
|
|
122
120
|
values
|
|
123
121
|
};
|
|
124
122
|
}
|
|
125
|
-
const id = source.id ?? source.message ?? "";
|
|
126
|
-
const message$1 = source.message ?? source.id ?? "";
|
|
127
123
|
return {
|
|
128
|
-
msgid: id,
|
|
129
|
-
msgstr: message
|
|
124
|
+
msgid: source.id ?? source.message ?? "",
|
|
125
|
+
msgstr: source.message ?? source.id ?? ""
|
|
130
126
|
};
|
|
131
127
|
}
|
|
132
128
|
function plural(...args) {
|
|
@@ -143,36 +139,35 @@ const basePlural = plural;
|
|
|
143
139
|
function context(...args) {
|
|
144
140
|
const [source] = args;
|
|
145
141
|
const ctx = typeof source === "string" ? source : source[0];
|
|
146
|
-
function message
|
|
142
|
+
function message(...args) {
|
|
147
143
|
return {
|
|
148
|
-
id: baseMessage(...args
|
|
144
|
+
id: baseMessage(...args),
|
|
149
145
|
context: ctx
|
|
150
146
|
};
|
|
151
147
|
}
|
|
152
|
-
function plural
|
|
148
|
+
function plural(...forms) {
|
|
153
149
|
return {
|
|
154
150
|
id: basePlural(...forms),
|
|
155
151
|
context: ctx
|
|
156
152
|
};
|
|
157
153
|
}
|
|
158
154
|
return {
|
|
159
|
-
message
|
|
160
|
-
plural
|
|
155
|
+
message,
|
|
156
|
+
plural
|
|
161
157
|
};
|
|
162
158
|
}
|
|
163
|
-
|
|
164
159
|
//#endregion
|
|
165
160
|
//#region src/translator.ts
|
|
166
|
-
function selectValues(message
|
|
167
|
-
const values = message
|
|
161
|
+
function selectValues(message, fallback) {
|
|
162
|
+
const values = message?.values;
|
|
168
163
|
if (values?.length) return values;
|
|
169
164
|
return fallback?.values;
|
|
170
165
|
}
|
|
171
166
|
function selectTemplate(preferred, fallback) {
|
|
172
167
|
return preferred?.length ? preferred : fallback;
|
|
173
168
|
}
|
|
174
|
-
function applyValues(template, message
|
|
175
|
-
const values = selectValues(message
|
|
169
|
+
function applyValues(template, message, fallback) {
|
|
170
|
+
const values = selectValues(message, fallback);
|
|
176
171
|
return values?.length ? substitute(template, values) : template;
|
|
177
172
|
}
|
|
178
173
|
function isPluralMessage(value) {
|
|
@@ -198,52 +193,49 @@ var LocaleTranslator = class {
|
|
|
198
193
|
this.locale = locale;
|
|
199
194
|
this.translations = translations ? normalizeTranslations(translations) : void 0;
|
|
200
195
|
}
|
|
201
|
-
resolveMessage = (message
|
|
202
|
-
const entry = this.translations?.translations?.[context
|
|
203
|
-
|
|
204
|
-
return applyValues(template, message$1);
|
|
196
|
+
resolveMessage = (message, context = "") => {
|
|
197
|
+
const entry = this.translations?.translations?.[context]?.[message.msgid];
|
|
198
|
+
return applyValues(selectTemplate(entry?.msgstr?.[0], message.msgstr), message);
|
|
205
199
|
};
|
|
206
|
-
resolvePluralForm = (message
|
|
207
|
-
const entry = this.translations?.translations?.[context
|
|
208
|
-
const index = pluralFunc(this.locale)(message
|
|
209
|
-
const forms = message
|
|
200
|
+
resolvePluralForm = (message, context = "") => {
|
|
201
|
+
const entry = this.translations?.translations?.[context]?.[message.forms[0].msgid];
|
|
202
|
+
const index = pluralFunc(this.locale)(message.n);
|
|
203
|
+
const forms = message.forms;
|
|
210
204
|
const selectedForm = forms[index] ?? forms[forms.length - 1];
|
|
211
205
|
const translatedForms = entry?.msgstr;
|
|
212
|
-
|
|
213
|
-
const template = selectTemplate(templateCandidate, selectedForm.msgstr);
|
|
214
|
-
return applyValues(template, selectedForm, forms[0]);
|
|
206
|
+
return applyValues(selectTemplate(translatedForms?.length ? translatedForms[index] ?? translatedForms[translatedForms.length - 1] : void 0, selectedForm.msgstr), selectedForm, forms[0]);
|
|
215
207
|
};
|
|
216
|
-
translateValue = (message
|
|
217
|
-
if (isContextPluralMessage(message
|
|
218
|
-
if (isContextMessage(message
|
|
219
|
-
if (isPluralMessage(message
|
|
220
|
-
return this.resolveMessage(message
|
|
208
|
+
translateValue = (message) => {
|
|
209
|
+
if (isContextPluralMessage(message)) return this.resolvePluralForm(message.id, message.context);
|
|
210
|
+
if (isContextMessage(message)) return this.resolveMessage(message.id, message.context);
|
|
211
|
+
if (isPluralMessage(message)) return this.resolvePluralForm(message);
|
|
212
|
+
return this.resolveMessage(message);
|
|
221
213
|
};
|
|
222
|
-
translateMessage = (args, context
|
|
214
|
+
translateMessage = (args, context) => {
|
|
223
215
|
const message$1 = message(...args);
|
|
224
|
-
return this.resolveMessage(message$1, context
|
|
216
|
+
return this.resolveMessage(message$1, context);
|
|
225
217
|
};
|
|
226
|
-
translatePlural = (args, context
|
|
227
|
-
const message
|
|
228
|
-
return this.resolvePluralForm(message
|
|
218
|
+
translatePlural = (args, context) => {
|
|
219
|
+
const message = plural(...args);
|
|
220
|
+
return this.resolvePluralForm(message, context);
|
|
229
221
|
};
|
|
230
|
-
translate = (message
|
|
231
|
-
return this.translateValue(message
|
|
222
|
+
translate = (message) => {
|
|
223
|
+
return this.translateValue(message);
|
|
232
224
|
};
|
|
233
225
|
message = (...args) => this.translateMessage(args);
|
|
234
226
|
plural = (...args) => this.translatePlural(args);
|
|
235
227
|
context = (...args) => {
|
|
236
228
|
const [source] = args;
|
|
237
|
-
const context
|
|
229
|
+
const context = typeof source === "string" ? source : source[0];
|
|
238
230
|
return {
|
|
239
|
-
message: (...args
|
|
240
|
-
plural: (...args
|
|
231
|
+
message: (...args) => this.translateMessage(args, context),
|
|
232
|
+
plural: (...args) => this.translatePlural(args, context)
|
|
241
233
|
};
|
|
242
234
|
};
|
|
243
235
|
gettext = (...args) => this.message(...args);
|
|
244
236
|
ngettext = (...args) => this.plural(...args);
|
|
245
|
-
pgettext = (context
|
|
246
|
-
npgettext = (context
|
|
237
|
+
pgettext = (context, ...args) => this.translateMessage(args, context);
|
|
238
|
+
npgettext = (context, ...args) => this.translatePlural(args, context);
|
|
247
239
|
};
|
|
248
240
|
var Translator = class {
|
|
249
241
|
parent;
|
|
@@ -303,7 +295,7 @@ var Translator = class {
|
|
|
303
295
|
return this.getLocale(key);
|
|
304
296
|
};
|
|
305
297
|
};
|
|
306
|
-
|
|
307
298
|
//#endregion
|
|
308
299
|
export { LocaleTranslator, Translator, assert, context, memo, mergeTranslations, message, normalizeMessageId, normalizeTranslations, plural, pluralFunc, substitute };
|
|
309
|
-
|
|
300
|
+
|
|
301
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["message","buildMessage","buildPlural"],"sources":["../src/utils.ts","../src/messages.ts","../src/translator.ts"],"sourcesContent":["import type { GetTextTranslationRecord, GetTextTranslations } from \"gettext-parser\";\nimport { getNPlurals, getPluralFunc } from \"plural-forms\";\n\nimport type { Locale } from \"./config.ts\";\n\nexport type IsUnion<T, U = T> = (T extends any ? (x: T) => 0 : never) extends (x: U) => 0 ? false : true;\n\nexport type StrictStaticString<T extends string> = string extends T ? never : IsUnion<T> extends true ? never : T;\n\nexport function assert<T>(value: T, message?: string): asserts value is T {\n if (!value) {\n throw new Error(message || \"Assertion failed\");\n }\n}\n\nexport function memo<T extends (...args: any[]) => any>(fn: T): T {\n const cache = new Map<string, ReturnType<T>>();\n return ((...args: Parameters<T>): ReturnType<T> => {\n const key = JSON.stringify(args);\n if (cache.has(key)) {\n return cache.get(key)!;\n }\n const result = fn(...args);\n cache.set(key, result);\n return result;\n }) as T;\n}\n\nexport function substitute(text: string, values: unknown[] = []): string {\n const placeholders: string[] = [];\n\n return text.replace(/\\$\\{([^}]+)\\}/g, (match, placeholder) => {\n if (/^\\d+$/.test(placeholder)) {\n const index = Number(placeholder);\n return index < values.length ? String(values[index]) : match;\n }\n\n let index = placeholders.indexOf(placeholder);\n if (index === -1) {\n index = placeholders.length;\n placeholders.push(placeholder);\n }\n\n return index < values.length ? String(values[index]) : match;\n });\n}\n\nexport function normalizeMessageId(msgid: string): string {\n const placeholders: string[] = [];\n return msgid.replace(/\\$\\{([^}]+)\\}/g, (match, placeholder) => {\n if (/^\\d+$/.test(placeholder)) {\n return match;\n }\n\n let index = placeholders.indexOf(placeholder);\n if (index === -1) {\n index = placeholders.length;\n placeholders.push(placeholder);\n }\n return `\\${${index}}`;\n });\n}\n\nexport function normalizeTranslations(translations: GetTextTranslations): GetTextTranslations {\n const normalized: GetTextTranslations = {\n ...translations,\n translations: {},\n };\n\n for (const [context, messages] of Object.entries(translations.translations)) {\n normalized.translations[context] = {};\n for (const [msgid, entry] of Object.entries(messages)) {\n const normalizedId = normalizeMessageId(msgid);\n normalized.translations[context][normalizedId] = entry;\n }\n }\n\n return normalized;\n}\n\nconst defaultPluralFunc = (n: number) => (n !== 1 ? 1 : 0);\n\nexport const pluralFunc = memo(function pluralFunc(locale: Locale) {\n try {\n const length = Number(getNPlurals(locale));\n if (length === 1) {\n return () => 0;\n }\n const pluralFunc = getPluralFunc(locale);\n const forms = Array.from({ length }, (_, i) => String(i));\n return (n: number) => {\n const idx = Number(pluralFunc(n, forms));\n if (!Number.isFinite(idx) || idx < 0) return 0;\n if (idx >= length) return length - 1;\n return Math.floor(idx);\n };\n } catch {\n return defaultPluralFunc;\n }\n});\n\nexport function mergeTranslations(\n primary: GetTextTranslations,\n ...others: (GetTextTranslations | undefined)[]\n): GetTextTranslations {\n function mergeRecords(target: GetTextTranslationRecord, source: GetTextTranslationRecord): void {\n for (const ctx in source) {\n if (!target[ctx]) {\n target[ctx] = source[ctx];\n continue;\n }\n\n const targetContext = target[ctx];\n const sourceContext = source[ctx];\n for (const id in sourceContext) {\n if (!targetContext[id]) {\n targetContext[id] = sourceContext[id];\n }\n }\n }\n }\n\n const result: GetTextTranslations = {\n charset: primary.charset,\n headers: { ...primary.headers },\n translations: { ...primary.translations },\n obsolete: primary.obsolete ? { ...primary.obsolete } : undefined,\n };\n\n for (const other of others) {\n if (other?.translations) {\n mergeRecords(result.translations, other.translations);\n }\n\n if (other?.obsolete) {\n if (!result.obsolete) {\n result.obsolete = other.obsolete;\n } else {\n mergeRecords(result.obsolete, other.obsolete);\n }\n }\n }\n\n return result;\n}\n","import { assert, type StrictStaticString } from \"./utils.ts\";\n\nexport interface MessageDescriptor {\n id?: string;\n message?: string;\n}\n\nexport interface Message {\n msgid: string;\n msgstr: string;\n values?: any[];\n}\n\nexport interface PluralMessage {\n forms: Message[];\n n: number;\n}\n\nexport interface ContextMessage {\n context: string;\n id: Message;\n}\n\nexport interface ContextPluralMessage {\n context: string;\n id: PluralMessage;\n}\n\nfunction buildFromTemplate(strings: TemplateStringsArray): string {\n let result = \"\";\n for (let i = 0; i < strings.length; i++) {\n result += strings[i];\n if (i < strings.length - 1) result += `\\${${i}}`;\n }\n return result;\n}\n\nexport type MessageArgs<T extends string> =\n | [id: StrictStaticString<T>]\n | [descriptor: MessageDescriptor]\n | [strings: TemplateStringsArray, ...values: unknown[]];\n\nexport type MessageFunction = <T extends string>(...args: MessageArgs<T>) => Message;\n\nexport function message<T extends string>(...args: MessageArgs<T>): Message {\n const [source, ...values] = args as [MessageDescriptor | TemplateStringsArray, ...unknown[]];\n\n if (typeof source === \"string\") {\n return { msgid: source, msgstr: source };\n }\n\n if (typeof source === \"object\" && \"reduce\" in source) {\n const id = buildFromTemplate(source);\n return { msgid: id, msgstr: id, values };\n }\n\n const id = source.id ?? source.message ?? \"\";\n const message = source.message ?? source.id ?? \"\";\n return { msgid: id, msgstr: message };\n}\n\nexport type PluralArgs = [...forms: Message[], n: number];\n\nexport function plural(...args: PluralArgs): PluralMessage {\n assert(args.length > 1, \"At least one plural form and n are required\");\n\n const n = args[args.length - 1] as number;\n assert(typeof n === \"number\", \"The last argument must be a number\");\n\n const forms = args.slice(0, -1) as Message[];\n\n return { forms, n };\n}\n\nexport type PluralFunction = (...args: PluralArgs) => PluralMessage;\nexport type MessageInput<T extends string = string> = [Message] | MessageArgs<T>;\nexport type PluralInput = [PluralMessage] | PluralArgs;\n\nexport type ContextMessageFunction = <T extends string>(...args: MessageArgs<T>) => ContextMessage;\n\nexport type ContextPluralFunction = (...args: PluralArgs) => ContextPluralMessage;\n\nexport interface ContextBuilder {\n message: ContextMessageFunction;\n plural: ContextPluralFunction;\n}\n\nconst baseMessage = message;\nconst basePlural = plural;\n\nexport function context<T extends string>(context: StrictStaticString<T>): ContextBuilder;\nexport function context(strings: TemplateStringsArray, ...values: never[]): ContextBuilder;\nexport function context<T extends string>(\n ...args: [StrictStaticString<T>] | [TemplateStringsArray, ...never[]]\n): ContextBuilder {\n const [source] = args as [StrictStaticString<T> | TemplateStringsArray];\n\n const ctx = typeof source === \"string\" ? source : source[0];\n\n function message<T extends string>(...args: MessageArgs<T>): ContextMessage {\n return { id: baseMessage(...args), context: ctx };\n }\n\n function plural(...forms: PluralArgs): ContextPluralMessage {\n return { id: basePlural(...forms), context: ctx };\n }\n\n return {\n message,\n plural,\n };\n}\n","import type { GetTextTranslations } from \"gettext-parser\";\nimport type { Locale } from \"./config.ts\";\n\nimport {\n message as buildMessage,\n plural as buildPlural,\n type ContextMessage,\n type ContextPluralMessage,\n type Message,\n type MessageArgs,\n type PluralArgs,\n type PluralMessage,\n} from \"./messages.ts\";\nimport { mergeTranslations, normalizeTranslations, pluralFunc, type StrictStaticString, substitute } from \"./utils.ts\";\n\ntype TranslationModule = GetTextTranslations | { default: GetTextTranslations };\ntype TranslationLoader = () => Promise<TranslationModule>;\ntype TranslationEntry = TranslationModule | Promise<TranslationModule> | TranslationLoader;\ntype TranslationRecord = Partial<Record<Locale, TranslationEntry>>;\ntype SyncLocaleKeys<T> = {\n [K in keyof T]: T[K] extends GetTextTranslations ? K : never;\n}[keyof T];\n\nfunction selectValues(message: Message | undefined, fallback?: Message): unknown[] | undefined {\n const values = message?.values;\n if (values?.length) {\n return values;\n }\n return fallback?.values;\n}\n\nfunction selectTemplate(preferred: string | undefined, fallback: string): string {\n return preferred?.length ? preferred : fallback;\n}\n\nfunction applyValues(template: string, message: Message | undefined, fallback?: Message): string {\n const values = selectValues(message, fallback);\n return values?.length ? substitute(template, values) : template;\n}\n\nfunction isPluralMessage(value: unknown): value is PluralMessage {\n return Boolean(value) && typeof value === \"object\" && \"forms\" in (value as PluralMessage);\n}\n\nfunction isContextMessage(value: unknown): value is ContextMessage {\n if (!value || typeof value !== \"object\" || !(\"id\" in value)) {\n return false;\n }\n const candidate = (value as ContextMessage).id;\n return !isPluralMessage(candidate);\n}\n\nfunction isContextPluralMessage(value: unknown): value is ContextPluralMessage {\n if (!value || typeof value !== \"object\" || !(\"id\" in value)) {\n return false;\n }\n const candidate = (value as ContextPluralMessage).id;\n return isPluralMessage(candidate);\n}\n\ntype AnyTranslationMessage = Message | PluralMessage | ContextMessage | ContextPluralMessage;\n\nfunction resolveTranslationModule(module: TranslationModule): GetTextTranslations {\n return \"default\" in module ? module.default : module;\n}\n\nexport class LocaleTranslator {\n locale: Locale;\n translations?: GetTextTranslations;\n\n constructor(locale: Locale, translations?: GetTextTranslations) {\n this.locale = locale;\n this.translations = translations ? normalizeTranslations(translations) : undefined;\n }\n\n resolveMessage = (message: Message, context = \"\"): string => {\n const entry = this.translations?.translations?.[context]?.[message.msgid];\n const template = selectTemplate(entry?.msgstr?.[0], message.msgstr);\n return applyValues(template, message);\n };\n\n resolvePluralForm = (message: PluralMessage, context = \"\"): string => {\n const entry = this.translations?.translations?.[context]?.[message.forms[0].msgid];\n const index = pluralFunc(this.locale)(message.n);\n const forms = message.forms;\n const selectedForm = forms[index] ?? forms[forms.length - 1];\n const translatedForms = entry?.msgstr;\n const templateCandidate = translatedForms?.length\n ? (translatedForms[index] ?? translatedForms[translatedForms.length - 1])\n : undefined;\n const template = selectTemplate(templateCandidate, selectedForm.msgstr);\n return applyValues(template, selectedForm, forms[0]);\n };\n\n translateValue = (message: AnyTranslationMessage): string => {\n if (isContextPluralMessage(message)) {\n return this.resolvePluralForm(message.id, message.context);\n }\n\n if (isContextMessage(message)) {\n return this.resolveMessage(message.id, message.context);\n }\n\n if (isPluralMessage(message)) {\n return this.resolvePluralForm(message);\n }\n\n return this.resolveMessage(message);\n };\n\n translateMessage = <T extends string>(args: MessageArgs<T>, context?: string): string => {\n const message = buildMessage(...args);\n return this.resolveMessage(message, context);\n };\n\n translatePlural = (args: PluralArgs, context?: string): string => {\n const message = buildPlural(...args);\n return this.resolvePluralForm(message, context);\n };\n\n translate = (message: Message | PluralMessage | ContextMessage | ContextPluralMessage): string => {\n return this.translateValue(message);\n };\n\n message = <T extends string>(...args: MessageArgs<T>): string => this.translateMessage(args);\n plural = (...args: PluralArgs): string => this.translatePlural(args);\n\n context = <T extends string>(...args: [StrictStaticString<T>] | [TemplateStringsArray, ...never[]]) => {\n const [source] = args as [StrictStaticString<T> | TemplateStringsArray];\n\n const context = typeof source === \"string\" ? source : source[0];\n\n return {\n message: <U extends string>(...args: MessageArgs<U>): string => this.translateMessage(args, context),\n plural: (...args: PluralArgs): string => this.translatePlural(args, context),\n };\n };\n\n gettext = <T extends string>(...args: MessageArgs<T>): string => this.message(...args);\n ngettext = (...args: PluralArgs): string => this.plural(...args);\n pgettext = <C extends string, T extends string>(context: StrictStaticString<C>, ...args: MessageArgs<T>): string =>\n this.translateMessage(args, context);\n npgettext = <C extends string>(context: StrictStaticString<C>, ...args: PluralArgs): string =>\n this.translatePlural(args, context);\n}\n\nexport class Translator<T extends TranslationRecord = TranslationRecord> {\n parent: Translator | undefined;\n loaders: Partial<Record<Locale, TranslationLoader>> = {};\n translations: Partial<Record<Locale, GetTextTranslations>> = {};\n pending: Partial<Record<Locale, Promise<LocaleTranslator>>> = {};\n translators: Partial<Record<Locale, LocaleTranslator>> = {};\n\n constructor(translations: T, parent?: Translator) {\n this.parent = parent;\n for (const [locale, value] of Object.entries(translations) as [Locale, TranslationEntry][]) {\n if (!value) continue;\n if (typeof value === \"function\") {\n this.loaders[locale] = value;\n } else if (\"then\" in value) {\n this.loaders[locale] = () => value;\n } else {\n this.translations[locale] = resolveTranslationModule(value);\n }\n }\n }\n\n loadLocale = async (locale: Locale, loader?: TranslationLoader): Promise<LocaleTranslator> => {\n this.loaders[locale] = loader ?? this.loaders[locale];\n\n return this.fetchLocale(locale as never);\n };\n\n getLocale = <L extends SyncLocaleKeys<T>>(locale: L): LocaleTranslator => {\n const key = locale as Locale;\n const existing = this.translators[key];\n if (existing) {\n return existing;\n }\n\n const base = this.translations[key];\n if (base) {\n const parentTranslations = this.parent?.getLocale(locale as never)?.translations;\n const translations = mergeTranslations(base, parentTranslations);\n delete this.translations[key];\n\n const translator = new LocaleTranslator(key, translations);\n this.translators[key] = translator;\n return translator;\n }\n\n if (this.pending[key] || this.loaders[key]) {\n console.warn(\n `Translator.getLocale(${key}) called before async locale resolved. Returning untranslated fallback.`,\n );\n this.translators[key] ??= new LocaleTranslator(key);\n return this.translators[key];\n }\n\n this.translators[key] ??= new LocaleTranslator(key);\n return this.translators[key];\n };\n\n fetchLocale = <L extends keyof T>(locale: L) => {\n const key = locale as Locale;\n\n const pending = this.pending[key];\n if (pending) {\n return pending;\n }\n\n const loader = this.loaders[key];\n if (loader) {\n const promise = loader().then((translations) => {\n this.translations[key] ??= resolveTranslationModule(translations);\n delete this.pending[key];\n\n return this.getLocale(key as never);\n });\n this.pending[key] = promise;\n delete this.loaders[key];\n\n return promise;\n }\n\n return this.getLocale(key as never);\n };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,35 +1,40 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
2
|
+
"name": "@let-value/translate",
|
|
3
|
+
"version": "1.1.6-beta.1",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "https://github.com/let-value/translate"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"type": "module",
|
|
12
|
+
"main": "dist/index.cjs",
|
|
13
|
+
"module": "dist/index.mjs",
|
|
14
|
+
"types": "dist/index.d.mts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.mts",
|
|
18
|
+
"import": "./dist/index.mjs",
|
|
19
|
+
"require": "./dist/index.cjs"
|
|
15
20
|
},
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
21
|
+
"./package.json": "./package.json"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"plural-forms": "0.5.5"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/gettext-parser": "9.0.0",
|
|
28
|
+
"gettext-parser": "9.0.2",
|
|
29
|
+
"typescript": "6.0.3",
|
|
30
|
+
"vite-plus": "latest"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "vp pack",
|
|
34
|
+
"pretest": "pnpm run build",
|
|
35
|
+
"check": "vp check",
|
|
36
|
+
"format": "vp fmt",
|
|
37
|
+
"typecheck": "tsc --build",
|
|
38
|
+
"test": "vp test"
|
|
39
|
+
}
|
|
40
|
+
}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/locales.ts","../src/config.ts","../src/utils.ts","../src/messages.ts","../src/translator.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["message","placeholders: string[]","index","normalized: GetTextTranslations","context","pluralFunc","result: GetTextTranslations","id","message","args","plural","message","context","buildMessage","buildPlural","args"],"sources":["../src/utils.ts","../src/messages.ts","../src/translator.ts"],"sourcesContent":["import type { GetTextTranslationRecord, GetTextTranslations } from \"gettext-parser\";\nimport { getNPlurals, getPluralFunc } from \"plural-forms\";\n\nimport type { Locale } from \"./config.ts\";\n\n// biome-ignore lint/suspicious/noExplicitAny: true\nexport type IsUnion<T, U = T> = (T extends any ? (x: T) => 0 : never) extends (x: U) => 0 ? false : true;\n\nexport type StrictStaticString<T extends string> = string extends T ? never : IsUnion<T> extends true ? never : T;\n\nexport function assert<T>(value: T, message?: string): asserts value is T {\n if (!value) {\n throw new Error(message || \"Assertion failed\");\n }\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: true\nexport function memo<T extends (...args: any[]) => any>(fn: T): T {\n const cache = new Map<string, ReturnType<T>>();\n return ((...args: Parameters<T>): ReturnType<T> => {\n const key = JSON.stringify(args);\n if (cache.has(key)) {\n // biome-ignore lint/style/noNonNullAssertion: true\n return cache.get(key)!;\n }\n const result = fn(...args);\n cache.set(key, result);\n return result;\n }) as T;\n}\n\nexport function substitute(text: string, values: unknown[] = []): string {\n const placeholders: string[] = [];\n\n return text.replace(/\\$\\{([^}]+)\\}/g, (match, placeholder) => {\n if (/^\\d+$/.test(placeholder)) {\n const index = Number(placeholder);\n return index < values.length ? String(values[index]) : match;\n }\n\n let index = placeholders.indexOf(placeholder);\n if (index === -1) {\n index = placeholders.length;\n placeholders.push(placeholder);\n }\n\n return index < values.length ? String(values[index]) : match;\n });\n}\n\nexport function normalizeMessageId(msgid: string): string {\n const placeholders: string[] = [];\n return msgid.replace(/\\$\\{([^}]+)\\}/g, (match, placeholder) => {\n if (/^\\d+$/.test(placeholder)) {\n return match;\n }\n\n let index = placeholders.indexOf(placeholder);\n if (index === -1) {\n index = placeholders.length;\n placeholders.push(placeholder);\n }\n return `\\${${index}}`;\n });\n}\n\nexport function normalizeTranslations(translations: GetTextTranslations): GetTextTranslations {\n const normalized: GetTextTranslations = {\n ...translations,\n translations: {},\n };\n\n for (const [context, messages] of Object.entries(translations.translations)) {\n normalized.translations[context] = {};\n for (const [msgid, entry] of Object.entries(messages)) {\n const normalizedId = normalizeMessageId(msgid);\n normalized.translations[context][normalizedId] = entry;\n }\n }\n\n return normalized;\n}\n\nconst defaultPluralFunc = (n: number) => (n !== 1 ? 1 : 0);\n\nexport const pluralFunc = memo(function pluralFunc(locale: Locale) {\n try {\n const length = Number(getNPlurals(locale));\n if (length === 1) {\n return () => 0;\n }\n const pluralFunc = getPluralFunc(locale);\n const forms = Array.from({ length }, (_, i) => String(i));\n return (n: number) => {\n const idx = Number(pluralFunc(n, forms));\n if (!Number.isFinite(idx) || idx < 0) return 0;\n if (idx >= length) return length - 1;\n return Math.floor(idx);\n };\n } catch {\n return defaultPluralFunc;\n }\n});\n\nexport function mergeTranslations(\n primary: GetTextTranslations,\n ...others: (GetTextTranslations | undefined)[]\n): GetTextTranslations {\n function mergeRecords(target: GetTextTranslationRecord, source: GetTextTranslationRecord): void {\n for (const ctx in source) {\n if (!target[ctx]) {\n target[ctx] = source[ctx];\n continue;\n }\n\n const targetContext = target[ctx];\n const sourceContext = source[ctx];\n for (const id in sourceContext) {\n if (!targetContext[id]) {\n targetContext[id] = sourceContext[id];\n }\n }\n }\n }\n\n const result: GetTextTranslations = {\n charset: primary.charset,\n headers: { ...primary.headers },\n translations: { ...primary.translations },\n obsolete: primary.obsolete ? { ...primary.obsolete } : undefined,\n };\n\n for (const other of others) {\n if (other?.translations) {\n mergeRecords(result.translations, other.translations);\n }\n\n if (other?.obsolete) {\n if (!result.obsolete) {\n result.obsolete = other.obsolete;\n } else {\n mergeRecords(result.obsolete, other.obsolete);\n }\n }\n }\n\n return result;\n}\n","import { assert, type StrictStaticString } from \"./utils.ts\";\n\nexport interface MessageDescriptor {\n id?: string;\n message?: string;\n}\n\nexport interface Message {\n msgid: string;\n msgstr: string;\n // biome-ignore lint/suspicious/noExplicitAny: true\n values?: any[];\n}\n\nexport interface PluralMessage {\n forms: Message[];\n n: number;\n}\n\nexport interface ContextMessage {\n context: string;\n id: Message;\n}\n\nexport interface ContextPluralMessage {\n context: string;\n id: PluralMessage;\n}\n\nfunction buildFromTemplate(strings: TemplateStringsArray): string {\n let result = \"\";\n for (let i = 0; i < strings.length; i++) {\n result += strings[i];\n if (i < strings.length - 1) result += `\\${${i}}`;\n }\n return result;\n}\n\nexport type MessageArgs<T extends string> =\n | [id: StrictStaticString<T>]\n | [descriptor: MessageDescriptor]\n | [strings: TemplateStringsArray, ...values: unknown[]];\n\nexport type MessageFunction = <T extends string>(...args: MessageArgs<T>) => Message;\n\nexport function message<T extends string>(...args: MessageArgs<T>): Message {\n const [source, ...values] = args as [MessageDescriptor | TemplateStringsArray, ...unknown[]];\n\n if (typeof source === \"string\") {\n return { msgid: source, msgstr: source };\n }\n\n if (typeof source === \"object\" && \"reduce\" in source) {\n const id = buildFromTemplate(source);\n return { msgid: id, msgstr: id, values };\n }\n\n const id = source.id ?? source.message ?? \"\";\n const message = source.message ?? source.id ?? \"\";\n return { msgid: id, msgstr: message };\n}\n\nexport type PluralArgs = [...forms: Message[], n: number];\n\nexport function plural(...args: PluralArgs): PluralMessage {\n assert(args.length > 1, \"At least one plural form and n are required\");\n\n const n = args[args.length - 1] as number;\n assert(typeof n === \"number\", \"The last argument must be a number\");\n\n const forms = args.slice(0, -1) as Message[];\n\n return { forms, n };\n}\n\nexport type PluralFunction = (...args: PluralArgs) => PluralMessage;\nexport type MessageInput<T extends string = string> = [Message] | MessageArgs<T>;\nexport type PluralInput = [PluralMessage] | PluralArgs;\n\nexport type ContextMessageFunction = <T extends string>(...args: MessageArgs<T>) => ContextMessage;\n\nexport type ContextPluralFunction = (...args: PluralArgs) => ContextPluralMessage;\n\nexport interface ContextBuilder {\n message: ContextMessageFunction;\n plural: ContextPluralFunction;\n}\n\nconst baseMessage = message;\nconst basePlural = plural;\n\nexport function context<T extends string>(context: StrictStaticString<T>): ContextBuilder;\nexport function context(strings: TemplateStringsArray, ...values: never[]): ContextBuilder;\nexport function context<T extends string>(\n ...args: [StrictStaticString<T>] | [TemplateStringsArray, ...never[]]\n): ContextBuilder {\n const [source] = args as [StrictStaticString<T> | TemplateStringsArray];\n\n const ctx = typeof source === \"string\" ? source : source[0];\n\n function message<T extends string>(...args: MessageArgs<T>): ContextMessage {\n return { id: baseMessage(...args), context: ctx };\n }\n\n function plural(...forms: PluralArgs): ContextPluralMessage {\n return { id: basePlural(...forms), context: ctx };\n }\n\n return {\n message,\n plural,\n };\n}\n","import type { GetTextTranslations } from \"gettext-parser\";\nimport type { Locale } from \"./config.ts\";\n\nimport {\n message as buildMessage,\n plural as buildPlural,\n type ContextMessage,\n type ContextPluralMessage,\n type Message,\n type MessageArgs,\n type PluralArgs,\n type PluralMessage,\n} from \"./messages.ts\";\nimport { mergeTranslations, normalizeTranslations, pluralFunc, type StrictStaticString, substitute } from \"./utils.ts\";\n\ntype TranslationModule = GetTextTranslations | { default: GetTextTranslations };\ntype TranslationLoader = () => Promise<TranslationModule>;\ntype TranslationEntry = TranslationModule | Promise<TranslationModule> | TranslationLoader;\ntype TranslationRecord = Partial<Record<Locale, TranslationEntry>>;\ntype SyncLocaleKeys<T> = {\n [K in keyof T]: T[K] extends GetTextTranslations ? K : never;\n}[keyof T];\n\nfunction selectValues(message: Message | undefined, fallback?: Message): unknown[] | undefined {\n const values = message?.values;\n if (values?.length) {\n return values;\n }\n return fallback?.values;\n}\n\nfunction selectTemplate(preferred: string | undefined, fallback: string): string {\n return preferred?.length ? preferred : fallback;\n}\n\nfunction applyValues(template: string, message: Message | undefined, fallback?: Message): string {\n const values = selectValues(message, fallback);\n return values?.length ? substitute(template, values) : template;\n}\n\nfunction isPluralMessage(value: unknown): value is PluralMessage {\n return Boolean(value) && typeof value === \"object\" && \"forms\" in (value as PluralMessage);\n}\n\nfunction isContextMessage(value: unknown): value is ContextMessage {\n if (!value || typeof value !== \"object\" || !(\"id\" in value)) {\n return false;\n }\n const candidate = (value as ContextMessage).id;\n return !isPluralMessage(candidate);\n}\n\nfunction isContextPluralMessage(value: unknown): value is ContextPluralMessage {\n if (!value || typeof value !== \"object\" || !(\"id\" in value)) {\n return false;\n }\n const candidate = (value as ContextPluralMessage).id;\n return isPluralMessage(candidate);\n}\n\ntype AnyTranslationMessage = Message | PluralMessage | ContextMessage | ContextPluralMessage;\n\nfunction resolveTranslationModule(module: TranslationModule): GetTextTranslations {\n return \"default\" in module ? module.default : module;\n}\n\nexport class LocaleTranslator {\n locale: Locale;\n translations?: GetTextTranslations;\n\n constructor(locale: Locale, translations?: GetTextTranslations) {\n this.locale = locale;\n this.translations = translations ? normalizeTranslations(translations) : undefined;\n }\n\n resolveMessage = (message: Message, context = \"\"): string => {\n const entry = this.translations?.translations?.[context]?.[message.msgid];\n const template = selectTemplate(entry?.msgstr?.[0], message.msgstr);\n return applyValues(template, message);\n };\n\n resolvePluralForm = (message: PluralMessage, context = \"\"): string => {\n const entry = this.translations?.translations?.[context]?.[message.forms[0].msgid];\n const index = pluralFunc(this.locale)(message.n);\n const forms = message.forms;\n const selectedForm = forms[index] ?? forms[forms.length - 1];\n const translatedForms = entry?.msgstr;\n const templateCandidate = translatedForms?.length\n ? (translatedForms[index] ?? translatedForms[translatedForms.length - 1])\n : undefined;\n const template = selectTemplate(templateCandidate, selectedForm.msgstr);\n return applyValues(template, selectedForm, forms[0]);\n };\n\n translateValue = (message: AnyTranslationMessage): string => {\n if (isContextPluralMessage(message)) {\n return this.resolvePluralForm(message.id, message.context);\n }\n\n if (isContextMessage(message)) {\n return this.resolveMessage(message.id, message.context);\n }\n\n if (isPluralMessage(message)) {\n return this.resolvePluralForm(message);\n }\n\n return this.resolveMessage(message);\n };\n\n translateMessage = <T extends string>(args: MessageArgs<T>, context?: string): string => {\n const message = buildMessage(...args);\n return this.resolveMessage(message, context);\n };\n\n translatePlural = (args: PluralArgs, context?: string): string => {\n const message = buildPlural(...args);\n return this.resolvePluralForm(message, context);\n };\n\n translate = (message: Message | PluralMessage | ContextMessage | ContextPluralMessage): string => {\n return this.translateValue(message);\n };\n\n message = <T extends string>(...args: MessageArgs<T>): string => this.translateMessage(args);\n plural = (...args: PluralArgs): string => this.translatePlural(args);\n\n context = <T extends string>(...args: [StrictStaticString<T>] | [TemplateStringsArray, ...never[]]) => {\n const [source] = args as [StrictStaticString<T> | TemplateStringsArray];\n\n const context = typeof source === \"string\" ? source : source[0];\n\n return {\n message: <U extends string>(...args: MessageArgs<U>): string => this.translateMessage(args, context),\n plural: (...args: PluralArgs): string => this.translatePlural(args, context),\n };\n };\n\n gettext = <T extends string>(...args: MessageArgs<T>): string => this.message(...args);\n ngettext = (...args: PluralArgs): string => this.plural(...args);\n pgettext = <C extends string, T extends string>(context: StrictStaticString<C>, ...args: MessageArgs<T>): string =>\n this.translateMessage(args, context);\n npgettext = <C extends string>(context: StrictStaticString<C>, ...args: PluralArgs): string =>\n this.translatePlural(args, context);\n}\n\nexport class Translator<T extends TranslationRecord = TranslationRecord> {\n parent: Translator | undefined;\n loaders: Partial<Record<Locale, TranslationLoader>> = {};\n translations: Partial<Record<Locale, GetTextTranslations>> = {};\n pending: Partial<Record<Locale, Promise<LocaleTranslator>>> = {};\n translators: Partial<Record<Locale, LocaleTranslator>> = {};\n\n constructor(translations: T, parent?: Translator) {\n this.parent = parent;\n for (const [locale, value] of Object.entries(translations) as [Locale, TranslationEntry][]) {\n if (!value) continue;\n if (typeof value === \"function\") {\n this.loaders[locale] = value;\n } else if (\"then\" in value) {\n this.loaders[locale] = () => value;\n } else {\n this.translations[locale] = resolveTranslationModule(value);\n }\n }\n }\n\n loadLocale = async (locale: Locale, loader?: TranslationLoader): Promise<LocaleTranslator> => {\n this.loaders[locale] = loader ?? this.loaders[locale];\n\n return this.fetchLocale(locale as never);\n };\n\n getLocale = <L extends SyncLocaleKeys<T>>(locale: L): LocaleTranslator => {\n const key = locale as Locale;\n const existing = this.translators[key];\n if (existing) {\n return existing;\n }\n\n const base = this.translations[key];\n if (base) {\n const parentTranslations = this.parent?.getLocale(locale as never)?.translations;\n const translations = mergeTranslations(base, parentTranslations);\n delete this.translations[key];\n\n const translator = new LocaleTranslator(key, translations);\n this.translators[key] = translator;\n return translator;\n }\n\n if (this.pending[key] || this.loaders[key]) {\n console.warn(\n `Translator.getLocale(${key}) called before async locale resolved. Returning untranslated fallback.`,\n );\n this.translators[key] ??= new LocaleTranslator(key);\n return this.translators[key];\n }\n\n this.translators[key] ??= new LocaleTranslator(key);\n return this.translators[key];\n };\n\n fetchLocale = <L extends keyof T>(locale: L) => {\n const key = locale as Locale;\n\n const pending = this.pending[key];\n if (pending) {\n return pending;\n }\n\n const loader = this.loaders[key];\n if (loader) {\n const promise = loader().then((translations) => {\n this.translations[key] ??= resolveTranslationModule(translations);\n delete this.pending[key];\n\n return this.getLocale(key as never);\n });\n this.pending[key] = promise;\n delete this.loaders[key];\n\n return promise;\n }\n\n return this.getLocale(key as never);\n };\n}\n"],"mappings":"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"}
|