@xndrjs/i18n 0.6.1 → 0.7.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/README.md +154 -141
- package/dist/codegen/index.js.map +1 -1
- package/dist/index.d.ts +268 -69
- package/dist/index.js +572 -65
- package/dist/index.js.map +1 -1
- package/dist/validation/index.d.ts +23 -7
- package/dist/validation/index.js +196 -89
- package/dist/validation/index.js.map +1 -1
- package/package.json +1 -1
- package/src/IcuTranslationProviderMulti.test.ts +80 -234
- package/src/IcuTranslationProviderMulti.ts +101 -112
- package/src/IcuTranslationProviderSingle.test.ts +30 -309
- package/src/IcuTranslationProviderSingle.ts +42 -75
- package/src/builder-load-registry.ts +18 -0
- package/src/builder-loaders.ts +18 -0
- package/src/builder-multi.ts +481 -0
- package/src/builder-types.test.ts +80 -0
- package/src/builder-types.ts +24 -0
- package/src/builder.test.ts +421 -0
- package/src/builder.ts +112 -0
- package/src/codegen/delivery-artifacts.test.ts +2 -1
- package/src/codegen/delivery-artifacts.ts +2 -1
- package/src/codegen/emit/dictionary-file.test.ts +0 -7
- package/src/codegen/emit/dictionary-schema-file.ts +55 -42
- package/src/codegen/emit/instance-file.test.ts +88 -0
- package/src/codegen/emit/instance-file.ts +164 -17
- package/src/codegen/emit/namespace-loaders-file.test.ts +4 -18
- package/src/codegen/emit/namespace-loaders-file.ts +4 -54
- package/src/codegen/emit/types-file.test.ts +0 -2
- package/src/codegen/generate-i18n-types.test.ts +8 -303
- package/src/codegen/generate-i18n-types.ts +16 -1
- package/src/codegen/project-locales-set-namespace.test.ts +25 -32
- package/src/engine.ts +71 -0
- package/src/index.ts +45 -7
- package/src/patch-key.test.ts +186 -0
- package/src/patch-key.ts +140 -0
- package/src/project-locales.test.ts +16 -6
- package/src/project-locales.ts +17 -6
- package/src/scope-multi.ts +124 -0
- package/src/scope-single.ts +85 -0
- package/src/scope-types.ts +27 -0
- package/src/scope.test.ts +481 -0
- package/src/single-builder.ts +153 -0
- package/src/types.ts +16 -0
- package/src/validation/create-normalized-schema.ts +1 -1
- package/src/validation/errors.ts +2 -0
- package/src/validation/index.ts +135 -27
- package/src/validation/normalize.ts +176 -46
- package/src/validation/types.ts +4 -0
- package/src/validation/validate-normalized.ts +43 -1
- package/src/validation/validation.test.ts +200 -7
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import { IcuTranslationProviderMulti } from "./IcuTranslationProviderMulti.js";
|
|
3
|
-
import type { LocaleOfMulti } from "./types.js";
|
|
4
3
|
|
|
5
4
|
type TestSchema = {
|
|
6
5
|
default: {
|
|
@@ -69,199 +68,141 @@ const dictionary: TestSchema = {
|
|
|
69
68
|
};
|
|
70
69
|
|
|
71
70
|
describe("IcuTranslationProviderMulti", () => {
|
|
72
|
-
const
|
|
71
|
+
const engine = new IcuTranslationProviderMulti<TestSchema, TestParams>(dictionary);
|
|
73
72
|
|
|
74
|
-
it("
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
it("tracks namespaces via dictionary keys", () => {
|
|
74
|
+
const partial = new IcuTranslationProviderMulti<TestSchema, TestParams>({
|
|
75
|
+
default: dictionary.default,
|
|
76
|
+
});
|
|
78
77
|
|
|
79
|
-
|
|
80
|
-
expect(
|
|
81
|
-
"You have 1 invoice for Ada"
|
|
82
|
-
);
|
|
83
|
-
expect(provider.get("billing", "invoice_summary", "en", { count: 3, name: "Ada" })).toBe(
|
|
84
|
-
"You have 3 invoices for Ada"
|
|
85
|
-
);
|
|
86
|
-
expect(provider.get("billing", "invoice_summary", "it", { count: 1, name: "Ada" })).toBe(
|
|
87
|
-
"Hai 1 fattura per Ada"
|
|
88
|
-
);
|
|
89
|
-
expect(provider.get("billing", "invoice_summary", "it", { count: 3, name: "Ada" })).toBe(
|
|
90
|
-
"Hai 3 fatture per Ada"
|
|
91
|
-
);
|
|
78
|
+
expect("default" in partial.getAll()).toBe(true);
|
|
79
|
+
expect("billing" in partial.getAll()).toBe(false);
|
|
92
80
|
});
|
|
93
81
|
|
|
94
|
-
it("
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
);
|
|
98
|
-
expect(provider.get("default", "dashboard_status", "en", { msgCount: 3, chatCount: 2 })).toBe(
|
|
99
|
-
"You have 3 messages in 2 chats"
|
|
100
|
-
);
|
|
101
|
-
expect(provider.get("default", "dashboard_status", "it", { msgCount: 1, chatCount: 1 })).toBe(
|
|
102
|
-
"Hai 1 messaggio in una chat"
|
|
103
|
-
);
|
|
104
|
-
expect(provider.get("default", "dashboard_status", "it", { msgCount: 3, chatCount: 2 })).toBe(
|
|
105
|
-
"Hai 3 messaggi in 2 chat"
|
|
106
|
-
);
|
|
107
|
-
});
|
|
82
|
+
it("supports partial initialization", () => {
|
|
83
|
+
const partial = new IcuTranslationProviderMulti<TestSchema, TestParams>({
|
|
84
|
+
default: dictionary.default,
|
|
85
|
+
});
|
|
108
86
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
"Linus owns his inbox"
|
|
112
|
-
);
|
|
113
|
-
expect(provider.get("default", "ranking_position", "en", { position: 3 })).toBe(
|
|
114
|
-
"You finished 3rd"
|
|
87
|
+
expect(partial.toScope({ namespaces: ["default"] }).t("default", "login_button", "en")).toBe(
|
|
88
|
+
"Login"
|
|
115
89
|
);
|
|
116
90
|
});
|
|
117
91
|
|
|
118
|
-
it("
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
const expectedAmount = new Intl.NumberFormat("en", {
|
|
122
|
-
style: "currency",
|
|
123
|
-
currency: "EUR",
|
|
124
|
-
}).format(amount);
|
|
125
|
-
const expectedDate = new Intl.DateTimeFormat("en", {
|
|
126
|
-
dateStyle: "short",
|
|
127
|
-
}).format(when);
|
|
128
|
-
const expectedTime = new Intl.DateTimeFormat("en", {
|
|
129
|
-
timeStyle: "short",
|
|
130
|
-
}).format(when);
|
|
92
|
+
it("patches a preloaded key and invalidates its cache", () => {
|
|
93
|
+
const local = new IcuTranslationProviderMulti<TestSchema, TestParams>(dictionary);
|
|
94
|
+
const view = () => local.toScope({ namespaces: ["default", "billing"] });
|
|
131
95
|
|
|
132
|
-
expect(
|
|
133
|
-
|
|
96
|
+
expect(view().t("billing", "invoice_summary", "en", { count: 2, name: "Bob" })).toBe(
|
|
97
|
+
"You have 2 invoices for Bob"
|
|
134
98
|
);
|
|
135
|
-
expect(
|
|
136
|
-
provider.get("billing", "appointment_summary", "en", {
|
|
137
|
-
dueDate: when,
|
|
138
|
-
startTime: when,
|
|
139
|
-
})
|
|
140
|
-
).toBe(`Due ${expectedDate} at ${expectedTime}`);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it("treats an empty string template as valid", () => {
|
|
144
|
-
expect(provider.get("billing", "empty_label", "en")).toBe("");
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it("tracks loaded namespaces with hasNamespace", () => {
|
|
148
|
-
const partial = new IcuTranslationProviderMulti<TestSchema, TestParams>({
|
|
149
|
-
default: dictionary.default,
|
|
150
|
-
});
|
|
151
99
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
default: dictionary.default,
|
|
159
|
-
});
|
|
100
|
+
local.patchKeyMulti(
|
|
101
|
+
"billing",
|
|
102
|
+
"invoice_summary",
|
|
103
|
+
"en",
|
|
104
|
+
"{count, plural, one {1 bill} other {{count} bills}} for {name}"
|
|
105
|
+
);
|
|
160
106
|
|
|
161
|
-
expect(()
|
|
162
|
-
|
|
163
|
-
).toThrow(
|
|
164
|
-
'[i18n] Namespace not loaded: "billing". Register it with setNamespace() before calling .get().'
|
|
107
|
+
expect(view().t("billing", "invoice_summary", "en", { count: 2, name: "Bob" })).toBe(
|
|
108
|
+
"2 bills for Bob"
|
|
165
109
|
);
|
|
110
|
+
expect(view().t("default", "login_button", "en")).toBe("Login");
|
|
166
111
|
});
|
|
167
112
|
|
|
168
|
-
it("
|
|
113
|
+
it("adds namespace to dictionary with applyLoadMergeNamespace", () => {
|
|
169
114
|
const partial = new IcuTranslationProviderMulti<TestSchema, TestParams>({
|
|
170
115
|
default: dictionary.default,
|
|
171
116
|
});
|
|
117
|
+
expect("billing" in partial.getAll()).toBe(false);
|
|
172
118
|
|
|
173
|
-
|
|
119
|
+
partial.applyLoadMergeNamespace("billing", dictionary.billing);
|
|
120
|
+
expect("billing" in partial.getAll()).toBe(true);
|
|
174
121
|
});
|
|
175
122
|
|
|
176
|
-
it("
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
).toThrow(
|
|
180
|
-
'[i18n] Missing key or locale: namespace "default", key "login_button" [fr] (fallback chain: fr)'
|
|
181
|
-
);
|
|
182
|
-
expect(() => provider.get("billing", "login_button" as "empty_label", "en")).toThrow(
|
|
183
|
-
'[i18n] Missing key or locale: namespace "billing", key "login_button" [en] (fallback chain: en)'
|
|
184
|
-
);
|
|
185
|
-
});
|
|
123
|
+
it("adds namespace to dictionary on first applyLoadMergeNamespace", () => {
|
|
124
|
+
const partial = new IcuTranslationProviderMulti<TestSchema, TestParams>({});
|
|
125
|
+
expect("billing" in partial.getAll()).toBe(false);
|
|
186
126
|
|
|
187
|
-
|
|
188
|
-
expect(
|
|
189
|
-
"[i18n Formatting Error]"
|
|
190
|
-
);
|
|
127
|
+
partial.applyLoadMergeNamespace("billing", dictionary.billing);
|
|
128
|
+
expect("billing" in partial.getAll()).toBe(true);
|
|
191
129
|
});
|
|
192
130
|
|
|
193
|
-
it("
|
|
194
|
-
const local = new IcuTranslationProviderMulti<TestSchema, TestParams>(
|
|
195
|
-
|
|
196
|
-
|
|
131
|
+
it("accumulates a locale via applyLoadMergeNamespace when the namespace already exists", () => {
|
|
132
|
+
const local = new IcuTranslationProviderMulti<TestSchema, TestParams>({
|
|
133
|
+
billing: {
|
|
134
|
+
invoice_summary: {
|
|
135
|
+
en: "You have {count, plural, one {1 invoice} other {{count} invoices}} for {name}",
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
const view = () => local.toScope({ namespaces: ["billing"] });
|
|
140
|
+
|
|
141
|
+
expect("billing" in local.getAll()).toBe(true);
|
|
142
|
+
expect(view().t("billing", "invoice_summary", "en", { count: 1, name: "Ada" })).toBe(
|
|
143
|
+
"You have 1 invoice for Ada"
|
|
197
144
|
);
|
|
198
145
|
|
|
199
|
-
local.
|
|
200
|
-
...dictionary.billing,
|
|
146
|
+
local.applyLoadMergeNamespace("billing", {
|
|
201
147
|
invoice_summary: {
|
|
202
|
-
|
|
203
|
-
it: dictionary.billing.invoice_summary.it,
|
|
148
|
+
it: "Hai {count, plural, one {1 fattura} other {{count} fatture}} per {name}",
|
|
204
149
|
},
|
|
205
150
|
});
|
|
206
151
|
|
|
207
|
-
expect(
|
|
208
|
-
"2
|
|
152
|
+
expect(view().t("billing", "invoice_summary", "en", { count: 2, name: "Bob" })).toBe(
|
|
153
|
+
"You have 2 invoices for Bob"
|
|
154
|
+
);
|
|
155
|
+
expect(view().t("billing", "invoice_summary", "it", { count: 2, name: "Bob" })).toBe(
|
|
156
|
+
"Hai 2 fatture per Bob"
|
|
209
157
|
);
|
|
210
|
-
expect(local.get("default", "login_button", "en")).toBe("Login");
|
|
211
158
|
});
|
|
212
159
|
|
|
213
|
-
it("merges locales per key with
|
|
160
|
+
it("merges locales per key with applyLoadMergeNamespace without dropping existing locales", () => {
|
|
214
161
|
const local = new IcuTranslationProviderMulti<TestSchema, TestParams>({
|
|
215
162
|
billing: {
|
|
216
|
-
// @ts-expect-error missing locale
|
|
217
163
|
invoice_summary: {
|
|
218
164
|
en: "You have {count, plural, one {1 invoice} other {{count} invoices}} for {name}",
|
|
219
165
|
},
|
|
220
166
|
},
|
|
221
167
|
});
|
|
168
|
+
const view = () => local.toScope({ namespaces: ["billing"] });
|
|
222
169
|
|
|
223
|
-
local.
|
|
224
|
-
// @ts-expect-error missing locale
|
|
170
|
+
local.applyLoadMergeNamespace("billing", {
|
|
225
171
|
invoice_summary: {
|
|
226
172
|
it: "Hai {count, plural, one {1 fattura} other {{count} fatture}} per {name}",
|
|
227
173
|
},
|
|
228
174
|
});
|
|
229
175
|
|
|
230
|
-
expect(
|
|
176
|
+
expect(view().t("billing", "invoice_summary", "en", { count: 2, name: "Bob" })).toBe(
|
|
231
177
|
"You have 2 invoices for Bob"
|
|
232
178
|
);
|
|
233
|
-
expect(
|
|
179
|
+
expect(view().t("billing", "invoice_summary", "it", { count: 2, name: "Bob" })).toBe(
|
|
234
180
|
"Hai 2 fatture per Bob"
|
|
235
181
|
);
|
|
236
182
|
});
|
|
237
183
|
|
|
238
|
-
it("
|
|
184
|
+
it("patches a preloaded default namespace key", () => {
|
|
239
185
|
const local = new IcuTranslationProviderMulti<TestSchema, TestParams>(dictionary);
|
|
240
186
|
|
|
241
|
-
local.
|
|
242
|
-
...dictionary,
|
|
243
|
-
default: {
|
|
244
|
-
...dictionary.default,
|
|
245
|
-
login_button: { en: "Sign in", it: "Entra" },
|
|
246
|
-
},
|
|
247
|
-
});
|
|
187
|
+
local.patchKeyMulti("default", "login_button", "en", "Sign in");
|
|
248
188
|
|
|
249
|
-
expect(local.
|
|
189
|
+
expect(local.toScope({ namespaces: ["default"] }).t("default", "login_button", "en")).toBe(
|
|
190
|
+
"Sign in"
|
|
191
|
+
);
|
|
250
192
|
});
|
|
251
193
|
|
|
252
|
-
it("merges namespaces with
|
|
194
|
+
it("merges namespaces with applyLoadMergeAll without dropping existing locales", () => {
|
|
253
195
|
const local = new IcuTranslationProviderMulti<TestSchema, TestParams>({
|
|
254
196
|
billing: {
|
|
255
|
-
// @ts-expect-error missing locale
|
|
256
197
|
invoice_summary: {
|
|
257
198
|
en: "You have {count, plural, one {1 invoice} other {{count} invoices}} for {name}",
|
|
258
199
|
},
|
|
259
200
|
},
|
|
260
201
|
});
|
|
202
|
+
const view = () => local.toScope({ namespaces: ["default", "billing"] });
|
|
261
203
|
|
|
262
|
-
local.
|
|
204
|
+
local.applyLoadMergeAll({
|
|
263
205
|
billing: {
|
|
264
|
-
// @ts-expect-error missing locale
|
|
265
206
|
invoice_summary: {
|
|
266
207
|
it: "Hai {count, plural, one {1 fattura} other {{count} fatture}} per {name}",
|
|
267
208
|
},
|
|
@@ -269,123 +210,28 @@ describe("IcuTranslationProviderMulti", () => {
|
|
|
269
210
|
default: dictionary.default,
|
|
270
211
|
});
|
|
271
212
|
|
|
272
|
-
expect(
|
|
213
|
+
expect(view().t("billing", "invoice_summary", "en", { count: 2, name: "Bob" })).toBe(
|
|
273
214
|
"You have 2 invoices for Bob"
|
|
274
215
|
);
|
|
275
|
-
expect(
|
|
216
|
+
expect(view().t("billing", "invoice_summary", "it", { count: 2, name: "Bob" })).toBe(
|
|
276
217
|
"Hai 2 fatture per Bob"
|
|
277
218
|
);
|
|
278
|
-
expect(
|
|
219
|
+
expect(view().t("default", "login_button", "en")).toBe("Login");
|
|
279
220
|
});
|
|
280
221
|
|
|
281
222
|
it("returns a deep-frozen snapshot from getAll", () => {
|
|
282
|
-
expect(
|
|
283
|
-
expect(
|
|
284
|
-
expect(Object.isFrozen(
|
|
223
|
+
expect(engine.getAll()).toEqual(dictionary);
|
|
224
|
+
expect(engine.getAll()).not.toBe(dictionary);
|
|
225
|
+
expect(Object.isFrozen(engine.getAll().default)).toBe(true);
|
|
285
226
|
});
|
|
286
227
|
|
|
287
|
-
it("does not mutate the
|
|
288
|
-
const snapshot =
|
|
228
|
+
it("does not mutate the engine when getAll snapshot is modified", () => {
|
|
229
|
+
const snapshot = engine.getAll();
|
|
289
230
|
expect(() => {
|
|
290
231
|
snapshot.default.login_button.en = "Hacked";
|
|
291
232
|
}).toThrow(TypeError);
|
|
292
|
-
expect(
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
describe("forLocale", () => {
|
|
296
|
-
it("binds a locale so get() no longer requires it", () => {
|
|
297
|
-
const it = provider.forLocale("it");
|
|
298
|
-
|
|
299
|
-
expect(it.locale).toBe("it");
|
|
300
|
-
expect(it.get("default", "login_button")).toBe("Accedi");
|
|
301
|
-
expect(it.get("billing", "invoice_summary", { count: 2, name: "Ada" })).toBe(
|
|
302
|
-
"Hai 2 fatture per Ada"
|
|
303
|
-
);
|
|
304
|
-
});
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
describe("locale fallback", () => {
|
|
308
|
-
const fallbackMap = {
|
|
309
|
-
en: null,
|
|
310
|
-
"de-DE": "en",
|
|
311
|
-
"de-CH": "de-DE",
|
|
312
|
-
it: "en",
|
|
313
|
-
} as const;
|
|
314
|
-
|
|
315
|
-
const fallbackProvider = new IcuTranslationProviderMulti<
|
|
316
|
-
TestSchema,
|
|
317
|
-
TestParams,
|
|
318
|
-
keyof typeof fallbackMap | LocaleOfMulti<TestSchema>,
|
|
319
|
-
typeof fallbackMap
|
|
320
|
-
>(dictionary, { localeFallback: fallbackMap });
|
|
321
|
-
|
|
322
|
-
it("resolves a locale through the fallback chain", () => {
|
|
323
|
-
expect(fallbackProvider.get("default", "login_button", "de-CH")).toBe("Login");
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
it("throws when the fallback chain cannot resolve a template", () => {
|
|
327
|
-
const unresolvedFallback = {
|
|
328
|
-
en: null,
|
|
329
|
-
"de-CH": "fr",
|
|
330
|
-
fr: null,
|
|
331
|
-
} as const;
|
|
332
|
-
const unresolvedProvider = new IcuTranslationProviderMulti<
|
|
333
|
-
TestSchema,
|
|
334
|
-
TestParams,
|
|
335
|
-
keyof typeof unresolvedFallback | LocaleOfMulti<TestSchema>,
|
|
336
|
-
typeof unresolvedFallback
|
|
337
|
-
>(dictionary, { localeFallback: unresolvedFallback });
|
|
338
|
-
|
|
339
|
-
expect(() => unresolvedProvider.get("default", "login_button", "de-CH")).toThrow(
|
|
340
|
-
'[i18n] Missing key or locale: namespace "default", key "login_button" [de-CH] (fallback chain: de-CH → fr)'
|
|
341
|
-
);
|
|
342
|
-
});
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
describe("onMissing", () => {
|
|
346
|
-
it('returns "namespace.key" with onMissing: "key"', () => {
|
|
347
|
-
const local = new IcuTranslationProviderMulti<TestSchema, TestParams>(dictionary, {
|
|
348
|
-
onMissing: "key",
|
|
349
|
-
});
|
|
350
|
-
expect(local.get("default", "missing_key" as "login_button", "en")).toBe(
|
|
351
|
-
"default.missing_key"
|
|
352
|
-
);
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
it("calls a custom handler with namespace, key, locale, and fallback chain", () => {
|
|
356
|
-
const contexts: unknown[] = [];
|
|
357
|
-
const local = new IcuTranslationProviderMulti<TestSchema, TestParams>(dictionary, {
|
|
358
|
-
onMissing: (context) => {
|
|
359
|
-
contexts.push(context);
|
|
360
|
-
return `<missing:${context.namespace}/${context.key}>`;
|
|
361
|
-
},
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
expect(local.get("default", "missing_key" as "login_button", "en")).toBe(
|
|
365
|
-
"<missing:default/missing_key>"
|
|
366
|
-
);
|
|
367
|
-
expect(contexts).toEqual([
|
|
368
|
-
{ namespace: "default", key: "missing_key", locale: "en", fallbackChain: "en" },
|
|
369
|
-
]);
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
it("still throws for unloaded namespaces with a lenient onMissing", () => {
|
|
373
|
-
const local = new IcuTranslationProviderMulti<TestSchema, TestParams>(
|
|
374
|
-
{ default: dictionary.default },
|
|
375
|
-
{ onMissing: "key" }
|
|
376
|
-
);
|
|
377
|
-
expect(() => local.get("billing", "account_balance", "en", { amount: 1 })).toThrow(
|
|
378
|
-
'[i18n] Namespace not loaded: "billing"'
|
|
379
|
-
);
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
it("applies onMissing through forLocale wrappers", () => {
|
|
383
|
-
const local = new IcuTranslationProviderMulti<TestSchema, TestParams>(dictionary, {
|
|
384
|
-
onMissing: "key",
|
|
385
|
-
});
|
|
386
|
-
expect(local.forLocale("en").get("default", "missing_key" as "login_button")).toBe(
|
|
387
|
-
"default.missing_key"
|
|
388
|
-
);
|
|
389
|
-
});
|
|
233
|
+
expect(engine.toScope({ namespaces: ["default"] }).t("default", "login_button", "en")).toBe(
|
|
234
|
+
"Login"
|
|
235
|
+
);
|
|
390
236
|
});
|
|
391
237
|
});
|