@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 ADDED
@@ -0,0 +1,3 @@
1
+ # @cozeloop/intl
2
+
3
+ Internationalization(intl) runtime for CozeLoop
@@ -0,0 +1,2 @@
1
+ export { intlClient } from './intl-client';
2
+ export type { IntlClientOptions } from './intl-client';
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
@@ -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
+ }