@to-kn/koa-locales 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +201 -0
- package/dist/esm/index.js +271 -0
- package/dist/esm/src/index.js +320 -0
- package/dist/esm/test/index.test.js +580 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +250 -0
- package/dist/types/index.d.ts +28 -0
- package/dist/types/src/index.d.ts +27 -0
- package/dist/types/test/index.test.d.ts +1 -0
- package/package.json +79 -0
@@ -0,0 +1,580 @@
|
|
1
|
+
import assert from "assert";
|
2
|
+
import Koa from "koa";
|
3
|
+
import mm from "mm";
|
4
|
+
import request from "supertest";
|
5
|
+
import { afterEach, describe, expect, it } from "vitest";
|
6
|
+
// @ts-expect-error: legacy test expects any type for locales import
|
7
|
+
import locales from "..";
|
8
|
+
|
9
|
+
describe("koa-locales.test.js", () => {
|
10
|
+
afterEach(mm.restore);
|
11
|
+
describe("default options", () => {
|
12
|
+
const app = createApp();
|
13
|
+
it("should use default locale: en-US", async () => {
|
14
|
+
await request(app.callback())
|
15
|
+
.get("/")
|
16
|
+
.expect({
|
17
|
+
email: "Email",
|
18
|
+
hello: "Hello fengmk2, how are you today?",
|
19
|
+
message: "Hello fengmk2, how are you today? How was your 18.",
|
20
|
+
empty: "",
|
21
|
+
notexists_key: "key not exists",
|
22
|
+
empty_string: "",
|
23
|
+
empty_value: "emptyValue",
|
24
|
+
novalue: "key %s ok",
|
25
|
+
arguments3: "1 2 3",
|
26
|
+
arguments4: "1 2 3 4",
|
27
|
+
arguments5: "1 2 3 4 5",
|
28
|
+
arguments6: "1 2 3 4 5. 6",
|
29
|
+
values: "foo bar foo bar {2} {100}",
|
30
|
+
object: "foo bar foo bar {z}",
|
31
|
+
gender: "model.user.fields.gender",
|
32
|
+
name: "model.user.fields.name",
|
33
|
+
})
|
34
|
+
.expect("Set-Cookie", /^locale=en-us; path=\/+; expires=[^;]+ GMT$/)
|
35
|
+
.expect(200);
|
36
|
+
});
|
37
|
+
it("should not set locale cookie after header sent", async () => {
|
38
|
+
await request(app.callback())
|
39
|
+
.get("/headerSent")
|
40
|
+
.expect("foo")
|
41
|
+
.expect(200);
|
42
|
+
});
|
43
|
+
});
|
44
|
+
describe("options.cookieDomain", () => {
|
45
|
+
const app = createApp({
|
46
|
+
cookieDomain: ".foo.com",
|
47
|
+
});
|
48
|
+
it("should use default locale: en-US", async () => {
|
49
|
+
await request(app.callback())
|
50
|
+
.get("/")
|
51
|
+
.expect({
|
52
|
+
email: "Email",
|
53
|
+
hello: "Hello fengmk2, how are you today?",
|
54
|
+
message: "Hello fengmk2, how are you today? How was your 18.",
|
55
|
+
empty: "",
|
56
|
+
notexists_key: "key not exists",
|
57
|
+
empty_string: "",
|
58
|
+
empty_value: "emptyValue",
|
59
|
+
novalue: "key %s ok",
|
60
|
+
arguments3: "1 2 3",
|
61
|
+
arguments4: "1 2 3 4",
|
62
|
+
arguments5: "1 2 3 4 5",
|
63
|
+
arguments6: "1 2 3 4 5. 6",
|
64
|
+
values: "foo bar foo bar {2} {100}",
|
65
|
+
object: "foo bar foo bar {z}",
|
66
|
+
gender: "model.user.fields.gender",
|
67
|
+
name: "model.user.fields.name",
|
68
|
+
})
|
69
|
+
.expect(
|
70
|
+
"Set-Cookie",
|
71
|
+
/^locale=en-us; path=\/; expires=[^;]+; domain=.foo.com$/,
|
72
|
+
)
|
73
|
+
.expect(200);
|
74
|
+
});
|
75
|
+
});
|
76
|
+
describe("custom options", () => {
|
77
|
+
const app = createApp({
|
78
|
+
dirs: [__dirname + "/locales", __dirname + "/other-locales"],
|
79
|
+
});
|
80
|
+
const cookieFieldMapApp = createApp({
|
81
|
+
dirs: [__dirname + "/locales", __dirname + "/other-locales"],
|
82
|
+
localeAlias: {
|
83
|
+
en: "en-US",
|
84
|
+
"de-de": "de",
|
85
|
+
},
|
86
|
+
});
|
87
|
+
const appNotWriteCookie = createApp({
|
88
|
+
dirs: [__dirname + "/locales", __dirname + "/other-locales"],
|
89
|
+
writeCookie: false,
|
90
|
+
});
|
91
|
+
it("should use default locale: en-US", async () => {
|
92
|
+
await request(app.callback())
|
93
|
+
.get("/")
|
94
|
+
.expect({
|
95
|
+
email: "Email",
|
96
|
+
hello: "Hello fengmk2, how are you today?",
|
97
|
+
message: "Hello fengmk2, how are you today? How was your 18.",
|
98
|
+
empty: "",
|
99
|
+
notexists_key: "key not exists",
|
100
|
+
empty_string: "",
|
101
|
+
empty_value: "emptyValue",
|
102
|
+
novalue: "key %s ok",
|
103
|
+
arguments3: "1 2 3",
|
104
|
+
arguments4: "1 2 3 4",
|
105
|
+
arguments5: "1 2 3 4 5",
|
106
|
+
arguments6: "1 2 3 4 5. 6",
|
107
|
+
values: "foo bar foo bar {2} {100}",
|
108
|
+
object: "foo bar foo bar {z}",
|
109
|
+
gender: "model.user.fields.gender",
|
110
|
+
name: "model.user.fields.name",
|
111
|
+
})
|
112
|
+
.expect("Set-Cookie", /^locale=en-us; path=\/; expires=\w+/)
|
113
|
+
.expect(200);
|
114
|
+
});
|
115
|
+
it("should gettext work on app.__(locale, key, value)", async () => {
|
116
|
+
await request(app.callback())
|
117
|
+
.get("/app_locale_zh")
|
118
|
+
.expect({
|
119
|
+
email: "邮箱1",
|
120
|
+
})
|
121
|
+
.expect(200);
|
122
|
+
});
|
123
|
+
describe("query.locale", () => {
|
124
|
+
it("should use query locale: zh-CN", async () => {
|
125
|
+
await request(app.callback())
|
126
|
+
.get("/?locale=zh-CN")
|
127
|
+
.expect({
|
128
|
+
email: "邮箱1",
|
129
|
+
hello: "fengmk2,今天过得如何?",
|
130
|
+
message: "Hello fengmk2, how are you today? How was your 18.",
|
131
|
+
empty: "",
|
132
|
+
notexists_key: "key not exists",
|
133
|
+
empty_string: "",
|
134
|
+
empty_value: "",
|
135
|
+
novalue: "key %s ok",
|
136
|
+
arguments3: "1 2 3",
|
137
|
+
arguments4: "1 2 3 4",
|
138
|
+
arguments5: "1 2 3 4 5",
|
139
|
+
arguments6: "1 2 3 4 5. 6",
|
140
|
+
values: "foo bar foo bar {2} {100}",
|
141
|
+
object: "foo bar foo bar {z}",
|
142
|
+
gender: "性别",
|
143
|
+
name: "姓名",
|
144
|
+
})
|
145
|
+
.expect("Set-Cookie", /^locale=zh-cn; path=\/; expires=\w+/)
|
146
|
+
.expect(200);
|
147
|
+
});
|
148
|
+
it("should use query locale: de on *.properties format", async () => {
|
149
|
+
await request(app.callback())
|
150
|
+
.get("/?locale=de")
|
151
|
+
.expect({
|
152
|
+
email: "Emailde",
|
153
|
+
hello: "Hallo fengmk2, wie geht es dir heute?",
|
154
|
+
message: "Hallo fengmk2, wie geht es dir heute? Wie war dein 18.",
|
155
|
+
empty: "",
|
156
|
+
notexists_key: "key not exists",
|
157
|
+
empty_string: "",
|
158
|
+
empty_value: "emptyValue",
|
159
|
+
novalue: "key %s ok",
|
160
|
+
arguments3: "1 2 3",
|
161
|
+
arguments4: "1 2 3 4",
|
162
|
+
arguments5: "1 2 3 4 5",
|
163
|
+
arguments6: "1 2 3 4 5. 6",
|
164
|
+
values: "foo bar foo bar {2} {100}",
|
165
|
+
object: "foo bar foo bar {z}",
|
166
|
+
gender: "model.user.fields.gender",
|
167
|
+
name: "model.user.fields.name",
|
168
|
+
})
|
169
|
+
.expect("Set-Cookie", /^locale=de; path=\/; expires=\w+/)
|
170
|
+
.expect(200);
|
171
|
+
});
|
172
|
+
it("should use query locale and change cookie locale", async () => {
|
173
|
+
await request(app.callback())
|
174
|
+
.get("/?locale=zh-CN")
|
175
|
+
.set("cookie", "locale=zh-TW")
|
176
|
+
.expect({
|
177
|
+
email: "邮箱1",
|
178
|
+
hello: "fengmk2,今天过得如何?",
|
179
|
+
message: "Hello fengmk2, how are you today? How was your 18.",
|
180
|
+
empty: "",
|
181
|
+
notexists_key: "key not exists",
|
182
|
+
empty_string: "",
|
183
|
+
empty_value: "",
|
184
|
+
novalue: "key %s ok",
|
185
|
+
arguments3: "1 2 3",
|
186
|
+
arguments4: "1 2 3 4",
|
187
|
+
arguments5: "1 2 3 4 5",
|
188
|
+
arguments6: "1 2 3 4 5. 6",
|
189
|
+
values: "foo bar foo bar {2} {100}",
|
190
|
+
object: "foo bar foo bar {z}",
|
191
|
+
gender: "性别",
|
192
|
+
name: "姓名",
|
193
|
+
})
|
194
|
+
.expect("Set-Cookie", /^locale=zh-cn; path=\/; expires=\w+/)
|
195
|
+
.expect(200);
|
196
|
+
});
|
197
|
+
it("should ignore invalid locale value", async () => {
|
198
|
+
await request(app.callback())
|
199
|
+
.get("/?locale=xss")
|
200
|
+
.expect({
|
201
|
+
email: "Email",
|
202
|
+
hello: "Hello fengmk2, how are you today?",
|
203
|
+
message: "Hello fengmk2, how are you today? How was your 18.",
|
204
|
+
empty: "",
|
205
|
+
notexists_key: "key not exists",
|
206
|
+
empty_string: "",
|
207
|
+
empty_value: "emptyValue",
|
208
|
+
novalue: "key %s ok",
|
209
|
+
arguments3: "1 2 3",
|
210
|
+
arguments4: "1 2 3 4",
|
211
|
+
arguments5: "1 2 3 4 5",
|
212
|
+
arguments6: "1 2 3 4 5. 6",
|
213
|
+
values: "foo bar foo bar {2} {100}",
|
214
|
+
object: "foo bar foo bar {z}",
|
215
|
+
gender: "model.user.fields.gender",
|
216
|
+
name: "model.user.fields.name",
|
217
|
+
})
|
218
|
+
.expect("Set-Cookie", /^locale=en-us; path=\/; expires=\w+/)
|
219
|
+
.expect(200);
|
220
|
+
});
|
221
|
+
it("should use localeAlias", async () => {
|
222
|
+
await request(cookieFieldMapApp.callback())
|
223
|
+
.get("/?locale=de-de")
|
224
|
+
.expect({
|
225
|
+
email: "Emailde",
|
226
|
+
hello: "Hallo fengmk2, wie geht es dir heute?",
|
227
|
+
message: "Hallo fengmk2, wie geht es dir heute? Wie war dein 18.",
|
228
|
+
empty: "",
|
229
|
+
notexists_key: "key not exists",
|
230
|
+
empty_string: "",
|
231
|
+
empty_value: "emptyValue",
|
232
|
+
novalue: "key %s ok",
|
233
|
+
arguments3: "1 2 3",
|
234
|
+
arguments4: "1 2 3 4",
|
235
|
+
arguments5: "1 2 3 4 5",
|
236
|
+
arguments6: "1 2 3 4 5. 6",
|
237
|
+
values: "foo bar foo bar {2} {100}",
|
238
|
+
object: "foo bar foo bar {z}",
|
239
|
+
gender: "model.user.fields.gender",
|
240
|
+
name: "model.user.fields.name",
|
241
|
+
})
|
242
|
+
.expect("Set-Cookie", /^locale=de; path=\/; expires=\w+/)
|
243
|
+
.expect(200);
|
244
|
+
});
|
245
|
+
it("should use query locale and response without set-cookie", async () => {
|
246
|
+
await request(appNotWriteCookie.callback())
|
247
|
+
.get("/?locale=zh-CN")
|
248
|
+
.expect({
|
249
|
+
email: "邮箱1",
|
250
|
+
hello: "fengmk2,今天过得如何?",
|
251
|
+
message: "Hello fengmk2, how are you today? How was your 18.",
|
252
|
+
empty: "",
|
253
|
+
notexists_key: "key not exists",
|
254
|
+
empty_string: "",
|
255
|
+
empty_value: "",
|
256
|
+
novalue: "key %s ok",
|
257
|
+
arguments3: "1 2 3",
|
258
|
+
arguments4: "1 2 3 4",
|
259
|
+
arguments5: "1 2 3 4 5",
|
260
|
+
arguments6: "1 2 3 4 5. 6",
|
261
|
+
values: "foo bar foo bar {2} {100}",
|
262
|
+
object: "foo bar foo bar {z}",
|
263
|
+
gender: "性别",
|
264
|
+
name: "姓名",
|
265
|
+
})
|
266
|
+
.expect((res) => {
|
267
|
+
if (res.headers["set-cookie"] || res.headers["Set-Cookie"]) {
|
268
|
+
throw new Error("should not write cookie");
|
269
|
+
}
|
270
|
+
})
|
271
|
+
.expect(200);
|
272
|
+
});
|
273
|
+
});
|
274
|
+
describe("cookie.locale", () => {
|
275
|
+
it("should use cookie locale: zh-CN", async () => {
|
276
|
+
await request(app.callback())
|
277
|
+
.get("/?locale=")
|
278
|
+
.set("cookie", "locale=zh-cn")
|
279
|
+
.expect({
|
280
|
+
email: "邮箱1",
|
281
|
+
hello: "fengmk2,今天过得如何?",
|
282
|
+
message: "Hello fengmk2, how are you today? How was your 18.",
|
283
|
+
empty: "",
|
284
|
+
notexists_key: "key not exists",
|
285
|
+
empty_string: "",
|
286
|
+
empty_value: "",
|
287
|
+
novalue: "key %s ok",
|
288
|
+
arguments3: "1 2 3",
|
289
|
+
arguments4: "1 2 3 4",
|
290
|
+
arguments5: "1 2 3 4 5",
|
291
|
+
arguments6: "1 2 3 4 5. 6",
|
292
|
+
values: "foo bar foo bar {2} {100}",
|
293
|
+
object: "foo bar foo bar {z}",
|
294
|
+
gender: "性别",
|
295
|
+
name: "姓名",
|
296
|
+
})
|
297
|
+
.expect((res) => {
|
298
|
+
assert(!res.headers["set-cookie"]);
|
299
|
+
})
|
300
|
+
.expect(200);
|
301
|
+
});
|
302
|
+
});
|
303
|
+
describe("Accept-Language", () => {
|
304
|
+
it("should use Accept-Language: zh-CN", async () => {
|
305
|
+
await request(app.callback())
|
306
|
+
.get("/?locale=")
|
307
|
+
.set("Accept-Language", "zh-CN")
|
308
|
+
.expect({
|
309
|
+
email: "邮箱1",
|
310
|
+
hello: "fengmk2,今天过得如何?",
|
311
|
+
message: "Hello fengmk2, how are you today? How was your 18.",
|
312
|
+
empty: "",
|
313
|
+
notexists_key: "key not exists",
|
314
|
+
empty_string: "",
|
315
|
+
empty_value: "",
|
316
|
+
novalue: "key %s ok",
|
317
|
+
arguments3: "1 2 3",
|
318
|
+
arguments4: "1 2 3 4",
|
319
|
+
arguments5: "1 2 3 4 5",
|
320
|
+
arguments6: "1 2 3 4 5. 6",
|
321
|
+
values: "foo bar foo bar {2} {100}",
|
322
|
+
object: "foo bar foo bar {z}",
|
323
|
+
gender: "性别",
|
324
|
+
name: "姓名",
|
325
|
+
})
|
326
|
+
.expect("Set-Cookie", /^locale=zh-cn; path=\/; expires=\w+/)
|
327
|
+
.expect(200);
|
328
|
+
});
|
329
|
+
it('should work with "Accept-Language: " header', async () => {
|
330
|
+
await request(app.callback())
|
331
|
+
.get("/?locale=")
|
332
|
+
.set("Accept-Language", "")
|
333
|
+
.expect({
|
334
|
+
email: "Email",
|
335
|
+
hello: "Hello fengmk2, how are you today?",
|
336
|
+
message: "Hello fengmk2, how are you today? How was your 18.",
|
337
|
+
empty: "",
|
338
|
+
notexists_key: "key not exists",
|
339
|
+
empty_string: "",
|
340
|
+
empty_value: "emptyValue",
|
341
|
+
novalue: "key %s ok",
|
342
|
+
arguments3: "1 2 3",
|
343
|
+
arguments4: "1 2 3 4",
|
344
|
+
arguments5: "1 2 3 4 5",
|
345
|
+
arguments6: "1 2 3 4 5. 6",
|
346
|
+
values: "foo bar foo bar {2} {100}",
|
347
|
+
object: "foo bar foo bar {z}",
|
348
|
+
gender: "model.user.fields.gender",
|
349
|
+
name: "model.user.fields.name",
|
350
|
+
})
|
351
|
+
.expect("Set-Cookie", /^locale=en-us; path=\/; expires=\w+/)
|
352
|
+
.expect(200);
|
353
|
+
});
|
354
|
+
it('should work with "Accept-Language: en"', async () => {
|
355
|
+
await request(app.callback())
|
356
|
+
.get("/")
|
357
|
+
.set("Accept-Language", "en")
|
358
|
+
.expect({
|
359
|
+
email: "Email",
|
360
|
+
hello: "Hello fengmk2, how are you today?",
|
361
|
+
message: "Hello fengmk2, how are you today? How was your 18.",
|
362
|
+
empty: "",
|
363
|
+
notexists_key: "key not exists",
|
364
|
+
empty_string: "",
|
365
|
+
empty_value: "emptyValue",
|
366
|
+
novalue: "key %s ok",
|
367
|
+
arguments3: "1 2 3",
|
368
|
+
arguments4: "1 2 3 4",
|
369
|
+
arguments5: "1 2 3 4 5",
|
370
|
+
arguments6: "1 2 3 4 5. 6",
|
371
|
+
values: "foo bar foo bar {2} {100}",
|
372
|
+
object: "foo bar foo bar {z}",
|
373
|
+
gender: "model.user.fields.gender",
|
374
|
+
name: "model.user.fields.name",
|
375
|
+
})
|
376
|
+
.expect("Set-Cookie", /^locale=en-us; path=\/; expires=\w+/)
|
377
|
+
.expect(200);
|
378
|
+
});
|
379
|
+
it('should work with "Accept-Language: de-de" by localeAlias', async () => {
|
380
|
+
await request(cookieFieldMapApp.callback())
|
381
|
+
.get("/")
|
382
|
+
.set("Accept-Language", "ja,de-de;q=0.8")
|
383
|
+
.expect({
|
384
|
+
email: "Emailde",
|
385
|
+
hello: "Hallo fengmk2, wie geht es dir heute?",
|
386
|
+
message: "Hallo fengmk2, wie geht es dir heute? Wie war dein 18.",
|
387
|
+
empty: "",
|
388
|
+
notexists_key: "key not exists",
|
389
|
+
empty_string: "",
|
390
|
+
empty_value: "emptyValue",
|
391
|
+
novalue: "key %s ok",
|
392
|
+
arguments3: "1 2 3",
|
393
|
+
arguments4: "1 2 3 4",
|
394
|
+
arguments5: "1 2 3 4 5",
|
395
|
+
arguments6: "1 2 3 4 5. 6",
|
396
|
+
values: "foo bar foo bar {2} {100}",
|
397
|
+
object: "foo bar foo bar {z}",
|
398
|
+
gender: "model.user.fields.gender",
|
399
|
+
name: "model.user.fields.name",
|
400
|
+
})
|
401
|
+
.expect("Set-Cookie", /^locale=de; path=\/; expires=\w+/)
|
402
|
+
.expect(200);
|
403
|
+
});
|
404
|
+
it("should mock acceptsLanguages return string", async () => {
|
405
|
+
mm(app.request, "acceptsLanguages", () => "zh-TW");
|
406
|
+
await request(app.callback())
|
407
|
+
.get("/?locale=")
|
408
|
+
.expect({
|
409
|
+
email: "郵箱",
|
410
|
+
hello: "fengmk2,今天過得如何?",
|
411
|
+
message: "Hello fengmk2, how are you today? How was your 18.",
|
412
|
+
empty: "",
|
413
|
+
notexists_key: "key not exists",
|
414
|
+
empty_string: "",
|
415
|
+
empty_value: "",
|
416
|
+
novalue: "key %s ok",
|
417
|
+
arguments3: "1 2 3",
|
418
|
+
arguments4: "1 2 3 4",
|
419
|
+
arguments5: "1 2 3 4 5",
|
420
|
+
arguments6: "1 2 3 4 5. 6",
|
421
|
+
values: "foo bar foo bar {2} {100}",
|
422
|
+
object: "foo bar foo bar {z}",
|
423
|
+
gender: "性別",
|
424
|
+
name: "姓名",
|
425
|
+
})
|
426
|
+
.expect("Set-Cookie", /^locale=zh-tw; path=\/; expires=\w+/)
|
427
|
+
.expect(200);
|
428
|
+
});
|
429
|
+
it("should mock acceptsLanguages return string", async () => {
|
430
|
+
mm(app.request, "acceptsLanguages", () => "fr");
|
431
|
+
await request(app.callback())
|
432
|
+
.get("/?locale=fr")
|
433
|
+
.set("Accept-Language", "fr;q=0.8, fr, fr")
|
434
|
+
.expect({
|
435
|
+
email: "le email",
|
436
|
+
hello: "fengmk2, Comment allez-vous",
|
437
|
+
message: "Hello fengmk2, how are you today? How was your 18.",
|
438
|
+
empty: "",
|
439
|
+
notexists_key: "key not exists",
|
440
|
+
empty_string: "",
|
441
|
+
empty_value: "",
|
442
|
+
novalue: "key %s ok",
|
443
|
+
arguments3: "1 2 3",
|
444
|
+
arguments4: "1 2 3 4",
|
445
|
+
arguments5: "1 2 3 4 5",
|
446
|
+
arguments6: "1 2 3 4 5. 6",
|
447
|
+
values: "foo bar foo bar {2} {100}",
|
448
|
+
object: "foo bar foo bar {z}",
|
449
|
+
gender: "le sexe",
|
450
|
+
name: "prénom",
|
451
|
+
})
|
452
|
+
.expect("Set-Cookie", /^locale=fr; path=\/; expires=\w+/)
|
453
|
+
.expect(200);
|
454
|
+
});
|
455
|
+
it("should mock acceptsLanguages return null", async () => {
|
456
|
+
mm(app.request, "acceptsLanguages", () => null);
|
457
|
+
await request(app.callback())
|
458
|
+
.get("/?locale=")
|
459
|
+
.expect({
|
460
|
+
email: "Email",
|
461
|
+
hello: "Hello fengmk2, how are you today?",
|
462
|
+
message: "Hello fengmk2, how are you today? How was your 18.",
|
463
|
+
empty: "",
|
464
|
+
notexists_key: "key not exists",
|
465
|
+
empty_string: "",
|
466
|
+
empty_value: "emptyValue",
|
467
|
+
novalue: "key %s ok",
|
468
|
+
arguments3: "1 2 3",
|
469
|
+
arguments4: "1 2 3 4",
|
470
|
+
arguments5: "1 2 3 4 5",
|
471
|
+
arguments6: "1 2 3 4 5. 6",
|
472
|
+
values: "foo bar foo bar {2} {100}",
|
473
|
+
object: "foo bar foo bar {z}",
|
474
|
+
gender: "model.user.fields.gender",
|
475
|
+
name: "model.user.fields.name",
|
476
|
+
})
|
477
|
+
.expect("Set-Cookie", /^locale=en-us; path=\/; expires=\w+/)
|
478
|
+
.expect(200);
|
479
|
+
});
|
480
|
+
});
|
481
|
+
describe("__getLocale and __getLocaleOrigin", () => {
|
482
|
+
it("should __getLocale and __getLocaleOrigin from cookie", async () => {
|
483
|
+
const res = await request(app.callback())
|
484
|
+
.get("/origin")
|
485
|
+
.set("cookie", "locale=de");
|
486
|
+
expect(res.body).toEqual({ locale: "de", localeOrigin: "cookie" });
|
487
|
+
});
|
488
|
+
it("should __getLocale and __getLocaleOrigin from query", async () => {
|
489
|
+
const res = await request(app.callback()).get("/origin?locale=de");
|
490
|
+
expect(res.body).toEqual({ locale: "de", localeOrigin: "query" });
|
491
|
+
});
|
492
|
+
it("should __getLocale and __getLocaleOrigin from header", async () => {
|
493
|
+
const res = await request(app.callback())
|
494
|
+
.get("/origin")
|
495
|
+
.set("Accept-Language", "zh-cn");
|
496
|
+
expect(res.body).toEqual({ locale: "zh-cn", localeOrigin: "header" });
|
497
|
+
});
|
498
|
+
it("should __getLocale and __getLocaleOrigin from default", async () => {
|
499
|
+
const res = await request(app.callback()).get("/origin");
|
500
|
+
expect(res.body).toEqual({ locale: "en-us", localeOrigin: "default" });
|
501
|
+
});
|
502
|
+
});
|
503
|
+
describe("__setLocale", () => {
|
504
|
+
it("should set locale and cookie", async () => {
|
505
|
+
const res = await request(app.callback())
|
506
|
+
.get("/set")
|
507
|
+
.set("cookie", "locale=de");
|
508
|
+
expect(res.body).toEqual({ locale: "zh-hk", localeOrigin: "set" });
|
509
|
+
expect(res.headers["set-cookie"]).toBeTruthy();
|
510
|
+
});
|
511
|
+
});
|
512
|
+
});
|
513
|
+
});
|
514
|
+
// @ts-ignore: legacy test expects any type for options
|
515
|
+
function createApp(options) {
|
516
|
+
const app = new Koa();
|
517
|
+
locales(app, options);
|
518
|
+
const fname = (options && options.functionName) || "__";
|
519
|
+
app.use(async (ctx, next) => {
|
520
|
+
if (ctx.url === "/app_locale_zh") {
|
521
|
+
ctx.body = {
|
522
|
+
// @ts-ignore: legacy test expects any type for Application index
|
523
|
+
email: ctx.app[fname]("zh-cn", "Email"),
|
524
|
+
};
|
525
|
+
return;
|
526
|
+
}
|
527
|
+
if (ctx.path === "/origin") {
|
528
|
+
ctx.body = {
|
529
|
+
locale: ctx.__getLocale(),
|
530
|
+
localeOrigin: ctx.__getLocaleOrigin(),
|
531
|
+
};
|
532
|
+
return;
|
533
|
+
}
|
534
|
+
if (ctx.path === "/set") {
|
535
|
+
ctx.__getLocale();
|
536
|
+
ctx.__setLocale("zh-tw");
|
537
|
+
ctx.__setLocale("zh-hk");
|
538
|
+
ctx.body = {
|
539
|
+
locale: ctx.__getLocale(),
|
540
|
+
localeOrigin: ctx.__getLocaleOrigin(),
|
541
|
+
};
|
542
|
+
return;
|
543
|
+
}
|
544
|
+
if (ctx.url === "/headerSent") {
|
545
|
+
ctx.body = "foo";
|
546
|
+
// @ts-ignore: legacy test expects any type for Application index
|
547
|
+
setTimeout(() => {
|
548
|
+
ctx.app[fname]("Email");
|
549
|
+
}, 50);
|
550
|
+
return;
|
551
|
+
}
|
552
|
+
ctx.body = {
|
553
|
+
email: ctx[fname]("Email"),
|
554
|
+
name: ctx[fname]("model.user.fields.name"),
|
555
|
+
gender: ctx[fname]("model.user.fields.gender"),
|
556
|
+
hello: ctx[fname]("Hello %s, how are you today?", "fengmk2"),
|
557
|
+
message: ctx[fname](
|
558
|
+
"Hello %s, how are you today? How was your %s.",
|
559
|
+
"fengmk2",
|
560
|
+
18,
|
561
|
+
),
|
562
|
+
empty: ctx[fname](),
|
563
|
+
notexists_key: ctx[fname]("key not exists"),
|
564
|
+
empty_string: ctx[fname](""),
|
565
|
+
empty_value: ctx[fname]("emptyValue"),
|
566
|
+
novalue: ctx[fname]("key %s ok"),
|
567
|
+
arguments3: ctx[fname]("%s %s %s", 1, 2, 3),
|
568
|
+
arguments4: ctx[fname]("%s %s %s %s", 1, 2, 3, 4),
|
569
|
+
arguments5: ctx[fname]("%s %s %s %s %s", 1, 2, 3, 4, 5),
|
570
|
+
arguments6: ctx[fname]("%s %s %s %s %s.", 1, 2, 3, 4, 5, 6),
|
571
|
+
values: ctx[fname]("{0} {1} {0} {1} {2} {100}", ["foo", "bar"]),
|
572
|
+
object: ctx[fname]("{foo} {bar} {foo} {bar} {z}", {
|
573
|
+
foo: "foo",
|
574
|
+
bar: "bar",
|
575
|
+
}),
|
576
|
+
};
|
577
|
+
if (next) await next();
|
578
|
+
});
|
579
|
+
return app;
|
580
|
+
}
|
package/dist/index.d.ts
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
import type Koa from "koa";
|
2
|
+
export interface LocalesOptions {
|
3
|
+
defaultLocale?: string;
|
4
|
+
queryField?: string;
|
5
|
+
cookieField?: string;
|
6
|
+
cookieDomain?: string;
|
7
|
+
localeAlias?: Record<string, string>;
|
8
|
+
writeCookie?: boolean;
|
9
|
+
cookieMaxAge?: string | number;
|
10
|
+
dir?: string;
|
11
|
+
dirs?: string[];
|
12
|
+
functionName?: string;
|
13
|
+
}
|
14
|
+
type GettextFunction = (locale: string, key: string, ...args: unknown[]) => string;
|
15
|
+
declare module "koa" {
|
16
|
+
interface Context {
|
17
|
+
__: GettextFunction;
|
18
|
+
__getLocale(): string;
|
19
|
+
__setLocale(locale: string): void;
|
20
|
+
__getLocaleOrigin(): string;
|
21
|
+
}
|
22
|
+
interface Application {
|
23
|
+
__: GettextFunction;
|
24
|
+
}
|
25
|
+
}
|
26
|
+
declare function locales(app: Koa, options?: LocalesOptions): void;
|
27
|
+
export default locales;
|