@cozeloop/intl 0.0.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/README.md +3 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -0
- package/dist/intl-client.d.ts +18 -0
- package/dist/intl-client.js +54 -0
- package/dist/intl-format.d.ts +18 -0
- package/dist/intl-format.js +45 -0
- package/dist/react-postprocessor.d.ts +7 -0
- package/dist/react-postprocessor.js +34 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +43 -0
- package/package.json +52 -0
package/README.md
ADDED
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.intlClient = void 0;
|
|
4
|
+
var intl_client_1 = require("./intl-client");
|
|
5
|
+
Object.defineProperty(exports, "intlClient", { enumerable: true, get: function () { return intl_client_1.intlClient; } });
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type DetectorOptions } from 'i18next-browser-languagedetector';
|
|
2
|
+
import { type InitOptions } from 'i18next';
|
|
3
|
+
export interface IntlClientOptions extends InitOptions {
|
|
4
|
+
/** {@link DetectorOptions} for i18next-browser-languagedetector */
|
|
5
|
+
detection?: DetectorOptions;
|
|
6
|
+
}
|
|
7
|
+
export declare class IntlClient {
|
|
8
|
+
get i18next(): import("i18next").i18n;
|
|
9
|
+
get lang(): string;
|
|
10
|
+
get language(): string;
|
|
11
|
+
setLang(lng: string): Promise<void>;
|
|
12
|
+
init(options: IntlClientOptions): Promise<void>;
|
|
13
|
+
t(key: string, defaultValue?: string): string;
|
|
14
|
+
t(key: string, interpolation?: Record<string, unknown>, defaultValue?: string): string;
|
|
15
|
+
/** i18n unsafely, **TRUST THE KEY :)** */
|
|
16
|
+
unsafeT(key: string, interpolation?: Record<string, unknown>, defaultValue?: string): string;
|
|
17
|
+
}
|
|
18
|
+
export declare const intlClient: IntlClient;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.intlClient = exports.IntlClient = void 0;
|
|
7
|
+
const i18next_browser_languagedetector_1 = __importDefault(require("i18next-browser-languagedetector"));
|
|
8
|
+
const i18next_1 = __importDefault(require("i18next"));
|
|
9
|
+
const react_postprocessor_1 = require("./react-postprocessor");
|
|
10
|
+
const intl_format_1 = require("./intl-format");
|
|
11
|
+
class IntlClient {
|
|
12
|
+
get i18next() {
|
|
13
|
+
return i18next_1.default;
|
|
14
|
+
}
|
|
15
|
+
get lang() {
|
|
16
|
+
return i18next_1.default.language;
|
|
17
|
+
}
|
|
18
|
+
get language() {
|
|
19
|
+
return i18next_1.default.language;
|
|
20
|
+
}
|
|
21
|
+
async setLang(lng) {
|
|
22
|
+
await i18next_1.default.changeLanguage(lng);
|
|
23
|
+
}
|
|
24
|
+
async init(options) {
|
|
25
|
+
await i18next_1.default
|
|
26
|
+
.use(i18next_browser_languagedetector_1.default)
|
|
27
|
+
.use(intl_format_1.IntlFormat)
|
|
28
|
+
.use(new react_postprocessor_1.ReactPostprocessor())
|
|
29
|
+
.init({
|
|
30
|
+
...options,
|
|
31
|
+
postProcess: [react_postprocessor_1.ReactPostprocessor.processorName],
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
t(key, interpolationOrDefaultValue, defaultValue) {
|
|
35
|
+
var _a, _b;
|
|
36
|
+
if (typeof interpolationOrDefaultValue === 'string') {
|
|
37
|
+
return ((_a = i18next_1.default.t(key, { defaultValue: interpolationOrDefaultValue })) !== null && _a !== void 0 ? _a : key);
|
|
38
|
+
}
|
|
39
|
+
return ((_b = i18next_1.default.t(key, { ...interpolationOrDefaultValue, defaultValue })) !== null && _b !== void 0 ? _b : key);
|
|
40
|
+
}
|
|
41
|
+
/** i18n unsafely, **TRUST THE KEY :)** */
|
|
42
|
+
unsafeT(key, interpolation, defaultValue) {
|
|
43
|
+
try {
|
|
44
|
+
return i18next_1.default.t(key, { ...interpolation, defaultValue });
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
console.warn('Unsafe translate', e);
|
|
48
|
+
return defaultValue !== null && defaultValue !== void 0 ? defaultValue : key;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.IntlClient = IntlClient;
|
|
53
|
+
exports.intlClient = new IntlClient();
|
|
54
|
+
//# sourceMappingURL=intl-client.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ModuleType, type i18n as I18next, type TOptions } from 'i18next';
|
|
2
|
+
interface Resolved {
|
|
3
|
+
res: string;
|
|
4
|
+
usedKey: string;
|
|
5
|
+
exactUsedKey: string;
|
|
6
|
+
usedLng: string;
|
|
7
|
+
usedNS: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class IntlFormat {
|
|
10
|
+
static type: ModuleType;
|
|
11
|
+
private readonly cache;
|
|
12
|
+
init(i18next: I18next): void;
|
|
13
|
+
parse(res: string, options: TOptions & Record<string, unknown>, lng: string, ns: string, key: string, info?: {
|
|
14
|
+
resolved?: Resolved;
|
|
15
|
+
}): unknown;
|
|
16
|
+
clearCache(): void;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.IntlFormat = void 0;
|
|
7
|
+
/* eslint-disable max-params -- skip */
|
|
8
|
+
const intl_messageformat_1 = __importDefault(require("intl-messageformat"));
|
|
9
|
+
const utils_1 = require("./utils");
|
|
10
|
+
class IntlFormat {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.cache = new Map();
|
|
13
|
+
}
|
|
14
|
+
init(i18next) {
|
|
15
|
+
// init with i18next
|
|
16
|
+
this.cache.clear();
|
|
17
|
+
}
|
|
18
|
+
parse(res, options, lng, ns, key, info) {
|
|
19
|
+
var _a, _b;
|
|
20
|
+
try {
|
|
21
|
+
const message = ((_a = info === null || info === void 0 ? void 0 : info.resolved) === null || _a === void 0 ? void 0 : _a.res)
|
|
22
|
+
? res
|
|
23
|
+
: `${(_b = options.defaultValue) !== null && _b !== void 0 ? _b : key}`;
|
|
24
|
+
const cacheKey = `${ns}###${key}###${res}`;
|
|
25
|
+
const messageFormat = this.cache.has(cacheKey)
|
|
26
|
+
? this.cache.get(cacheKey)
|
|
27
|
+
: this.cache
|
|
28
|
+
.set(cacheKey, new intl_messageformat_1.default(message, lng, undefined, {}))
|
|
29
|
+
.get(cacheKey);
|
|
30
|
+
return messageFormat
|
|
31
|
+
? messageFormat.format((0, utils_1.fillMissingOptions)(messageFormat, options))
|
|
32
|
+
: res;
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
console.warn(`Failed to parse ${key}, ${e}`);
|
|
36
|
+
return res;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
clearCache() {
|
|
40
|
+
this.cache.clear();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.IntlFormat = IntlFormat;
|
|
44
|
+
IntlFormat.type = 'i18nFormat';
|
|
45
|
+
//# sourceMappingURL=intl-format.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type PostProcessorModule, type TOptions } from 'i18next';
|
|
2
|
+
export declare class ReactPostprocessor implements PostProcessorModule {
|
|
3
|
+
readonly type = "postProcessor";
|
|
4
|
+
readonly name = "ReactPostprocessor";
|
|
5
|
+
static processorName: string;
|
|
6
|
+
process(value: string | unknown[], key: string | string[], options: TOptions): string;
|
|
7
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ReactPostprocessor = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
class ReactPostprocessor {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.type = 'postProcessor';
|
|
9
|
+
this.name = 'ReactPostprocessor';
|
|
10
|
+
}
|
|
11
|
+
process(value, key, options) {
|
|
12
|
+
// won't happen, only in case
|
|
13
|
+
if (!value || !value.length) {
|
|
14
|
+
return `${options.defaultValue || key}`;
|
|
15
|
+
}
|
|
16
|
+
if (Array.isArray(value)) {
|
|
17
|
+
const v = value;
|
|
18
|
+
const hasReactElements = v.some(it => (0, react_1.isValidElement)(it));
|
|
19
|
+
if (!hasReactElements) {
|
|
20
|
+
return v.map(it => (0, utils_1.stringifyVal)(it)).join('');
|
|
21
|
+
}
|
|
22
|
+
return (0, react_1.createElement)(react_1.Fragment, null, ...v.map((it, index) => {
|
|
23
|
+
var _a;
|
|
24
|
+
return (0, react_1.isValidElement)(it)
|
|
25
|
+
? (0, react_1.cloneElement)(it, { key: (_a = it.key) !== null && _a !== void 0 ? _a : index, ...it.props })
|
|
26
|
+
: (0, utils_1.stringifyVal)(it);
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.ReactPostprocessor = ReactPostprocessor;
|
|
33
|
+
ReactPostprocessor.processorName = 'ReactPostprocessor';
|
|
34
|
+
//# sourceMappingURL=react-postprocessor.js.map
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type IntlMessageFormat from 'intl-messageformat';
|
|
2
|
+
export declare function stringifyVal(val: unknown): string;
|
|
3
|
+
export declare function fillMissingOptions(messageFormat: IntlMessageFormat, options: Record<string, unknown>): {
|
|
4
|
+
[x: string]: unknown;
|
|
5
|
+
} | undefined;
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stringifyVal = stringifyVal;
|
|
4
|
+
exports.fillMissingOptions = fillMissingOptions;
|
|
5
|
+
function stringifyVal(val) {
|
|
6
|
+
switch (typeof val) {
|
|
7
|
+
case 'number':
|
|
8
|
+
case 'bigint':
|
|
9
|
+
return `${val}`;
|
|
10
|
+
case 'boolean':
|
|
11
|
+
return val ? 'true' : 'false';
|
|
12
|
+
case 'string':
|
|
13
|
+
case 'symbol':
|
|
14
|
+
return val.toString();
|
|
15
|
+
case 'object':
|
|
16
|
+
return val === null
|
|
17
|
+
? ''
|
|
18
|
+
: val instanceof Date
|
|
19
|
+
? val.toISOString()
|
|
20
|
+
: JSON.stringify(val);
|
|
21
|
+
default:
|
|
22
|
+
return '';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function fillMissingOptions(messageFormat, options) {
|
|
26
|
+
const ast = messageFormat.getAst();
|
|
27
|
+
if (!(ast === null || ast === void 0 ? void 0 : ast.length)) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
const missing = {};
|
|
31
|
+
for (const element of ast) {
|
|
32
|
+
// TYPE.ARGUMENT = 1
|
|
33
|
+
if (element.type !== 1) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (element.value in options) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
missing[element.value] = '';
|
|
40
|
+
}
|
|
41
|
+
return { ...options, ...missing };
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=utils.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cozeloop/intl",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Intl runtime For CozeLoop",
|
|
5
|
+
"author": "qihai@bytedance.com",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "exit 0",
|
|
9
|
+
"build:sdk": "tsc -b tsconfig.build.json",
|
|
10
|
+
"lint": "eslint ./ --cache",
|
|
11
|
+
"test": "vitest --run --passWithNoTests",
|
|
12
|
+
"test:cov": "npm run test -- --coverage",
|
|
13
|
+
"vitest": "vitest"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"i18next": ">= 19.0.0",
|
|
17
|
+
"i18next-browser-languagedetector": "8.0.4",
|
|
18
|
+
"intl-messageformat": "^10.7.16"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@coze-arch/eslint-config": "workspace:*",
|
|
22
|
+
"@coze-arch/ts-config": "workspace:*",
|
|
23
|
+
"@coze-arch/vitest-config": "workspace:*",
|
|
24
|
+
"@types/react": "18.2.37",
|
|
25
|
+
"@vitest/coverage-v8": "~3.0.5",
|
|
26
|
+
"react": "~18.2.0",
|
|
27
|
+
"typescript": "~5.8.2",
|
|
28
|
+
"vitest": "~3.0.5"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"react": ">=18.2.0"
|
|
32
|
+
},
|
|
33
|
+
"publishRegistries": [
|
|
34
|
+
"npm"
|
|
35
|
+
],
|
|
36
|
+
"exports": {
|
|
37
|
+
".": "./dist/index.js"
|
|
38
|
+
},
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"typesVersions": {
|
|
41
|
+
"*": {
|
|
42
|
+
".": [
|
|
43
|
+
"./dist/index.d.ts"
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"dist",
|
|
49
|
+
"README.md",
|
|
50
|
+
"CHANGELOG.md"
|
|
51
|
+
]
|
|
52
|
+
}
|