i18next-http-middleware 3.0.3 → 3.1.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/CHANGELOG.md +12 -0
- package/README.md +2 -0
- package/cjs/LanguageDetector.js +13 -1
- package/cjs/httpFunctions.js +2 -1
- package/cjs/languageLookups/cookie.js +1 -1
- package/esm/LanguageDetector.js +13 -1
- package/esm/httpFunctions.js +2 -1
- package/esm/languageLookups/cookie.js +1 -1
- package/index.d.ts +175 -0
- package/index.js +1 -0
- package/lib/LanguageDetector.js +9 -1
- package/lib/httpFunctions.js +2 -1
- package/lib/index.js +3 -3
- package/lib/languageLookups/cookie.js +1 -1
- package/lib/utils.js +2 -2
- package/package.json +23 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [v3.1.0](https://github.com/i18next/i18next-http-middleware/compare/v3.0.6...v3.1.0)
|
|
2
|
+
- added types
|
|
3
|
+
|
|
4
|
+
## [v3.0.6](https://github.com/i18next/i18next-http-middleware/compare/v3.0.5...v3.0.6)
|
|
5
|
+
- ignoreCase option true by default
|
|
6
|
+
|
|
7
|
+
## [v3.0.5](https://github.com/i18next/i18next-http-middleware/compare/v3.0.4...v3.0.5)
|
|
8
|
+
- introduce ignoreCase option
|
|
9
|
+
|
|
10
|
+
## [v3.0.4](https://github.com/i18next/i18next-http-middleware/compare/v3.0.3...v3.0.4)
|
|
11
|
+
- fix language detection algorithm to handle fallbackLng correctly
|
|
12
|
+
|
|
1
13
|
## [v3.0.3](https://github.com/i18next/i18next-http-middleware/compare/v3.0.2...v3.0.3)
|
|
2
14
|
- prevent URIError with cookie language detector
|
|
3
15
|
|
package/README.md
CHANGED
|
@@ -296,6 +296,8 @@ As with all modules you can either pass the constructor function (class) to the
|
|
|
296
296
|
// cache user language
|
|
297
297
|
caches: false, // ['cookie']
|
|
298
298
|
|
|
299
|
+
ignoreCase: true, // ignore case of detected language
|
|
300
|
+
|
|
299
301
|
// optional expire and domain for set cookie
|
|
300
302
|
cookieExpirationDate: new Date(),
|
|
301
303
|
cookieDomain: 'myDomain',
|
package/cjs/LanguageDetector.js
CHANGED
|
@@ -41,7 +41,8 @@ function getDefaults() {
|
|
|
41
41
|
lookupSession: 'lng',
|
|
42
42
|
lookupFromPathIndex: 0,
|
|
43
43
|
caches: false,
|
|
44
|
-
cookieSameSite: 'strict'
|
|
44
|
+
cookieSameSite: 'strict',
|
|
45
|
+
ignoreCase: true
|
|
45
46
|
});
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -94,6 +95,17 @@ var LanguageDetector = function () {
|
|
|
94
95
|
|
|
95
96
|
if (_this.services.languageUtils.getBestMatchFromCodes) {
|
|
96
97
|
found = _this.services.languageUtils.getBestMatchFromCodes(detections);
|
|
98
|
+
|
|
99
|
+
if (found) {
|
|
100
|
+
if (_this.options.ignoreCase) {
|
|
101
|
+
if (detections.map(function (d) {
|
|
102
|
+
return d.toLowerCase();
|
|
103
|
+
}).indexOf(found.toLowerCase()) < 0) found = undefined;
|
|
104
|
+
} else {
|
|
105
|
+
if (detections.indexOf(found) < 0) found = undefined;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
97
109
|
if (found) req.i18nextLookupName = detectorName;
|
|
98
110
|
} else {
|
|
99
111
|
found = detections.length > 0 ? detections[0] : null;
|
package/cjs/httpFunctions.js
CHANGED
|
@@ -90,7 +90,8 @@ var getCookies = function getCookies(req) {
|
|
|
90
90
|
exports.getCookies = getCookies;
|
|
91
91
|
|
|
92
92
|
var getBody = function getBody(req) {
|
|
93
|
-
if (req.ctx && req.ctx.body) return req.ctx.body.bind(req.ctx);
|
|
93
|
+
if (req.ctx && typeof req.ctx.body === 'function') return req.ctx.body.bind(req.ctx);
|
|
94
|
+
if (req.ctx && req.ctx.body) return req.ctx.body;
|
|
94
95
|
if (req.json) return req.json;
|
|
95
96
|
if (req.body) return req.body;
|
|
96
97
|
console.log('no possibility found to get body');
|
package/esm/LanguageDetector.js
CHANGED
|
@@ -20,7 +20,8 @@ function getDefaults() {
|
|
|
20
20
|
lookupSession: 'lng',
|
|
21
21
|
lookupFromPathIndex: 0,
|
|
22
22
|
caches: false,
|
|
23
|
-
cookieSameSite: 'strict'
|
|
23
|
+
cookieSameSite: 'strict',
|
|
24
|
+
ignoreCase: true
|
|
24
25
|
});
|
|
25
26
|
}
|
|
26
27
|
|
|
@@ -73,6 +74,17 @@ var LanguageDetector = function () {
|
|
|
73
74
|
|
|
74
75
|
if (_this.services.languageUtils.getBestMatchFromCodes) {
|
|
75
76
|
found = _this.services.languageUtils.getBestMatchFromCodes(detections);
|
|
77
|
+
|
|
78
|
+
if (found) {
|
|
79
|
+
if (_this.options.ignoreCase) {
|
|
80
|
+
if (detections.map(function (d) {
|
|
81
|
+
return d.toLowerCase();
|
|
82
|
+
}).indexOf(found.toLowerCase()) < 0) found = undefined;
|
|
83
|
+
} else {
|
|
84
|
+
if (detections.indexOf(found) < 0) found = undefined;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
76
88
|
if (found) req.i18nextLookupName = detectorName;
|
|
77
89
|
} else {
|
|
78
90
|
found = detections.length > 0 ? detections[0] : null;
|
package/esm/httpFunctions.js
CHANGED
|
@@ -59,7 +59,8 @@ export var getCookies = function getCookies(req) {
|
|
|
59
59
|
console.log('no possibility found to get cookies');
|
|
60
60
|
};
|
|
61
61
|
export var getBody = function getBody(req) {
|
|
62
|
-
if (req.ctx && req.ctx.body) return req.ctx.body.bind(req.ctx);
|
|
62
|
+
if (req.ctx && typeof req.ctx.body === 'function') return req.ctx.body.bind(req.ctx);
|
|
63
|
+
if (req.ctx && req.ctx.body) return req.ctx.body;
|
|
63
64
|
if (req.json) return req.json;
|
|
64
65
|
if (req.body) return req.body;
|
|
65
66
|
console.log('no possibility found to get body');
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Application,
|
|
3
|
+
Handler,
|
|
4
|
+
NextFunction,
|
|
5
|
+
Request,
|
|
6
|
+
RequestHandler,
|
|
7
|
+
Response,
|
|
8
|
+
Router,
|
|
9
|
+
} from "express-serve-static-core";
|
|
10
|
+
import * as i18next from "i18next";
|
|
11
|
+
|
|
12
|
+
/// <reference types="express-serve-static-core" />
|
|
13
|
+
|
|
14
|
+
type I18next = i18next.i18n;
|
|
15
|
+
type App = Application | Router;
|
|
16
|
+
|
|
17
|
+
type I18NextRequest = {
|
|
18
|
+
language: string;
|
|
19
|
+
languages: string[];
|
|
20
|
+
i18n: i18next.i18n;
|
|
21
|
+
t: i18next.TFunction;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
declare global {
|
|
25
|
+
namespace Express {
|
|
26
|
+
interface Request extends I18NextRequest {}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface ExtendedOptions extends Object {
|
|
31
|
+
getPath?: (req: Request) => string;
|
|
32
|
+
getOriginalUrl?: (req: Request) => string;
|
|
33
|
+
getUrl?: (req: Request) => string;
|
|
34
|
+
setUrl?: (req: Request, url: string) => void;
|
|
35
|
+
getParams?: (req: Request) => Object;
|
|
36
|
+
getSession?: (req: Request) => Object;
|
|
37
|
+
getQuery?: (req: Request) => Object;
|
|
38
|
+
getCookies?: (req: Request) => Object;
|
|
39
|
+
getBody?: (req: Request) => Object;
|
|
40
|
+
getHeaders?: (req: Request) => Object;
|
|
41
|
+
getHeader?: (res: Response, name: string) => Object;
|
|
42
|
+
setHeader?: (res: Response, name: string, value: string) => void;
|
|
43
|
+
setContentType?: (res: Response, type: string) => void;
|
|
44
|
+
setStatus?: (res: Response, code: number) => void;
|
|
45
|
+
send?: (res: Response, body: any) => void;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface HandleOptions extends ExtendedOptions {
|
|
49
|
+
ignoreRoutes?: string[] | IgnoreRoutesFunction;
|
|
50
|
+
removeLngFromUrl?: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface GetResourcesHandlerOptions extends ExtendedOptions {
|
|
54
|
+
maxAge?: number;
|
|
55
|
+
cache?: boolean;
|
|
56
|
+
lngParam?: string;
|
|
57
|
+
nsParam?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface MissingKeyHandlerOptions extends ExtendedOptions {
|
|
61
|
+
lngParam?: string;
|
|
62
|
+
nsParam?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
type IgnoreRoutesFunction = (
|
|
66
|
+
req: Request,
|
|
67
|
+
res: Response,
|
|
68
|
+
options: HandleOptions,
|
|
69
|
+
i18next: I18next
|
|
70
|
+
) => boolean;
|
|
71
|
+
|
|
72
|
+
export function handle(i18next: I18next, options?: HandleOptions): Handler;
|
|
73
|
+
|
|
74
|
+
export function plugin(
|
|
75
|
+
instance: any,
|
|
76
|
+
options: HandleOptions & { i18next?: I18next },
|
|
77
|
+
next: NextFunction
|
|
78
|
+
): Handler;
|
|
79
|
+
|
|
80
|
+
export function getResourcesHandler(
|
|
81
|
+
i18next: I18next,
|
|
82
|
+
options?: GetResourcesHandlerOptions
|
|
83
|
+
): Handler;
|
|
84
|
+
|
|
85
|
+
export function missingKeyHandler(
|
|
86
|
+
i18next: I18next,
|
|
87
|
+
options?: MissingKeyHandlerOptions
|
|
88
|
+
): Handler;
|
|
89
|
+
|
|
90
|
+
export function addRoute(
|
|
91
|
+
i18next: I18next,
|
|
92
|
+
route: string,
|
|
93
|
+
lngs: string[],
|
|
94
|
+
app: App,
|
|
95
|
+
verb: string,
|
|
96
|
+
fc: RequestHandler
|
|
97
|
+
): void;
|
|
98
|
+
|
|
99
|
+
// LanguageDetector
|
|
100
|
+
type LanguageDetectorServices = any;
|
|
101
|
+
type LanguageDetectorOrder = string[];
|
|
102
|
+
type LanguageDetectorCaches = boolean | string[];
|
|
103
|
+
interface LanguageDetectorOptions {
|
|
104
|
+
order?: LanguageDetectorOrder;
|
|
105
|
+
lookupQuerystring?: string;
|
|
106
|
+
lookupCookie?: string;
|
|
107
|
+
lookupSession?: string;
|
|
108
|
+
lookupFromPathIndex?: number;
|
|
109
|
+
caches?: LanguageDetectorCaches;
|
|
110
|
+
cookieExpirationDate?: Date;
|
|
111
|
+
cookieDomain?: string;
|
|
112
|
+
}
|
|
113
|
+
interface LanguageDetectorAllOptions {
|
|
114
|
+
fallbackLng: boolean | string | string[];
|
|
115
|
+
}
|
|
116
|
+
interface LanguageDetectorInterfaceOptions {
|
|
117
|
+
[name: string]: any;
|
|
118
|
+
}
|
|
119
|
+
interface LanguageDetectorInterface {
|
|
120
|
+
name: string;
|
|
121
|
+
|
|
122
|
+
lookup: (
|
|
123
|
+
req: Request,
|
|
124
|
+
res: Response,
|
|
125
|
+
options?: LanguageDetectorInterfaceOptions
|
|
126
|
+
) => string | string[];
|
|
127
|
+
|
|
128
|
+
cacheUserLanguage?: (
|
|
129
|
+
req: Request,
|
|
130
|
+
res: Response,
|
|
131
|
+
lng: string,
|
|
132
|
+
options?: Object
|
|
133
|
+
) => void;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export class LanguageDetector implements i18next.Module {
|
|
137
|
+
type: "languageDetector";
|
|
138
|
+
|
|
139
|
+
constructor(
|
|
140
|
+
services: LanguageDetectorServices,
|
|
141
|
+
options?: LanguageDetectorOptions,
|
|
142
|
+
allOptions?: LanguageDetectorAllOptions
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
constructor(
|
|
146
|
+
options?: LanguageDetectorOptions,
|
|
147
|
+
allOptions?: LanguageDetectorAllOptions
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
init(
|
|
151
|
+
services: LanguageDetectorServices,
|
|
152
|
+
options?: LanguageDetectorOptions,
|
|
153
|
+
allOptions?: LanguageDetectorAllOptions
|
|
154
|
+
): void;
|
|
155
|
+
|
|
156
|
+
init(
|
|
157
|
+
options?: LanguageDetectorOptions,
|
|
158
|
+
allOptions?: LanguageDetectorAllOptions
|
|
159
|
+
): void;
|
|
160
|
+
|
|
161
|
+
addDetector(detector: LanguageDetectorInterface): void;
|
|
162
|
+
|
|
163
|
+
detect(
|
|
164
|
+
req: Request,
|
|
165
|
+
res: Response,
|
|
166
|
+
detectionOrder: LanguageDetectorOrder
|
|
167
|
+
): void;
|
|
168
|
+
|
|
169
|
+
cacheUserLanguage(
|
|
170
|
+
req: Request,
|
|
171
|
+
res: Response,
|
|
172
|
+
lng: string,
|
|
173
|
+
caches: LanguageDetectorCaches
|
|
174
|
+
): void;
|
|
175
|
+
}
|
package/index.js
CHANGED
package/lib/LanguageDetector.js
CHANGED
|
@@ -19,7 +19,8 @@ function getDefaults () {
|
|
|
19
19
|
// cookieExpirationDate: new Date(),
|
|
20
20
|
// cookieDomain: 'myDomain'
|
|
21
21
|
// cookiePath: '/my/path'
|
|
22
|
-
cookieSameSite: 'strict'
|
|
22
|
+
cookieSameSite: 'strict',
|
|
23
|
+
ignoreCase: true
|
|
23
24
|
})
|
|
24
25
|
}
|
|
25
26
|
|
|
@@ -61,6 +62,13 @@ class LanguageDetector {
|
|
|
61
62
|
|
|
62
63
|
if (this.services.languageUtils.getBestMatchFromCodes) { // new i18next v19.5.0
|
|
63
64
|
found = this.services.languageUtils.getBestMatchFromCodes(detections)
|
|
65
|
+
if (found) {
|
|
66
|
+
if (this.options.ignoreCase) {
|
|
67
|
+
if (detections.map(d => d.toLowerCase()).indexOf(found.toLowerCase()) < 0) found = undefined
|
|
68
|
+
} else {
|
|
69
|
+
if (detections.indexOf(found) < 0) found = undefined
|
|
70
|
+
}
|
|
71
|
+
}
|
|
64
72
|
if (found) req.i18nextLookupName = detectorName
|
|
65
73
|
} else {
|
|
66
74
|
found = detections.length > 0 ? detections[0] : null // a little backward compatibility
|
package/lib/httpFunctions.js
CHANGED
|
@@ -56,7 +56,8 @@ export const getCookies = (req) => {
|
|
|
56
56
|
console.log('no possibility found to get cookies')
|
|
57
57
|
}
|
|
58
58
|
export const getBody = (req) => {
|
|
59
|
-
if (req.ctx && req.ctx.body) return req.ctx.body.bind(req.ctx)
|
|
59
|
+
if (req.ctx && typeof req.ctx.body === 'function') return req.ctx.body.bind(req.ctx)
|
|
60
|
+
if (req.ctx && req.ctx.body) return req.ctx.body
|
|
60
61
|
if (req.json) return req.json
|
|
61
62
|
if (req.body) return req.body
|
|
62
63
|
console.log('no possibility found to get body')
|
package/lib/index.js
CHANGED
|
@@ -31,7 +31,7 @@ export function handle (i18next, options = {}) {
|
|
|
31
31
|
}
|
|
32
32
|
} else {
|
|
33
33
|
const ignores = (options.ignoreRoutes instanceof Array && options.ignoreRoutes) || []
|
|
34
|
-
for (
|
|
34
|
+
for (let i = 0; i < ignores.length; i++) {
|
|
35
35
|
if (options.getPath(req).indexOf(ignores[i]) > -1) return next()
|
|
36
36
|
}
|
|
37
37
|
}
|
|
@@ -167,7 +167,7 @@ export function missingKeyHandler (i18next, options = {}) {
|
|
|
167
167
|
if (promise && typeof promise.then === 'function') {
|
|
168
168
|
return new Promise((resolve) => {
|
|
169
169
|
promise.then((b) => {
|
|
170
|
-
for (
|
|
170
|
+
for (const m in b) {
|
|
171
171
|
i18next.services.backendConnector.saveMissing([lng], ns, m, b[m])
|
|
172
172
|
}
|
|
173
173
|
resolve(options.send(res, 'ok'))
|
|
@@ -176,7 +176,7 @@ export function missingKeyHandler (i18next, options = {}) {
|
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
for (
|
|
179
|
+
for (const m in body) {
|
|
180
180
|
i18next.services.backendConnector.saveMissing([lng], ns, m, body[m])
|
|
181
181
|
}
|
|
182
182
|
|
package/lib/utils.js
CHANGED
|
@@ -22,7 +22,7 @@ const slice = arr.slice
|
|
|
22
22
|
export function defaults (obj) {
|
|
23
23
|
each.call(slice.call(arguments, 1), function (source) {
|
|
24
24
|
if (source) {
|
|
25
|
-
for (
|
|
25
|
+
for (const prop in source) {
|
|
26
26
|
if (obj[prop] === undefined) obj[prop] = source[prop]
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -33,7 +33,7 @@ export function defaults (obj) {
|
|
|
33
33
|
export function extend (obj) {
|
|
34
34
|
each.call(slice.call(arguments, 1), function (source) {
|
|
35
35
|
if (source) {
|
|
36
|
-
for (
|
|
36
|
+
for (const prop in source) {
|
|
37
37
|
obj[prop] = source[prop]
|
|
38
38
|
}
|
|
39
39
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "i18next-http-middleware",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./cjs/index.js",
|
|
7
|
+
"types": "./index.d.ts",
|
|
7
8
|
"exports": {
|
|
8
9
|
"./package.json": "./package.json",
|
|
9
10
|
".": {
|
|
@@ -20,24 +21,26 @@
|
|
|
20
21
|
"module": "./esm/index.js",
|
|
21
22
|
"dependencies": {},
|
|
22
23
|
"devDependencies": {
|
|
23
|
-
"@babel/cli": "7.10
|
|
24
|
-
"@babel/core": "7.
|
|
25
|
-
"@babel/preset-env": "7.11
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"eslint
|
|
29
|
-
"eslint-
|
|
24
|
+
"@babel/cli": "7.12.10",
|
|
25
|
+
"@babel/core": "7.12.10",
|
|
26
|
+
"@babel/preset-env": "7.12.11",
|
|
27
|
+
"@types/express-serve-static-core": "^4.17.18",
|
|
28
|
+
"babel-plugin-add-module-exports": "1.0.4",
|
|
29
|
+
"eslint": "7.17.0",
|
|
30
|
+
"eslint-config-standard": "16.0.2",
|
|
31
|
+
"eslint-plugin-import": "2.22.1",
|
|
30
32
|
"eslint-plugin-node": "11.1.0",
|
|
31
33
|
"eslint-plugin-promise": "4.2.1",
|
|
32
34
|
"eslint-plugin-require-path-exists": "1.1.9",
|
|
33
|
-
"eslint-plugin-standard": "
|
|
35
|
+
"eslint-plugin-standard": "5.0.0",
|
|
34
36
|
"expect.js": "0.3.1",
|
|
35
37
|
"express": "4.17.1",
|
|
36
|
-
"fastify": "3.
|
|
37
|
-
"i18next": "19.
|
|
38
|
-
"mocha": "8.1
|
|
39
|
-
"supertest": "
|
|
40
|
-
"
|
|
38
|
+
"fastify": "3.9.2",
|
|
39
|
+
"i18next": "19.8.4",
|
|
40
|
+
"mocha": "8.2.1",
|
|
41
|
+
"supertest": "6.0.1",
|
|
42
|
+
"tsd": "0.14.0",
|
|
43
|
+
"uglify-js": "3.12.4"
|
|
41
44
|
},
|
|
42
45
|
"description": "i18next-http-middleware is a middleware to be used with Node.js web frameworks like express or Fastify and also for Deno.",
|
|
43
46
|
"keywords": [
|
|
@@ -66,9 +69,13 @@
|
|
|
66
69
|
"compile:cjs": "rm -rf cjs && mkdir cjs && BABEL_ENV=cjs babel lib -d cjs && echo '{\"type\":\"commonjs\"}' > cjs/package.json",
|
|
67
70
|
"compile": "npm run compile:esm && npm run compile:cjs",
|
|
68
71
|
"build": "npm run compile",
|
|
69
|
-
"test": "npm run lint && npm run build && mocha test -R spec --exit --experimental-modules",
|
|
70
|
-
"test:deno": "deno test test/deno/*.js
|
|
72
|
+
"test": "npm run lint && npm run build && mocha test -R spec --exit --experimental-modules && npm run test:types",
|
|
73
|
+
"test:deno": "deno test --allow-net test/deno/*.js",
|
|
74
|
+
"test:types": "tsd",
|
|
71
75
|
"preversion": "npm run test && npm run build && git push",
|
|
72
76
|
"postversion": "git push && git push --tags"
|
|
77
|
+
},
|
|
78
|
+
"tsd": {
|
|
79
|
+
"directory": "test/types"
|
|
73
80
|
}
|
|
74
81
|
}
|