@windrun-huaiin/lib 15.1.0 → 16.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 +1 -1
- package/dist/i18n-server.d.ts +15 -0
- package/dist/i18n-server.d.ts.map +1 -0
- package/dist/i18n-server.js +60 -0
- package/dist/i18n-server.mjs +58 -0
- package/dist/i18n-utils.d.ts +3 -0
- package/dist/i18n-utils.d.ts.map +1 -0
- package/dist/i18n-utils.js +20 -0
- package/dist/i18n-utils.mjs +17 -0
- package/package.json +11 -1
- package/src/i18n-server.ts +77 -0
- package/src/i18n-utils.ts +23 -0
package/LICENSE
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface RuntimeMessageFileSource {
|
|
2
|
+
type: 'file';
|
|
3
|
+
path?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface RuntimeMessageDirectorySource {
|
|
6
|
+
type: 'dir';
|
|
7
|
+
path: string;
|
|
8
|
+
}
|
|
9
|
+
export type RuntimeMessageSource = RuntimeMessageFileSource | RuntimeMessageDirectorySource;
|
|
10
|
+
export declare function loadMergedLocaleMessages(options: {
|
|
11
|
+
locale: string;
|
|
12
|
+
messagesRoot: string;
|
|
13
|
+
sources: readonly RuntimeMessageSource[];
|
|
14
|
+
}): Promise<Record<string, unknown>>;
|
|
15
|
+
//# sourceMappingURL=i18n-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n-server.d.ts","sourceRoot":"","sources":["../src/i18n-server.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,KAAK,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,oBAAoB,GAAG,wBAAwB,GAAG,6BAA6B,CAAC;AAiC5F,wBAAsB,wBAAwB,CAAC,OAAO,EAAE;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,SAAS,oBAAoB,EAAE,CAAC;CAC1C,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAyBnC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var tslib = require('tslib');
|
|
4
|
+
var promises = require('fs/promises');
|
|
5
|
+
var path = require('path');
|
|
6
|
+
var i18nUtils = require('./i18n-utils.js');
|
|
7
|
+
|
|
8
|
+
function readMessageFile(filePath) {
|
|
9
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
10
|
+
const content = yield promises.readFile(filePath, 'utf8');
|
|
11
|
+
return JSON.parse(content);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
function collectLocaleFiles(dirPath, locale) {
|
|
15
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
16
|
+
try {
|
|
17
|
+
const entries = yield promises.readdir(dirPath, { withFileTypes: true });
|
|
18
|
+
const nestedFiles = yield Promise.all(entries.map((entry) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
19
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
20
|
+
if (entry.isDirectory()) {
|
|
21
|
+
return collectLocaleFiles(fullPath, locale);
|
|
22
|
+
}
|
|
23
|
+
return entry.isFile() && entry.name.endsWith(`.${locale}.json`) ? [fullPath] : [];
|
|
24
|
+
})));
|
|
25
|
+
return nestedFiles.flat().sort((left, right) => left.localeCompare(right));
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
const nodeError = error;
|
|
29
|
+
if (nodeError.code === 'ENOENT') {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function loadMergedLocaleMessages(options) {
|
|
37
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
const { locale, messagesRoot, sources } = options;
|
|
39
|
+
let mergedMessages = {};
|
|
40
|
+
for (const source of sources) {
|
|
41
|
+
if (source.type === 'file') {
|
|
42
|
+
const filePath = source.path
|
|
43
|
+
? path.join(messagesRoot, source.path, `${locale}.json`)
|
|
44
|
+
: path.join(messagesRoot, `${locale}.json`);
|
|
45
|
+
const fileMessages = yield readMessageFile(filePath);
|
|
46
|
+
mergedMessages = i18nUtils.deepMergeMessages(mergedMessages, fileMessages);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const dirPath = path.join(messagesRoot, source.path);
|
|
50
|
+
const filePaths = yield collectLocaleFiles(dirPath, locale);
|
|
51
|
+
for (const filePath of filePaths) {
|
|
52
|
+
const fileMessages = yield readMessageFile(filePath);
|
|
53
|
+
mergedMessages = i18nUtils.deepMergeMessages(mergedMessages, fileMessages);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return mergedMessages;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
exports.loadMergedLocaleMessages = loadMergedLocaleMessages;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { __awaiter } from 'tslib';
|
|
2
|
+
import { readFile, readdir } from 'fs/promises';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { deepMergeMessages } from './i18n-utils.mjs';
|
|
5
|
+
|
|
6
|
+
function readMessageFile(filePath) {
|
|
7
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
8
|
+
const content = yield readFile(filePath, 'utf8');
|
|
9
|
+
return JSON.parse(content);
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
function collectLocaleFiles(dirPath, locale) {
|
|
13
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
14
|
+
try {
|
|
15
|
+
const entries = yield readdir(dirPath, { withFileTypes: true });
|
|
16
|
+
const nestedFiles = yield Promise.all(entries.map((entry) => __awaiter(this, void 0, void 0, function* () {
|
|
17
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
18
|
+
if (entry.isDirectory()) {
|
|
19
|
+
return collectLocaleFiles(fullPath, locale);
|
|
20
|
+
}
|
|
21
|
+
return entry.isFile() && entry.name.endsWith(`.${locale}.json`) ? [fullPath] : [];
|
|
22
|
+
})));
|
|
23
|
+
return nestedFiles.flat().sort((left, right) => left.localeCompare(right));
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
const nodeError = error;
|
|
27
|
+
if (nodeError.code === 'ENOENT') {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function loadMergedLocaleMessages(options) {
|
|
35
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
+
const { locale, messagesRoot, sources } = options;
|
|
37
|
+
let mergedMessages = {};
|
|
38
|
+
for (const source of sources) {
|
|
39
|
+
if (source.type === 'file') {
|
|
40
|
+
const filePath = source.path
|
|
41
|
+
? path.join(messagesRoot, source.path, `${locale}.json`)
|
|
42
|
+
: path.join(messagesRoot, `${locale}.json`);
|
|
43
|
+
const fileMessages = yield readMessageFile(filePath);
|
|
44
|
+
mergedMessages = deepMergeMessages(mergedMessages, fileMessages);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const dirPath = path.join(messagesRoot, source.path);
|
|
48
|
+
const filePaths = yield collectLocaleFiles(dirPath, locale);
|
|
49
|
+
for (const filePath of filePaths) {
|
|
50
|
+
const fileMessages = yield readMessageFile(filePath);
|
|
51
|
+
mergedMessages = deepMergeMessages(mergedMessages, fileMessages);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return mergedMessages;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { loadMergedLocaleMessages };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n-utils.d.ts","sourceRoot":"","sources":["../src/i18n-utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAE9E;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAezB"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function isPlainObject(value) {
|
|
4
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
5
|
+
}
|
|
6
|
+
function deepMergeMessages(base, extra) {
|
|
7
|
+
const result = Object.assign({}, base);
|
|
8
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
9
|
+
const current = result[key];
|
|
10
|
+
if (isPlainObject(current) && isPlainObject(value)) {
|
|
11
|
+
result[key] = deepMergeMessages(current, value);
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
result[key] = value;
|
|
15
|
+
}
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
exports.deepMergeMessages = deepMergeMessages;
|
|
20
|
+
exports.isPlainObject = isPlainObject;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
function isPlainObject(value) {
|
|
2
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
3
|
+
}
|
|
4
|
+
function deepMergeMessages(base, extra) {
|
|
5
|
+
const result = Object.assign({}, base);
|
|
6
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
7
|
+
const current = result[key];
|
|
8
|
+
if (isPlainObject(current) && isPlainObject(value)) {
|
|
9
|
+
result[key] = deepMergeMessages(current, value);
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
result[key] = value;
|
|
13
|
+
}
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { deepMergeMessages, isPlainObject };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windrun-huaiin/lib",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "16.0.0",
|
|
4
4
|
"description": "Common utilities and configuration",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -26,6 +26,16 @@
|
|
|
26
26
|
"import": "./dist/common-app-config.mjs",
|
|
27
27
|
"require": "./dist/common-app-config.js"
|
|
28
28
|
},
|
|
29
|
+
"./i18n-utils": {
|
|
30
|
+
"types": "./dist/i18n-utils.d.ts",
|
|
31
|
+
"import": "./dist/i18n-utils.mjs",
|
|
32
|
+
"require": "./dist/i18n-utils.js"
|
|
33
|
+
},
|
|
34
|
+
"./i18n-server": {
|
|
35
|
+
"types": "./dist/i18n-server.d.ts",
|
|
36
|
+
"import": "./dist/i18n-server.mjs",
|
|
37
|
+
"require": "./dist/i18n-server.js"
|
|
38
|
+
},
|
|
29
39
|
"./package.json": "./package.json"
|
|
30
40
|
},
|
|
31
41
|
"files": [
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { readdir, readFile } from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { deepMergeMessages } from './i18n-utils';
|
|
4
|
+
|
|
5
|
+
export interface RuntimeMessageFileSource {
|
|
6
|
+
type: 'file';
|
|
7
|
+
path?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface RuntimeMessageDirectorySource {
|
|
11
|
+
type: 'dir';
|
|
12
|
+
path: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type RuntimeMessageSource = RuntimeMessageFileSource | RuntimeMessageDirectorySource;
|
|
16
|
+
|
|
17
|
+
async function readMessageFile(filePath: string): Promise<Record<string, unknown>> {
|
|
18
|
+
const content = await readFile(filePath, 'utf8');
|
|
19
|
+
return JSON.parse(content) as Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function collectLocaleFiles(dirPath: string, locale: string): Promise<string[]> {
|
|
23
|
+
try {
|
|
24
|
+
const entries = await readdir(dirPath, { withFileTypes: true });
|
|
25
|
+
const nestedFiles = await Promise.all(
|
|
26
|
+
entries.map(async entry => {
|
|
27
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
28
|
+
|
|
29
|
+
if (entry.isDirectory()) {
|
|
30
|
+
return collectLocaleFiles(fullPath, locale);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return entry.isFile() && entry.name.endsWith(`.${locale}.json`) ? [fullPath] : [];
|
|
34
|
+
})
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
return nestedFiles.flat().sort((left, right) => left.localeCompare(right));
|
|
38
|
+
} catch (error) {
|
|
39
|
+
const nodeError = error as NodeJS.ErrnoException;
|
|
40
|
+
if (nodeError.code === 'ENOENT') {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function loadMergedLocaleMessages(options: {
|
|
49
|
+
locale: string;
|
|
50
|
+
messagesRoot: string;
|
|
51
|
+
sources: readonly RuntimeMessageSource[];
|
|
52
|
+
}): Promise<Record<string, unknown>> {
|
|
53
|
+
const { locale, messagesRoot, sources } = options;
|
|
54
|
+
|
|
55
|
+
let mergedMessages: Record<string, unknown> = {};
|
|
56
|
+
|
|
57
|
+
for (const source of sources) {
|
|
58
|
+
if (source.type === 'file') {
|
|
59
|
+
const filePath = source.path
|
|
60
|
+
? path.join(messagesRoot, source.path, `${locale}.json`)
|
|
61
|
+
: path.join(messagesRoot, `${locale}.json`);
|
|
62
|
+
const fileMessages = await readMessageFile(filePath);
|
|
63
|
+
mergedMessages = deepMergeMessages(mergedMessages, fileMessages);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const dirPath = path.join(messagesRoot, source.path);
|
|
68
|
+
const filePaths = await collectLocaleFiles(dirPath, locale);
|
|
69
|
+
|
|
70
|
+
for (const filePath of filePaths) {
|
|
71
|
+
const fileMessages = await readMessageFile(filePath);
|
|
72
|
+
mergedMessages = deepMergeMessages(mergedMessages, fileMessages);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return mergedMessages;
|
|
77
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
2
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function deepMergeMessages(
|
|
6
|
+
base: Record<string, unknown>,
|
|
7
|
+
extra: Record<string, unknown>
|
|
8
|
+
): Record<string, unknown> {
|
|
9
|
+
const result: Record<string, unknown> = { ...base };
|
|
10
|
+
|
|
11
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
12
|
+
const current = result[key];
|
|
13
|
+
|
|
14
|
+
if (isPlainObject(current) && isPlainObject(value)) {
|
|
15
|
+
result[key] = deepMergeMessages(current, value);
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
result[key] = value;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return result;
|
|
23
|
+
}
|