@lytjs/plugin-i18n 5.0.1 → 6.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/dist/index.cjs +151 -1
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +65 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.mjs +145 -1
- package/dist/index.mjs.map +1 -0
- package/package.json +32 -25
- package/README.md +0 -145
- package/dist/types/index.d.ts +0 -55
- package/dist/types/index.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1 +1,151 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var core = require('@lytjs/core');
|
|
6
|
+
var reactivity = require('@lytjs/reactivity');
|
|
7
|
+
var commonIs = require('@lytjs/common-is');
|
|
8
|
+
|
|
9
|
+
// src/index.ts
|
|
10
|
+
function deepClone(obj) {
|
|
11
|
+
if (obj === null || typeof obj !== "object") {
|
|
12
|
+
return obj;
|
|
13
|
+
}
|
|
14
|
+
if (Array.isArray(obj)) {
|
|
15
|
+
return obj.map(deepClone);
|
|
16
|
+
}
|
|
17
|
+
const cloned = {};
|
|
18
|
+
for (const key in obj) {
|
|
19
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
20
|
+
cloned[key] = deepClone(obj[key]);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return cloned;
|
|
24
|
+
}
|
|
25
|
+
function createI18n(options = {}) {
|
|
26
|
+
const {
|
|
27
|
+
locale: defaultLocale = "zh-CN",
|
|
28
|
+
fallbackLocale = "en-US",
|
|
29
|
+
messages = {},
|
|
30
|
+
warnHtmlMessage = true
|
|
31
|
+
} = options;
|
|
32
|
+
const currentLocale = reactivity.signal(defaultLocale);
|
|
33
|
+
const availableLocalesState = reactivity.signal(Object.keys(messages));
|
|
34
|
+
const localeMessages = deepClone(messages);
|
|
35
|
+
function getNestedValue(obj, path) {
|
|
36
|
+
const keys = path.split(".");
|
|
37
|
+
let current = obj;
|
|
38
|
+
for (const key of keys) {
|
|
39
|
+
if (!commonIs.isObject(current) || !(key in current)) {
|
|
40
|
+
return void 0;
|
|
41
|
+
}
|
|
42
|
+
current = current[key];
|
|
43
|
+
}
|
|
44
|
+
return commonIs.isString(current) ? current : void 0;
|
|
45
|
+
}
|
|
46
|
+
function interpolate(message, args) {
|
|
47
|
+
if (args.length === 0) return message;
|
|
48
|
+
return message.replace(/\{(\w+)\}/g, (match, key) => {
|
|
49
|
+
const index = parseInt(key, 10);
|
|
50
|
+
if (!isNaN(index)) {
|
|
51
|
+
return args[index] !== void 0 ? String(args[index]) : match;
|
|
52
|
+
}
|
|
53
|
+
if (commonIs.isObject(args[0])) {
|
|
54
|
+
return args[0][key] !== void 0 ? String(args[0][key]) : match;
|
|
55
|
+
}
|
|
56
|
+
return match;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function t(key, ...args) {
|
|
60
|
+
const locale = currentLocale();
|
|
61
|
+
const msgs = localeMessages[locale];
|
|
62
|
+
const fallbackMessages = localeMessages[fallbackLocale];
|
|
63
|
+
let message = msgs ? getNestedValue(msgs, key) : void 0;
|
|
64
|
+
if (!message && fallbackMessages) {
|
|
65
|
+
message = getNestedValue(fallbackMessages, key);
|
|
66
|
+
}
|
|
67
|
+
if (!message) {
|
|
68
|
+
if (warnHtmlMessage) {
|
|
69
|
+
console.warn(`[i18n] Missing translation for key: "${key}"`);
|
|
70
|
+
}
|
|
71
|
+
return key;
|
|
72
|
+
}
|
|
73
|
+
return interpolate(message, args);
|
|
74
|
+
}
|
|
75
|
+
function te(key, locale) {
|
|
76
|
+
const targetLocale = locale || currentLocale();
|
|
77
|
+
const msgs = localeMessages[targetLocale];
|
|
78
|
+
if (!msgs) return false;
|
|
79
|
+
return getNestedValue(msgs, key) !== void 0;
|
|
80
|
+
}
|
|
81
|
+
function setLocale(locale) {
|
|
82
|
+
currentLocale.set(locale);
|
|
83
|
+
}
|
|
84
|
+
function registerLocale2(locale, messages2) {
|
|
85
|
+
if (!localeMessages[locale]) {
|
|
86
|
+
localeMessages[locale] = {};
|
|
87
|
+
const newLocales = [...Object.keys(localeMessages)];
|
|
88
|
+
availableLocalesState.set(newLocales);
|
|
89
|
+
}
|
|
90
|
+
localeMessages[locale] = {
|
|
91
|
+
...localeMessages[locale],
|
|
92
|
+
...deepClone(messages2)
|
|
93
|
+
};
|
|
94
|
+
console.log(`[i18n] Locale "${locale}" registered successfully`);
|
|
95
|
+
}
|
|
96
|
+
function getMessages() {
|
|
97
|
+
return deepClone(localeMessages);
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
locale: {
|
|
101
|
+
get value() {
|
|
102
|
+
return currentLocale();
|
|
103
|
+
},
|
|
104
|
+
set value(v) {
|
|
105
|
+
currentLocale.set(v);
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
setLocale,
|
|
109
|
+
t,
|
|
110
|
+
te,
|
|
111
|
+
get availableLocales() {
|
|
112
|
+
return availableLocalesState();
|
|
113
|
+
},
|
|
114
|
+
registerLocale: registerLocale2,
|
|
115
|
+
getMessages
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function registerLocale(i18n, locale, messages) {
|
|
119
|
+
i18n.registerLocale(locale, messages);
|
|
120
|
+
}
|
|
121
|
+
var pluginI18n = core.definePlugin({
|
|
122
|
+
name: "i18n",
|
|
123
|
+
version: "6.0.0",
|
|
124
|
+
description: "LytJS official i18n plugin for internationalization and localization support",
|
|
125
|
+
author: "LytJS Team",
|
|
126
|
+
keywords: ["lytjs", "i18n", "internationalization", "localization"],
|
|
127
|
+
schema: {
|
|
128
|
+
type: "object",
|
|
129
|
+
object: {
|
|
130
|
+
properties: {
|
|
131
|
+
locale: { type: "string", default: "zh-CN" },
|
|
132
|
+
fallbackLocale: { type: "string", default: "en-US" },
|
|
133
|
+
messages: { type: "object", default: {} },
|
|
134
|
+
warnHtmlMessage: { type: "boolean", default: true }
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
install(app, options) {
|
|
139
|
+
const i18n = createI18n(options);
|
|
140
|
+
app.config.globalProperties.$i18n = i18n;
|
|
141
|
+
app.config.globalProperties.$t = i18n.t;
|
|
142
|
+
app.provide("lyt-i18n", i18n);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
var index_default = pluginI18n;
|
|
146
|
+
|
|
147
|
+
exports.createI18n = createI18n;
|
|
148
|
+
exports.default = index_default;
|
|
149
|
+
exports.registerLocale = registerLocale;
|
|
150
|
+
//# sourceMappingURL=index.cjs.map
|
|
151
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["signal","isObject","isString","registerLocale","messages","definePlugin"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\r\n * @lytjs/plugin-i18n\r\n *\r\n * LytJS official i18n plugin for internationalization and localization support.\r\n *\r\n * @packageDocumentation\r\n */\r\n\r\nimport { definePlugin } from '@lytjs/core';\r\nimport { signal } from '@lytjs/reactivity';\r\nimport { isString, isObject } from '@lytjs/common-is';\r\nimport type { I18nOptions, I18nInstance, Locale, LocaleMessages, TranslateFn } from './types';\r\n\r\n/**\r\n * 深度克隆对象,防止直接修改\r\n */\r\nfunction deepClone<T>(obj: T): T {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n if (Array.isArray(obj)) {\r\n return obj.map(deepClone) as T;\r\n }\r\n\r\n const cloned = {} as Record<string, any>;\r\n for (const key in obj) {\r\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\r\n cloned[key] = deepClone((obj as Record<string, any>)[key]);\r\n }\r\n }\r\n return cloned as T;\r\n}\r\n\r\n/**\r\n * 创建 i18n 实例\r\n */\r\nfunction createI18n(options: I18nOptions = {}): I18nInstance {\r\n const {\r\n locale: defaultLocale = 'zh-CN',\r\n fallbackLocale = 'en-US',\r\n messages = {},\r\n warnHtmlMessage = true,\r\n } = options;\r\n\r\n // 当前语言\r\n const currentLocale = signal(defaultLocale);\r\n\r\n // 可用语言列表(响应式)\r\n const availableLocalesState = signal<string[]>(Object.keys(messages));\r\n\r\n // 语言包存储(深度克隆以防止外部修改)\r\n const localeMessages: Locale = deepClone(messages);\r\n\r\n /**\r\n * 获取嵌套对象的值\r\n */\r\n function getNestedValue(obj: LocaleMessages, path: string): string | undefined {\r\n const keys = path.split('.');\r\n let current: any = obj;\r\n\r\n for (const key of keys) {\r\n if (!isObject(current) || !(key in current)) {\r\n return undefined;\r\n }\r\n current = current[key as keyof typeof current];\r\n }\r\n\r\n return isString(current) ? current : undefined;\r\n }\r\n\r\n /**\r\n * 替换插值\r\n */\r\n function interpolate(message: string, args: any[]): string {\r\n if (args.length === 0) return message;\r\n\r\n // 支持命名参数 {name} 和位置参数 {0}\r\n return message.replace(/\\{(\\w+)\\}/g, (match, key) => {\r\n const index = parseInt(key, 10);\r\n if (!isNaN(index)) {\r\n return args[index] !== undefined ? String(args[index]) : match;\r\n }\r\n // 命名参数(从对象中获取)\r\n if (isObject(args[0])) {\r\n return (args[0] as Record<string, any>)[key] !== undefined\r\n ? String((args[0] as Record<string, any>)[key])\r\n : match;\r\n }\r\n return match;\r\n });\r\n }\r\n\r\n /**\r\n * 翻译函数\r\n */\r\n function t(key: string, ...args: any[]): string {\r\n const locale = currentLocale();\r\n const msgs = localeMessages[locale];\r\n const fallbackMessages = localeMessages[fallbackLocale];\r\n\r\n // 尝试获取翻译\r\n let message = msgs ? getNestedValue(msgs, key) : undefined;\r\n\r\n // 回退到默认语言\r\n if (!message && fallbackMessages) {\r\n message = getNestedValue(fallbackMessages, key);\r\n }\r\n\r\n // 找不到翻译,返回 key\r\n if (!message) {\r\n if (warnHtmlMessage) {\r\n console.warn(`[i18n] Missing translation for key: \"${key}\"`);\r\n }\r\n return key;\r\n }\r\n\r\n return interpolate(message, args);\r\n }\r\n\r\n /**\r\n * 检查翻译是否存在\r\n */\r\n function te(key: string, locale?: string): boolean {\r\n const targetLocale = locale || currentLocale();\r\n const msgs = localeMessages[targetLocale];\r\n\r\n if (!msgs) return false;\r\n return getNestedValue(msgs, key) !== undefined;\r\n }\r\n\r\n /**\r\n * 设置当前语言\r\n */\r\n function setLocale(locale: string): void {\r\n currentLocale.set(locale);\r\n }\r\n\r\n /**\r\n * 注册语言包\r\n */\r\n function registerLocale(locale: string, messages: LocaleMessages): void {\r\n // 如果是新语言,添加到可用语言列表\r\n if (!localeMessages[locale]) {\r\n localeMessages[locale] = {};\r\n // 更新可用语言列表\r\n const newLocales = [...Object.keys(localeMessages)];\r\n availableLocalesState.set(newLocales);\r\n }\r\n // 合并语言包(支持部分更新,深度克隆以防止外部修改)\r\n localeMessages[locale] = {\r\n ...localeMessages[locale],\r\n ...deepClone(messages),\r\n };\r\n console.log(`[i18n] Locale \"${locale}\" registered successfully`);\r\n }\r\n\r\n /**\r\n * 获取所有语言包\r\n */\r\n function getMessages(): Locale {\r\n // 返回深度克隆以防止外部直接修改\r\n return deepClone(localeMessages);\r\n }\r\n\r\n return {\r\n locale: {\r\n get value() { return currentLocale(); },\r\n set value(v: string) { currentLocale.set(v); }\r\n },\r\n setLocale,\r\n t,\r\n te,\r\n get availableLocales() { return availableLocalesState(); },\r\n registerLocale,\r\n getMessages,\r\n };\r\n}\r\n\r\n/**\r\n * 注册语言包(独立函数版本)\r\n */\r\nfunction registerLocale(i18n: I18nInstance, locale: string, messages: LocaleMessages): void {\r\n i18n.registerLocale(locale, messages);\r\n}\r\n\r\nconst pluginI18n = definePlugin({\r\n name: 'i18n',\r\n version: '6.0.0',\r\n description: 'LytJS official i18n plugin for internationalization and localization support',\r\n author: 'LytJS Team',\r\n keywords: ['lytjs', 'i18n', 'internationalization', 'localization'],\r\n schema: {\r\n type: 'object',\r\n object: {\r\n properties: {\r\n locale: { type: 'string', default: 'zh-CN' },\r\n fallbackLocale: { type: 'string', default: 'en-US' },\r\n messages: { type: 'object', default: {} },\r\n warnHtmlMessage: { type: 'boolean', default: true },\r\n },\r\n },\r\n },\r\n install(app, options) {\r\n const i18n = createI18n(options as I18nOptions);\r\n\r\n app.config.globalProperties.$i18n = i18n;\r\n app.config.globalProperties.$t = i18n.t;\r\n\r\n app.provide('lyt-i18n', i18n);\r\n },\r\n});\r\n\r\nexport default pluginI18n;\r\nexport type { I18nOptions, I18nInstance, Locale, LocaleMessages, TranslateFn };\r\nexport { createI18n, registerLocale };\r\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as _lytjs_core from '@lytjs/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @lytjs/plugin-i18n - 类型定义
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* 语言消息定义
|
|
8
|
+
*/
|
|
9
|
+
type LocaleMessages = Record<string, string | Record<string, any>>;
|
|
10
|
+
/**
|
|
11
|
+
* 语言包
|
|
12
|
+
*/
|
|
13
|
+
interface Locale {
|
|
14
|
+
[locale: string]: LocaleMessages;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* i18n 配置选项
|
|
18
|
+
*/
|
|
19
|
+
interface I18nOptions {
|
|
20
|
+
/** 默认语言 */
|
|
21
|
+
locale?: string;
|
|
22
|
+
/** 回退语言 */
|
|
23
|
+
fallbackLocale?: string;
|
|
24
|
+
/** 语言包 */
|
|
25
|
+
messages?: Locale;
|
|
26
|
+
/** 是否在控制台警告缺失的翻译 */
|
|
27
|
+
warnHtmlMessage?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 翻译函数
|
|
31
|
+
*/
|
|
32
|
+
type TranslateFn = (key: string, ...args: any[]) => string;
|
|
33
|
+
/**
|
|
34
|
+
* i18n 实例
|
|
35
|
+
*/
|
|
36
|
+
interface I18nInstance {
|
|
37
|
+
/** 当前语言 */
|
|
38
|
+
locale: {
|
|
39
|
+
value: string;
|
|
40
|
+
};
|
|
41
|
+
/** 设置语言 */
|
|
42
|
+
setLocale(locale: string): void;
|
|
43
|
+
/** 获取翻译 */
|
|
44
|
+
t: TranslateFn;
|
|
45
|
+
/** 是否存在翻译 */
|
|
46
|
+
te(key: string, locale?: string): boolean;
|
|
47
|
+
/** 获取语言列表 */
|
|
48
|
+
availableLocales: string[];
|
|
49
|
+
/** 注册语言包 */
|
|
50
|
+
registerLocale(locale: string, messages: LocaleMessages): void;
|
|
51
|
+
/** 获取所有语言包 */
|
|
52
|
+
getMessages(): Locale;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 创建 i18n 实例
|
|
57
|
+
*/
|
|
58
|
+
declare function createI18n(options?: I18nOptions): I18nInstance;
|
|
59
|
+
/**
|
|
60
|
+
* 注册语言包(独立函数版本)
|
|
61
|
+
*/
|
|
62
|
+
declare function registerLocale(i18n: I18nInstance, locale: string, messages: LocaleMessages): void;
|
|
63
|
+
declare const pluginI18n: _lytjs_core.PluginDefinition<unknown>;
|
|
64
|
+
|
|
65
|
+
export { type I18nInstance, type I18nOptions, type Locale, type LocaleMessages, type TranslateFn, createI18n, pluginI18n as default, registerLocale };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as _lytjs_core from '@lytjs/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @lytjs/plugin-i18n - 类型定义
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* 语言消息定义
|
|
8
|
+
*/
|
|
9
|
+
type LocaleMessages = Record<string, string | Record<string, any>>;
|
|
10
|
+
/**
|
|
11
|
+
* 语言包
|
|
12
|
+
*/
|
|
13
|
+
interface Locale {
|
|
14
|
+
[locale: string]: LocaleMessages;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* i18n 配置选项
|
|
18
|
+
*/
|
|
19
|
+
interface I18nOptions {
|
|
20
|
+
/** 默认语言 */
|
|
21
|
+
locale?: string;
|
|
22
|
+
/** 回退语言 */
|
|
23
|
+
fallbackLocale?: string;
|
|
24
|
+
/** 语言包 */
|
|
25
|
+
messages?: Locale;
|
|
26
|
+
/** 是否在控制台警告缺失的翻译 */
|
|
27
|
+
warnHtmlMessage?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 翻译函数
|
|
31
|
+
*/
|
|
32
|
+
type TranslateFn = (key: string, ...args: any[]) => string;
|
|
33
|
+
/**
|
|
34
|
+
* i18n 实例
|
|
35
|
+
*/
|
|
36
|
+
interface I18nInstance {
|
|
37
|
+
/** 当前语言 */
|
|
38
|
+
locale: {
|
|
39
|
+
value: string;
|
|
40
|
+
};
|
|
41
|
+
/** 设置语言 */
|
|
42
|
+
setLocale(locale: string): void;
|
|
43
|
+
/** 获取翻译 */
|
|
44
|
+
t: TranslateFn;
|
|
45
|
+
/** 是否存在翻译 */
|
|
46
|
+
te(key: string, locale?: string): boolean;
|
|
47
|
+
/** 获取语言列表 */
|
|
48
|
+
availableLocales: string[];
|
|
49
|
+
/** 注册语言包 */
|
|
50
|
+
registerLocale(locale: string, messages: LocaleMessages): void;
|
|
51
|
+
/** 获取所有语言包 */
|
|
52
|
+
getMessages(): Locale;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 创建 i18n 实例
|
|
57
|
+
*/
|
|
58
|
+
declare function createI18n(options?: I18nOptions): I18nInstance;
|
|
59
|
+
/**
|
|
60
|
+
* 注册语言包(独立函数版本)
|
|
61
|
+
*/
|
|
62
|
+
declare function registerLocale(i18n: I18nInstance, locale: string, messages: LocaleMessages): void;
|
|
63
|
+
declare const pluginI18n: _lytjs_core.PluginDefinition<unknown>;
|
|
64
|
+
|
|
65
|
+
export { type I18nInstance, type I18nOptions, type Locale, type LocaleMessages, type TranslateFn, createI18n, pluginI18n as default, registerLocale };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1,145 @@
|
|
|
1
|
-
|
|
1
|
+
import { definePlugin } from '@lytjs/core';
|
|
2
|
+
import { signal } from '@lytjs/reactivity';
|
|
3
|
+
import { isObject, isString } from '@lytjs/common-is';
|
|
4
|
+
|
|
5
|
+
// src/index.ts
|
|
6
|
+
function deepClone(obj) {
|
|
7
|
+
if (obj === null || typeof obj !== "object") {
|
|
8
|
+
return obj;
|
|
9
|
+
}
|
|
10
|
+
if (Array.isArray(obj)) {
|
|
11
|
+
return obj.map(deepClone);
|
|
12
|
+
}
|
|
13
|
+
const cloned = {};
|
|
14
|
+
for (const key in obj) {
|
|
15
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
16
|
+
cloned[key] = deepClone(obj[key]);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return cloned;
|
|
20
|
+
}
|
|
21
|
+
function createI18n(options = {}) {
|
|
22
|
+
const {
|
|
23
|
+
locale: defaultLocale = "zh-CN",
|
|
24
|
+
fallbackLocale = "en-US",
|
|
25
|
+
messages = {},
|
|
26
|
+
warnHtmlMessage = true
|
|
27
|
+
} = options;
|
|
28
|
+
const currentLocale = signal(defaultLocale);
|
|
29
|
+
const availableLocalesState = signal(Object.keys(messages));
|
|
30
|
+
const localeMessages = deepClone(messages);
|
|
31
|
+
function getNestedValue(obj, path) {
|
|
32
|
+
const keys = path.split(".");
|
|
33
|
+
let current = obj;
|
|
34
|
+
for (const key of keys) {
|
|
35
|
+
if (!isObject(current) || !(key in current)) {
|
|
36
|
+
return void 0;
|
|
37
|
+
}
|
|
38
|
+
current = current[key];
|
|
39
|
+
}
|
|
40
|
+
return isString(current) ? current : void 0;
|
|
41
|
+
}
|
|
42
|
+
function interpolate(message, args) {
|
|
43
|
+
if (args.length === 0) return message;
|
|
44
|
+
return message.replace(/\{(\w+)\}/g, (match, key) => {
|
|
45
|
+
const index = parseInt(key, 10);
|
|
46
|
+
if (!isNaN(index)) {
|
|
47
|
+
return args[index] !== void 0 ? String(args[index]) : match;
|
|
48
|
+
}
|
|
49
|
+
if (isObject(args[0])) {
|
|
50
|
+
return args[0][key] !== void 0 ? String(args[0][key]) : match;
|
|
51
|
+
}
|
|
52
|
+
return match;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function t(key, ...args) {
|
|
56
|
+
const locale = currentLocale();
|
|
57
|
+
const msgs = localeMessages[locale];
|
|
58
|
+
const fallbackMessages = localeMessages[fallbackLocale];
|
|
59
|
+
let message = msgs ? getNestedValue(msgs, key) : void 0;
|
|
60
|
+
if (!message && fallbackMessages) {
|
|
61
|
+
message = getNestedValue(fallbackMessages, key);
|
|
62
|
+
}
|
|
63
|
+
if (!message) {
|
|
64
|
+
if (warnHtmlMessage) {
|
|
65
|
+
console.warn(`[i18n] Missing translation for key: "${key}"`);
|
|
66
|
+
}
|
|
67
|
+
return key;
|
|
68
|
+
}
|
|
69
|
+
return interpolate(message, args);
|
|
70
|
+
}
|
|
71
|
+
function te(key, locale) {
|
|
72
|
+
const targetLocale = locale || currentLocale();
|
|
73
|
+
const msgs = localeMessages[targetLocale];
|
|
74
|
+
if (!msgs) return false;
|
|
75
|
+
return getNestedValue(msgs, key) !== void 0;
|
|
76
|
+
}
|
|
77
|
+
function setLocale(locale) {
|
|
78
|
+
currentLocale.set(locale);
|
|
79
|
+
}
|
|
80
|
+
function registerLocale2(locale, messages2) {
|
|
81
|
+
if (!localeMessages[locale]) {
|
|
82
|
+
localeMessages[locale] = {};
|
|
83
|
+
const newLocales = [...Object.keys(localeMessages)];
|
|
84
|
+
availableLocalesState.set(newLocales);
|
|
85
|
+
}
|
|
86
|
+
localeMessages[locale] = {
|
|
87
|
+
...localeMessages[locale],
|
|
88
|
+
...deepClone(messages2)
|
|
89
|
+
};
|
|
90
|
+
console.log(`[i18n] Locale "${locale}" registered successfully`);
|
|
91
|
+
}
|
|
92
|
+
function getMessages() {
|
|
93
|
+
return deepClone(localeMessages);
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
locale: {
|
|
97
|
+
get value() {
|
|
98
|
+
return currentLocale();
|
|
99
|
+
},
|
|
100
|
+
set value(v) {
|
|
101
|
+
currentLocale.set(v);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
setLocale,
|
|
105
|
+
t,
|
|
106
|
+
te,
|
|
107
|
+
get availableLocales() {
|
|
108
|
+
return availableLocalesState();
|
|
109
|
+
},
|
|
110
|
+
registerLocale: registerLocale2,
|
|
111
|
+
getMessages
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function registerLocale(i18n, locale, messages) {
|
|
115
|
+
i18n.registerLocale(locale, messages);
|
|
116
|
+
}
|
|
117
|
+
var pluginI18n = definePlugin({
|
|
118
|
+
name: "i18n",
|
|
119
|
+
version: "6.0.0",
|
|
120
|
+
description: "LytJS official i18n plugin for internationalization and localization support",
|
|
121
|
+
author: "LytJS Team",
|
|
122
|
+
keywords: ["lytjs", "i18n", "internationalization", "localization"],
|
|
123
|
+
schema: {
|
|
124
|
+
type: "object",
|
|
125
|
+
object: {
|
|
126
|
+
properties: {
|
|
127
|
+
locale: { type: "string", default: "zh-CN" },
|
|
128
|
+
fallbackLocale: { type: "string", default: "en-US" },
|
|
129
|
+
messages: { type: "object", default: {} },
|
|
130
|
+
warnHtmlMessage: { type: "boolean", default: true }
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
install(app, options) {
|
|
135
|
+
const i18n = createI18n(options);
|
|
136
|
+
app.config.globalProperties.$i18n = i18n;
|
|
137
|
+
app.config.globalProperties.$t = i18n.t;
|
|
138
|
+
app.provide("lyt-i18n", i18n);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
var index_default = pluginI18n;
|
|
142
|
+
|
|
143
|
+
export { createI18n, index_default as default, registerLocale };
|
|
144
|
+
//# sourceMappingURL=index.mjs.map
|
|
145
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["registerLocale","messages"],"mappings":";;;;;AAgBA,SAAS,UAAa,GAAA,EAAW;AAC/B,EAAA,IAAI,GAAA,KAAQ,IAAA,IAAQ,OAAO,GAAA,KAAQ,QAAA,EAAU;AAC3C,IAAA,OAAO,GAAA;AAAA,EACT;AAEA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACtB,IAAA,OAAO,GAAA,CAAI,IAAI,SAAS,CAAA;AAAA,EAC1B;AAEA,EAAA,MAAM,SAAS,EAAC;AAChB,EAAA,KAAA,MAAW,OAAO,GAAA,EAAK;AACrB,IAAA,IAAI,OAAO,SAAA,CAAU,cAAA,CAAe,IAAA,CAAK,GAAA,EAAK,GAAG,CAAA,EAAG;AAClD,MAAA,MAAA,CAAO,GAAG,CAAA,GAAI,SAAA,CAAW,GAAA,CAA4B,GAAG,CAAC,CAAA;AAAA,IAC3D;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AAKA,SAAS,UAAA,CAAW,OAAA,GAAuB,EAAC,EAAiB;AAC3D,EAAA,MAAM;AAAA,IACJ,QAAQ,aAAA,GAAgB,OAAA;AAAA,IACxB,cAAA,GAAiB,OAAA;AAAA,IACjB,WAAW,EAAC;AAAA,IACZ,eAAA,GAAkB;AAAA,GACpB,GAAI,OAAA;AAGJ,EAAA,MAAM,aAAA,GAAgB,OAAO,aAAa,CAAA;AAG1C,EAAA,MAAM,qBAAA,GAAwB,MAAA,CAAiB,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAC,CAAA;AAGpE,EAAA,MAAM,cAAA,GAAyB,UAAU,QAAQ,CAAA;AAKjD,EAAA,SAAS,cAAA,CAAe,KAAqB,IAAA,EAAkC;AAC7E,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC3B,IAAA,IAAI,OAAA,GAAe,GAAA;AAEnB,IAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,MAAA,IAAI,CAAC,QAAA,CAAS,OAAO,CAAA,IAAK,EAAE,OAAO,OAAA,CAAA,EAAU;AAC3C,QAAA,OAAO,MAAA;AAAA,MACT;AACA,MAAA,OAAA,GAAU,QAAQ,GAA2B,CAAA;AAAA,IAC/C;AAEA,IAAA,OAAO,QAAA,CAAS,OAAO,CAAA,GAAI,OAAA,GAAU,MAAA;AAAA,EACvC;AAKA,EAAA,SAAS,WAAA,CAAY,SAAiB,IAAA,EAAqB;AACzD,IAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,OAAA;AAG9B,IAAA,OAAO,OAAA,CAAQ,OAAA,CAAQ,YAAA,EAAc,CAAC,OAAO,GAAA,KAAQ;AACnD,MAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,GAAA,EAAK,EAAE,CAAA;AAC9B,MAAA,IAAI,CAAC,KAAA,CAAM,KAAK,CAAA,EAAG;AACjB,QAAA,OAAO,IAAA,CAAK,KAAK,CAAA,KAAM,MAAA,GAAY,OAAO,IAAA,CAAK,KAAK,CAAC,CAAA,GAAI,KAAA;AAAA,MAC3D;AAEA,MAAA,IAAI,QAAA,CAAS,IAAA,CAAK,CAAC,CAAC,CAAA,EAAG;AACrB,QAAA,OAAQ,IAAA,CAAK,CAAC,CAAA,CAA0B,GAAG,CAAA,KAAM,MAAA,GAC7C,MAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,CAA0B,GAAG,CAAC,CAAA,GAC5C,KAAA;AAAA,MACN;AACA,MAAA,OAAO,KAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH;AAKA,EAAA,SAAS,CAAA,CAAE,QAAgB,IAAA,EAAqB;AAC9C,IAAA,MAAM,SAAS,aAAA,EAAc;AAC7B,IAAA,MAAM,IAAA,GAAO,eAAe,MAAM,CAAA;AAClC,IAAA,MAAM,gBAAA,GAAmB,eAAe,cAAc,CAAA;AAGtD,IAAA,IAAI,OAAA,GAAU,IAAA,GAAO,cAAA,CAAe,IAAA,EAAM,GAAG,CAAA,GAAI,MAAA;AAGjD,IAAA,IAAI,CAAC,WAAW,gBAAA,EAAkB;AAChC,MAAA,OAAA,GAAU,cAAA,CAAe,kBAAkB,GAAG,CAAA;AAAA,IAChD;AAGA,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,IAAI,eAAA,EAAiB;AACnB,QAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,qCAAA,EAAwC,GAAG,CAAA,CAAA,CAAG,CAAA;AAAA,MAC7D;AACA,MAAA,OAAO,GAAA;AAAA,IACT;AAEA,IAAA,OAAO,WAAA,CAAY,SAAS,IAAI,CAAA;AAAA,EAClC;AAKA,EAAA,SAAS,EAAA,CAAG,KAAa,MAAA,EAA0B;AACjD,IAAA,MAAM,YAAA,GAAe,UAAU,aAAA,EAAc;AAC7C,IAAA,MAAM,IAAA,GAAO,eAAe,YAAY,CAAA;AAExC,IAAA,IAAI,CAAC,MAAM,OAAO,KAAA;AAClB,IAAA,OAAO,cAAA,CAAe,IAAA,EAAM,GAAG,CAAA,KAAM,MAAA;AAAA,EACvC;AAKA,EAAA,SAAS,UAAU,MAAA,EAAsB;AACvC,IAAA,aAAA,CAAc,IAAI,MAAM,CAAA;AAAA,EAC1B;AAKA,EAAA,SAASA,eAAAA,CAAe,QAAgBC,SAAAA,EAAgC;AAEtE,IAAA,IAAI,CAAC,cAAA,CAAe,MAAM,CAAA,EAAG;AAC3B,MAAA,cAAA,CAAe,MAAM,IAAI,EAAC;AAE1B,MAAA,MAAM,aAAa,CAAC,GAAG,MAAA,CAAO,IAAA,CAAK,cAAc,CAAC,CAAA;AAClD,MAAA,qBAAA,CAAsB,IAAI,UAAU,CAAA;AAAA,IACtC;AAEA,IAAA,cAAA,CAAe,MAAM,CAAA,GAAI;AAAA,MACvB,GAAG,eAAe,MAAM,CAAA;AAAA,MACxB,GAAG,UAAUA,SAAQ;AAAA,KACvB;AACA,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,eAAA,EAAkB,MAAM,CAAA,yBAAA,CAA2B,CAAA;AAAA,EACjE;AAKA,EAAA,SAAS,WAAA,GAAsB;AAE7B,IAAA,OAAO,UAAU,cAAc,CAAA;AAAA,EACjC;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ;AAAA,MACN,IAAI,KAAA,GAAQ;AAAE,QAAA,OAAO,aAAA,EAAc;AAAA,MAAG,CAAA;AAAA,MACtC,IAAI,MAAM,CAAA,EAAW;AAAE,QAAA,aAAA,CAAc,IAAI,CAAC,CAAA;AAAA,MAAG;AAAA,KAC/C;AAAA,IACA,SAAA;AAAA,IACA,CAAA;AAAA,IACA,EAAA;AAAA,IACA,IAAI,gBAAA,GAAmB;AAAE,MAAA,OAAO,qBAAA,EAAsB;AAAA,IAAG,CAAA;AAAA,IACzD,cAAA,EAAAD,eAAAA;AAAA,IACA;AAAA,GACF;AACF;AAKA,SAAS,cAAA,CAAe,IAAA,EAAoB,MAAA,EAAgB,QAAA,EAAgC;AAC1F,EAAA,IAAA,CAAK,cAAA,CAAe,QAAQ,QAAQ,CAAA;AACtC;AAEA,IAAM,aAAa,YAAA,CAAa;AAAA,EAC9B,IAAA,EAAM,MAAA;AAAA,EACN,OAAA,EAAS,OAAA;AAAA,EACT,WAAA,EAAa,8EAAA;AAAA,EACb,MAAA,EAAQ,YAAA;AAAA,EACR,QAAA,EAAU,CAAC,OAAA,EAAS,MAAA,EAAQ,wBAAwB,cAAc,CAAA;AAAA,EAClE,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM,QAAA;AAAA,IACN,MAAA,EAAQ;AAAA,MACN,UAAA,EAAY;AAAA,QACV,MAAA,EAAQ,EAAE,IAAA,EAAM,QAAA,EAAU,SAAS,OAAA,EAAQ;AAAA,QAC3C,cAAA,EAAgB,EAAE,IAAA,EAAM,QAAA,EAAU,SAAS,OAAA,EAAQ;AAAA,QACnD,UAAU,EAAE,IAAA,EAAM,QAAA,EAAU,OAAA,EAAS,EAAC,EAAE;AAAA,QACxC,eAAA,EAAiB,EAAE,IAAA,EAAM,SAAA,EAAW,SAAS,IAAA;AAAK;AACpD;AACF,GACF;AAAA,EACA,OAAA,CAAQ,KAAK,OAAA,EAAS;AACpB,IAAA,MAAM,IAAA,GAAO,WAAW,OAAsB,CAAA;AAE9C,IAAA,GAAA,CAAI,MAAA,CAAO,iBAAiB,KAAA,GAAQ,IAAA;AACpC,IAAA,GAAA,CAAI,MAAA,CAAO,gBAAA,CAAiB,EAAA,GAAK,IAAA,CAAK,CAAA;AAEtC,IAAA,GAAA,CAAI,OAAA,CAAQ,YAAY,IAAI,CAAA;AAAA,EAC9B;AACF,CAAC,CAAA;AAED,IAAO,aAAA,GAAQ","file":"index.mjs","sourcesContent":["/**\r\n * @lytjs/plugin-i18n\r\n *\r\n * LytJS official i18n plugin for internationalization and localization support.\r\n *\r\n * @packageDocumentation\r\n */\r\n\r\nimport { definePlugin } from '@lytjs/core';\r\nimport { signal } from '@lytjs/reactivity';\r\nimport { isString, isObject } from '@lytjs/common-is';\r\nimport type { I18nOptions, I18nInstance, Locale, LocaleMessages, TranslateFn } from './types';\r\n\r\n/**\r\n * 深度克隆对象,防止直接修改\r\n */\r\nfunction deepClone<T>(obj: T): T {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n if (Array.isArray(obj)) {\r\n return obj.map(deepClone) as T;\r\n }\r\n\r\n const cloned = {} as Record<string, any>;\r\n for (const key in obj) {\r\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\r\n cloned[key] = deepClone((obj as Record<string, any>)[key]);\r\n }\r\n }\r\n return cloned as T;\r\n}\r\n\r\n/**\r\n * 创建 i18n 实例\r\n */\r\nfunction createI18n(options: I18nOptions = {}): I18nInstance {\r\n const {\r\n locale: defaultLocale = 'zh-CN',\r\n fallbackLocale = 'en-US',\r\n messages = {},\r\n warnHtmlMessage = true,\r\n } = options;\r\n\r\n // 当前语言\r\n const currentLocale = signal(defaultLocale);\r\n\r\n // 可用语言列表(响应式)\r\n const availableLocalesState = signal<string[]>(Object.keys(messages));\r\n\r\n // 语言包存储(深度克隆以防止外部修改)\r\n const localeMessages: Locale = deepClone(messages);\r\n\r\n /**\r\n * 获取嵌套对象的值\r\n */\r\n function getNestedValue(obj: LocaleMessages, path: string): string | undefined {\r\n const keys = path.split('.');\r\n let current: any = obj;\r\n\r\n for (const key of keys) {\r\n if (!isObject(current) || !(key in current)) {\r\n return undefined;\r\n }\r\n current = current[key as keyof typeof current];\r\n }\r\n\r\n return isString(current) ? current : undefined;\r\n }\r\n\r\n /**\r\n * 替换插值\r\n */\r\n function interpolate(message: string, args: any[]): string {\r\n if (args.length === 0) return message;\r\n\r\n // 支持命名参数 {name} 和位置参数 {0}\r\n return message.replace(/\\{(\\w+)\\}/g, (match, key) => {\r\n const index = parseInt(key, 10);\r\n if (!isNaN(index)) {\r\n return args[index] !== undefined ? String(args[index]) : match;\r\n }\r\n // 命名参数(从对象中获取)\r\n if (isObject(args[0])) {\r\n return (args[0] as Record<string, any>)[key] !== undefined\r\n ? String((args[0] as Record<string, any>)[key])\r\n : match;\r\n }\r\n return match;\r\n });\r\n }\r\n\r\n /**\r\n * 翻译函数\r\n */\r\n function t(key: string, ...args: any[]): string {\r\n const locale = currentLocale();\r\n const msgs = localeMessages[locale];\r\n const fallbackMessages = localeMessages[fallbackLocale];\r\n\r\n // 尝试获取翻译\r\n let message = msgs ? getNestedValue(msgs, key) : undefined;\r\n\r\n // 回退到默认语言\r\n if (!message && fallbackMessages) {\r\n message = getNestedValue(fallbackMessages, key);\r\n }\r\n\r\n // 找不到翻译,返回 key\r\n if (!message) {\r\n if (warnHtmlMessage) {\r\n console.warn(`[i18n] Missing translation for key: \"${key}\"`);\r\n }\r\n return key;\r\n }\r\n\r\n return interpolate(message, args);\r\n }\r\n\r\n /**\r\n * 检查翻译是否存在\r\n */\r\n function te(key: string, locale?: string): boolean {\r\n const targetLocale = locale || currentLocale();\r\n const msgs = localeMessages[targetLocale];\r\n\r\n if (!msgs) return false;\r\n return getNestedValue(msgs, key) !== undefined;\r\n }\r\n\r\n /**\r\n * 设置当前语言\r\n */\r\n function setLocale(locale: string): void {\r\n currentLocale.set(locale);\r\n }\r\n\r\n /**\r\n * 注册语言包\r\n */\r\n function registerLocale(locale: string, messages: LocaleMessages): void {\r\n // 如果是新语言,添加到可用语言列表\r\n if (!localeMessages[locale]) {\r\n localeMessages[locale] = {};\r\n // 更新可用语言列表\r\n const newLocales = [...Object.keys(localeMessages)];\r\n availableLocalesState.set(newLocales);\r\n }\r\n // 合并语言包(支持部分更新,深度克隆以防止外部修改)\r\n localeMessages[locale] = {\r\n ...localeMessages[locale],\r\n ...deepClone(messages),\r\n };\r\n console.log(`[i18n] Locale \"${locale}\" registered successfully`);\r\n }\r\n\r\n /**\r\n * 获取所有语言包\r\n */\r\n function getMessages(): Locale {\r\n // 返回深度克隆以防止外部直接修改\r\n return deepClone(localeMessages);\r\n }\r\n\r\n return {\r\n locale: {\r\n get value() { return currentLocale(); },\r\n set value(v: string) { currentLocale.set(v); }\r\n },\r\n setLocale,\r\n t,\r\n te,\r\n get availableLocales() { return availableLocalesState(); },\r\n registerLocale,\r\n getMessages,\r\n };\r\n}\r\n\r\n/**\r\n * 注册语言包(独立函数版本)\r\n */\r\nfunction registerLocale(i18n: I18nInstance, locale: string, messages: LocaleMessages): void {\r\n i18n.registerLocale(locale, messages);\r\n}\r\n\r\nconst pluginI18n = definePlugin({\r\n name: 'i18n',\r\n version: '6.0.0',\r\n description: 'LytJS official i18n plugin for internationalization and localization support',\r\n author: 'LytJS Team',\r\n keywords: ['lytjs', 'i18n', 'internationalization', 'localization'],\r\n schema: {\r\n type: 'object',\r\n object: {\r\n properties: {\r\n locale: { type: 'string', default: 'zh-CN' },\r\n fallbackLocale: { type: 'string', default: 'en-US' },\r\n messages: { type: 'object', default: {} },\r\n warnHtmlMessage: { type: 'boolean', default: true },\r\n },\r\n },\r\n },\r\n install(app, options) {\r\n const i18n = createI18n(options as I18nOptions);\r\n\r\n app.config.globalProperties.$i18n = i18n;\r\n app.config.globalProperties.$t = i18n.t;\r\n\r\n app.provide('lyt-i18n', i18n);\r\n },\r\n});\r\n\r\nexport default pluginI18n;\r\nexport type { I18nOptions, I18nInstance, Locale, LocaleMessages, TranslateFn };\r\nexport { createI18n, registerLocale };\r\n"]}
|
package/package.json
CHANGED
|
@@ -1,45 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lytjs/plugin-i18n",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
|
+
"description": "LytJS Internationalization plugin",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "./dist/index.cjs",
|
|
6
7
|
"module": "./dist/index.mjs",
|
|
7
|
-
"types": "./dist/
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
8
9
|
"exports": {
|
|
9
10
|
".": {
|
|
10
|
-
"types": "./dist/
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
11
12
|
"import": "./dist/index.mjs",
|
|
12
|
-
"require": "./dist/index.cjs"
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
},
|
|
15
|
+
"./package.json": "./package.json"
|
|
15
16
|
},
|
|
16
|
-
"sideEffects": false,
|
|
17
17
|
"files": [
|
|
18
18
|
"dist"
|
|
19
19
|
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup",
|
|
22
|
+
"dev": "tsup --watch",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest",
|
|
25
|
+
"test:coverage": "vitest run --coverage",
|
|
26
|
+
"type-check": "tsc --noEmit",
|
|
27
|
+
"lint": "eslint \"src/**/*.ts\"",
|
|
28
|
+
"clean": "rm -rf dist"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@lytjs/core": "^6.0.0",
|
|
32
|
+
"@lytjs/reactivity": "^6.0.0",
|
|
33
|
+
"@lytjs/common-is": "^6.0.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"tsup": "^8.0.0",
|
|
37
|
+
"typescript": "^5.4.0",
|
|
38
|
+
"vitest": "^3.0.0"
|
|
39
|
+
},
|
|
20
40
|
"license": "MIT",
|
|
21
|
-
"author": "lytjs",
|
|
22
41
|
"repository": {
|
|
23
42
|
"type": "git",
|
|
24
|
-
"url": "https://gitee.com/lytjs/lytjs"
|
|
43
|
+
"url": "https://gitee.com/lytjs/lytjs.git",
|
|
44
|
+
"directory": "packages/plugins/packages/plugin-i18n"
|
|
25
45
|
},
|
|
26
|
-
"homepage": "https://gitee.com/lytjs/lytjs",
|
|
27
46
|
"keywords": [
|
|
28
|
-
"lyt",
|
|
29
47
|
"lytjs",
|
|
30
|
-
"javascript",
|
|
31
|
-
"framework",
|
|
32
|
-
"frontend",
|
|
33
|
-
"vue-like",
|
|
34
|
-
"lightweight",
|
|
35
|
-
"zero-dependency",
|
|
36
48
|
"i18n",
|
|
37
49
|
"internationalization",
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
"国际化"
|
|
41
|
-
],
|
|
42
|
-
"publishConfig": {
|
|
43
|
-
"access": "public"
|
|
44
|
-
}
|
|
50
|
+
"localization"
|
|
51
|
+
]
|
|
45
52
|
}
|
package/README.md
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
# @lytjs/plugin-i18n
|
|
2
|
-
|
|
3
|
-
> Lyt.js 国际化插件 - 提供多语言支持、消息格式化和语言切换功能
|
|
4
|
-
|
|
5
|
-
**版本:** 4.2.0
|
|
6
|
-
|
|
7
|
-
## 安装
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npm install @lytjs/plugin-i18n
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## 使用
|
|
14
|
-
|
|
15
|
-
### 注册插件
|
|
16
|
-
|
|
17
|
-
```typescript
|
|
18
|
-
import { createApp } from '@lytjs/core'
|
|
19
|
-
import { createI18n } from '@lytjs/plugin-i18n'
|
|
20
|
-
|
|
21
|
-
const i18n = createI18n({
|
|
22
|
-
locale: 'zh-CN',
|
|
23
|
-
fallbackLocale: 'en',
|
|
24
|
-
messages: {
|
|
25
|
-
'zh-CN': {
|
|
26
|
-
hello: '你好',
|
|
27
|
-
welcome: '欢迎',
|
|
28
|
-
user: { profile: { name: '张三' } },
|
|
29
|
-
},
|
|
30
|
-
en: {
|
|
31
|
-
hello: 'Hello',
|
|
32
|
-
welcome: 'Welcome',
|
|
33
|
-
user: { profile: { name: 'John' } },
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
const app = createApp({})
|
|
39
|
-
app.use(i18n)
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
### 在模板中使用
|
|
43
|
-
|
|
44
|
-
安装插件后,会注入全局 `$t` 方法,可在模板中直接使用:
|
|
45
|
-
|
|
46
|
-
```html
|
|
47
|
-
<template>
|
|
48
|
-
<p>{{ $t('hello') }}</p>
|
|
49
|
-
<p>{{ $t('user.profile.name') }}</p>
|
|
50
|
-
</template>
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### 在 JS 中使用
|
|
54
|
-
|
|
55
|
-
```typescript
|
|
56
|
-
// 通过注入获取
|
|
57
|
-
const i18n = inject('i18n')
|
|
58
|
-
|
|
59
|
-
// 翻译
|
|
60
|
-
i18n.t('hello') // '你好'
|
|
61
|
-
|
|
62
|
-
// 带参数插值
|
|
63
|
-
i18n.t('greeting', { name: 'World' }) // 'Hello, World!'
|
|
64
|
-
|
|
65
|
-
// 带默认值
|
|
66
|
-
i18n.t('missing.key', {}, '默认文本') // '默认文本'
|
|
67
|
-
|
|
68
|
-
// 切换语言
|
|
69
|
-
i18n.setLocale('en')
|
|
70
|
-
|
|
71
|
-
// 获取当前语言
|
|
72
|
-
i18n.getLocale() // 'en'
|
|
73
|
-
|
|
74
|
-
// 可用语言列表
|
|
75
|
-
i18n.availableLocales // ['zh-CN', 'en']
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
### 复数形式
|
|
79
|
-
|
|
80
|
-
```typescript
|
|
81
|
-
// 定义复数消息(使用 | 分隔符)
|
|
82
|
-
const messages = {
|
|
83
|
-
'zh-CN': {
|
|
84
|
-
apple: '没有苹果 | 1 个苹果 | {count} 个苹果',
|
|
85
|
-
},
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
i18n.t('apple', { count: 0 }) // '没有苹果'
|
|
89
|
-
i18n.t('apple', { count: 1 }) // '1 个苹果'
|
|
90
|
-
i18n.t('apple', { count: 5 }) // '5 个苹果'
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### 运行时加载语言包
|
|
94
|
-
|
|
95
|
-
```typescript
|
|
96
|
-
// 浅合并新翻译
|
|
97
|
-
i18n.mergeMessage('zh-CN', { newKey: '新翻译' })
|
|
98
|
-
|
|
99
|
-
// 懒加载替换整个语言包
|
|
100
|
-
i18n.loadLocaleMessages('ja', {
|
|
101
|
-
hello: 'こんにちは',
|
|
102
|
-
welcome: 'ようこそ',
|
|
103
|
-
})
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### 监听语言变化
|
|
107
|
-
|
|
108
|
-
```typescript
|
|
109
|
-
const unsubscribe = i18n.onLocaleChange((locale) => {
|
|
110
|
-
console.log('语言已切换为:', locale)
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
// 取消监听
|
|
114
|
-
unsubscribe()
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
## API
|
|
118
|
-
|
|
119
|
-
### Options
|
|
120
|
-
|
|
121
|
-
| 选项 | 类型 | 默认值 | 描述 |
|
|
122
|
-
|------|------|--------|------|
|
|
123
|
-
| `locale` | `string` | **必填** | 当前语言 |
|
|
124
|
-
| `fallbackLocale` | `string` | - | 回退语言,当前语言找不到翻译时使用 |
|
|
125
|
-
| `messages` | `Record<string, Record<string, string>>` | **必填** | 语言包映射表 |
|
|
126
|
-
| `datetimeFormats` | `Record<string, any>` | - | 日期格式配置(预留) |
|
|
127
|
-
| `numberFormats` | `Record<string, any>` | - | 数字格式配置(预留) |
|
|
128
|
-
| `legacy` | `boolean` | - | 兼容模式(预留) |
|
|
129
|
-
|
|
130
|
-
### global 方法
|
|
131
|
-
|
|
132
|
-
| 方法 | 签名 | 描述 |
|
|
133
|
-
|------|------|------|
|
|
134
|
-
| `t` | `(key: string, params?: Record<string, any>, defaultValue?: string) => string` | 翻译函数,支持路径式 key、参数插值、回退语言、默认值、复数形式 |
|
|
135
|
-
| `setLocale` | `(locale: string) => void` | 切换语言 |
|
|
136
|
-
| `getLocale` | `() => string` | 获取当前语言 |
|
|
137
|
-
| `availableLocales` | `string[]` | 可用语言列表 |
|
|
138
|
-
| `mergeMessage` | `(locale: string, messages: Record<string, string>) => void` | 运行时合并新翻译(浅合并) |
|
|
139
|
-
| `mergeLocaleMessages` | `(locale: string, messages: Record<string, string>) => void` | 运行时合并翻译(已废弃,请使用 `mergeMessage`) |
|
|
140
|
-
| `loadLocaleMessages` | `(locale: string, messages: Record<string, string>) => void` | 懒加载翻译包(替换指定语言的全部翻译) |
|
|
141
|
-
| `onLocaleChange` | `(callback: (locale: string) => void) => () => void` | 注册语言变更监听器,返回取消监听函数 |
|
|
142
|
-
|
|
143
|
-
## License
|
|
144
|
-
|
|
145
|
-
MIT
|
package/dist/types/index.d.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/** 国际化配置选项 */
|
|
2
|
-
interface I18nOptions {
|
|
3
|
-
/** 当前语言 */
|
|
4
|
-
locale: string;
|
|
5
|
-
/** 回退语言,当前语言找不到翻译时使用 */
|
|
6
|
-
fallbackLocale?: string;
|
|
7
|
-
/** 语言包映射表 */
|
|
8
|
-
messages: Record<string, Record<string, string>>;
|
|
9
|
-
/** 日期格式配置 */
|
|
10
|
-
datetimeFormats?: Record<string, any>;
|
|
11
|
-
/** 数字格式配置 */
|
|
12
|
-
numberFormats?: Record<string, any>;
|
|
13
|
-
/** 兼容模式(预留) */
|
|
14
|
-
legacy?: boolean;
|
|
15
|
-
}
|
|
16
|
-
/** 国际化插件应用接口(最小化) */
|
|
17
|
-
interface I18nPluginApp {
|
|
18
|
-
use(plugin: unknown, options?: unknown): void;
|
|
19
|
-
[key: string]: unknown;
|
|
20
|
-
}
|
|
21
|
-
/** 国际化插件实例 */
|
|
22
|
-
interface I18n {
|
|
23
|
-
/** 安装到 Lyt 应用 */
|
|
24
|
-
install: (app: I18nPluginApp, options?: I18nOptions) => void;
|
|
25
|
-
/** 全局国际化 API */
|
|
26
|
-
global: {
|
|
27
|
-
/** 翻译函数,支持路径式 key、参数插值、回退语言、默认值、复数形式 */
|
|
28
|
-
t: (key: string, params?: Record<string, any>, defaultValue?: string) => string;
|
|
29
|
-
/** 当前语言 */
|
|
30
|
-
locale: string;
|
|
31
|
-
/** 切换语言 */
|
|
32
|
-
setLocale: (locale: string) => void;
|
|
33
|
-
/** 获取当前语言 */
|
|
34
|
-
getLocale: () => string;
|
|
35
|
-
/** 可用语言列表 */
|
|
36
|
-
availableLocales: string[];
|
|
37
|
-
/** 运行时合并新翻译(浅合并) */
|
|
38
|
-
mergeMessage: (locale: string, messages: Record<string, string>) => void;
|
|
39
|
-
/** 运行时合并翻译(与 mergeMessage 功能一致) */
|
|
40
|
-
mergeLocaleMessages: (locale: string, messages: Record<string, string>) => void;
|
|
41
|
-
/** 懒加载翻译包(替换指定语言的全部翻译) */
|
|
42
|
-
loadLocaleMessages: (locale: string, messages: Record<string, string>) => void;
|
|
43
|
-
/** 注册语言变更监听器,返回取消监听函数 */
|
|
44
|
-
onLocaleChange: (callback: (locale: string) => void) => () => void;
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* 创建国际化插件实例
|
|
49
|
-
* @param options 国际化配置
|
|
50
|
-
* @returns I18n 插件实例
|
|
51
|
-
*/
|
|
52
|
-
declare function createI18n(options: I18nOptions): I18n;
|
|
53
|
-
export { createI18n };
|
|
54
|
-
export type { I18n, I18nOptions };
|
|
55
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAkBA,cAAc;AACd,UAAU,WAAW;IACnB,WAAW;IACX,MAAM,EAAE,MAAM,CAAA;IACd,wBAAwB;IACxB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,aAAa;IACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAChD,aAAa;IACb,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACrC,aAAa;IACb,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACnC,eAAe;IACf,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,qBAAqB;AACrB,UAAU,aAAa;IACrB,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;IAC7C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,cAAc;AACd,UAAU,IAAI;IACZ,iBAAiB;IACjB,OAAO,EAAE,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,WAAW,KAAK,IAAI,CAAA;IAC5D,gBAAgB;IAChB,MAAM,EAAE;QACN,wCAAwC;QACxC,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;QAC/E,WAAW;QACX,MAAM,EAAE,MAAM,CAAA;QACd,WAAW;QACX,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;QACnC,aAAa;QACb,SAAS,EAAE,MAAM,MAAM,CAAA;QACvB,aAAa;QACb,gBAAgB,EAAE,MAAM,EAAE,CAAA;QAC1B,oBAAoB;QACpB,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAA;QACxE,mCAAmC;QACnC,mBAAmB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAA;QAC/E,0BAA0B;QAC1B,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAA;QAC9E,yBAAyB;QACzB,cAAc,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,KAAK,MAAM,IAAI,CAAA;KACnE,CAAA;CACF;AAkED;;;;GAIG;AACH,iBAAS,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CA+I9C;AAED,OAAO,EAAE,UAAU,EAAE,CAAA;AACrB,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,CAAA"}
|