@yumerijs/core 1.3.3 → 2.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/dist/core.js CHANGED
@@ -1,121 +1,27 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  Object.defineProperty(exports, "__esModule", { value: true });
36
3
  exports.Core = void 0;
37
- /**
38
- * @time: 2025/08/14 09:48
39
- * @author: FireGuo
40
- * WindyPear-Team All right reserved
41
- **/
42
- const yaml = __importStar(require("js-yaml"));
43
- const fs = __importStar(require("fs"));
44
- const path = __importStar(require("path"));
45
- const config_1 = require("./config");
46
4
  const logger_1 = require("./logger");
47
- const chokidar = __importStar(require("chokidar"));
48
5
  const route_1 = require("./route");
49
- const context_1 = require("./context");
50
6
  const hook_1 = require("./hook");
51
7
  const server_1 = require("./server");
52
8
  class Core {
53
- plugins = {};
54
- config = null;
55
9
  eventListeners = {};
56
10
  components = {};
57
11
  routes = {};
58
- pluginLoader;
59
12
  logger = new logger_1.Logger('core');
60
13
  globalMiddlewares = {};
61
- pluginStatus = {};
62
14
  hooks = {};
63
15
  coreConfig;
64
16
  server;
65
- pluginWatchers = {};
66
- pluginModules = {};
67
- configPath = '';
68
- /**
69
- * 插件名 -> Context 映射
70
- */
71
- pluginContexts = {};
72
- constructor(pluginLoader, coreConfig) {
73
- this.coreConfig = coreConfig;
74
- this.pluginLoader = pluginLoader;
75
- }
76
- /**
77
- * 获取或创建插件对应 Context
78
- */
79
- getContext(pluginName) {
80
- if (!this.pluginContexts[pluginName]) {
81
- this.pluginContexts[pluginName] = new context_1.Context(this, pluginName);
82
- }
83
- return this.pluginContexts[pluginName];
84
- }
85
- /**
86
- * 清理指定插件注册的所有内容
87
- */
88
- unregall(pluginName) {
89
- const ctx = this.pluginContexts[pluginName];
90
- if (ctx) {
91
- ctx.dispose();
92
- delete this.pluginContexts[pluginName];
93
- }
94
- }
95
- /**
96
- * 加载配置文件
97
- * @param configPath 配置文件的路径
98
- */
99
- async loadConfig(configPath) {
100
- try {
101
- this.configPath = configPath;
102
- const doc = yaml.load(fs.readFileSync(configPath, 'utf8'));
103
- this.config = doc;
104
- this.logger.info('Config loaded.');
105
- if (process.env.NODE_ENV === 'development') {
106
- this.watchConfig(configPath);
107
- }
108
- this.coreConfig = this.config.core || {};
109
- }
110
- catch (e) {
111
- this.logger.error('Failed to load config:', e);
112
- throw e;
113
- }
17
+ i18n;
18
+ loader;
19
+ constructor(loader, coreConfig, setCore = true) {
20
+ this.coreConfig = coreConfig || {};
21
+ this.loader = loader;
22
+ if (setCore)
23
+ logger_1.Logger.setCore(this);
114
24
  }
115
- /**
116
- * 启动应用
117
- * @returns Promise<void>
118
- */
119
25
  async runCore() {
120
26
  this.server = new server_1.Server(this, {
121
27
  port: this.coreConfig.port || 14510,
@@ -127,369 +33,38 @@ class Core {
127
33
  await this.server.start();
128
34
  this.logger.info(`Yumeri server started at ${this.coreConfig.host}:${this.coreConfig.port}`);
129
35
  }
130
- /**
131
- * 监听配置文件变化,实现热重载
132
- * @param configPath 配置文件的路径
133
- */
134
- watchConfig(configPath) {
135
- const watcher = chokidar.watch(configPath, {
136
- persistent: true,
137
- ignoreInitial: true,
138
- awaitWriteFinish: {
139
- stabilityThreshold: 300,
140
- pollInterval: 100,
141
- },
142
- });
143
- watcher.on('change', async () => {
144
- try {
145
- const doc = yaml.load(fs.readFileSync(configPath, 'utf8'));
146
- if (doc && doc.plugins) {
147
- this.config.plugins = doc.plugins;
148
- }
149
- await this.emit('config-changed', this.config);
150
- }
151
- catch (error) {
152
- this.logger.error('Failed to reload config:', error);
153
- }
154
- });
155
- this.logger.info(`Watching for config changes at ${configPath}`);
156
- }
157
- /**
158
- * 获取指定插件的配置
159
- * @param pluginName 插件名称
160
- * @returns 插件的配置对象
161
- */
162
- async getPluginConfig(pluginName) {
163
- const actualPluginName = pluginName.startsWith('~') ? pluginName.substring(1) : pluginName;
164
- if (this.configPath && process.env.NODE_ENV === 'development') {
165
- try {
166
- const doc = yaml.load(fs.readFileSync(this.configPath, 'utf8'));
167
- if (doc && doc.plugins) {
168
- this.config.plugins = doc.plugins;
169
- }
170
- }
171
- catch (error) {
172
- this.logger.warn('Failed to refresh config for hot reload:', error);
173
- }
174
- }
175
- if (!this.config.plugins[actualPluginName]) {
176
- return new config_1.Config(actualPluginName);
177
- }
178
- return new config_1.Config(actualPluginName, this.config.plugins[actualPluginName]);
179
- }
180
- /**
181
- * 加载所有在配置文件中启用的插件
182
- * @returns Promise<void>
183
- */
184
- async loadPlugins() {
185
- if (!this.config || typeof this.config.plugins !== 'object' || this.config.plugins === null) {
186
- this.logger.info('No plugins configuration found. No plugins to load.');
187
- return;
188
- }
189
- const allPluginNames = Object.keys(this.config.plugins);
190
- this.pluginStatus = {}; // 重置状态
191
- // 初始化所有插件的状态
192
- for (const name of allPluginNames) {
193
- if (name.startsWith('~')) {
194
- const actualName = name.substring(1);
195
- this.pluginStatus[actualName] = "disabled" /* PluginStatus.DISABLED */;
196
- }
197
- else {
198
- this.pluginStatus[name] = "pending" /* PluginStatus.PENDING */; // 默认为等待加载
199
- }
200
- }
201
- const enabledPlugins = allPluginNames.filter(name => !name.startsWith('~'));
202
- // 卸载配置中已禁用或移除的已加载插件
203
- const currentlyLoaded = Object.keys(this.plugins);
204
- for (const loadedName of currentlyLoaded) {
205
- if (!enabledPlugins.includes(loadedName)) {
206
- await this.unloadPlugin(loadedName);
207
- }
208
- }
209
- if (enabledPlugins.length === 0) {
210
- this.logger.info('No enabled plugins found in configuration.');
211
- return;
212
- }
213
- // this.logger.info(`Disabled plugins: ${Object.keys(this.pluginStatus).filter(p => this.pluginStatus[p] === PluginStatus.DISABLED).join(', ') || 'None'}`);
214
- // 循环加载,直到没有插件可以被加载
215
- let loadedInLastPass = true;
216
- while (loadedInLastPass) {
217
- loadedInLastPass = false;
218
- for (const pluginName of enabledPlugins) {
219
- // 如果插件已经是启用状态,则跳过
220
- if (this.pluginStatus[pluginName] === "enabled" /* PluginStatus.ENABLED */) {
221
- continue;
222
- }
223
- // 尝试加载单个插件
224
- const success = await this.loadSinglePlugin(pluginName, false); // 内部加载,不触发后续的pending检查
225
- if (success) {
226
- loadedInLastPass = true;
227
- }
228
- }
229
- }
230
- // 加载完所有能加载的插件后,统一检查并加载待定插件
231
- await this._loadPendingPlugins();
232
- const pendingPlugins = Object.keys(this.pluginStatus).filter(p => this.pluginStatus[p] === "pending" /* PluginStatus.PENDING */);
233
- if (pendingPlugins.length > 0) {
234
- // this.logger.warn('Some plugins could not be loaded due to unresolved dependencies:', pendingPlugins);
235
- }
236
- }
237
- /**
238
- * 加载单个插件
239
- * @param pluginName 要加载的插件名
240
- * @param triggerPendingCheck 是否在加载后触发对其他待定插件的检查,默认为 true
241
- * @returns Promise<boolean> 是否加载成功
242
- */
243
- async loadSinglePlugin(pluginName, triggerPendingCheck = true, onlypending = false) {
244
- // 如果插件不存在于状态记录中(例如,动态添加),则设为 PENDING
245
- if (!this.pluginStatus[pluginName]) {
246
- this.pluginStatus[pluginName] = "pending" /* PluginStatus.PENDING */;
247
- }
248
- // 只有 PENDING 状态的插件才能被加载
249
- if (this.pluginStatus[pluginName] !== "pending" /* PluginStatus.PENDING */ && onlypending) {
250
- // this.logger.info(`Plugin "${pluginName}" is not in a pending state (current: ${this.pluginStatus[pluginName]}). Skipping load.`);
251
- return false;
252
- }
253
- try {
254
- const pluginInstance = await this.pluginLoader.load(pluginName);
255
- if (!pluginInstance) {
256
- throw new Error('Plugin loader returned no instance.');
257
- }
258
- const deps = pluginInstance.depend || [];
259
- const unmetDependencies = deps.filter(dep => !this.components[dep]);
260
- if (unmetDependencies.length > 0) {
261
- // this.logger.info(`Plugin "${pluginName}" has unmet dependencies: [${unmetDependencies.join(', ')}]. Will retry later.`);
262
- return false;
263
- }
264
- // 依赖满足,开始加载
265
- this.plugins[pluginName] = pluginInstance;
266
- if (pluginInstance.apply) {
267
- this.pluginLoader.logger.info(`Apply plugin "${pluginName}"`);
268
- await pluginInstance.apply(this.getContext(pluginName), await this.getPluginConfig(pluginName));
269
- }
270
- // 注册提供的组件
271
- // if (pluginInstance.provide) {
272
- // for (const componentName of pluginInstance.provide) {
273
- // if (this.components[componentName]) {
274
- // this.logger.error(`Component "${componentName}" is provided by multiple plugins: "${this.providedComponents[componentName]}" and "${pluginName}".`);
275
- // } else {
276
- // this.components[componentName] = pluginName;
277
- // }
278
- // }
279
- // }
280
- this.pluginStatus[pluginName] = "enabled" /* PluginStatus.ENABLED */; // 更新状态为已启用
281
- // 加载成功后,检查是否可以加载其他等待中的插件
282
- if (triggerPendingCheck) {
283
- await this._loadPendingPlugins();
284
- }
285
- // In development mode, watch the plugin for changes.
286
- if (process.env.NODE_ENV === 'development') {
287
- let pluginPathToWatch = null;
288
- try {
289
- const pkgJsonPath = require.resolve(`${pluginName}/package.json`);
290
- pluginPathToWatch = path.dirname(pkgJsonPath);
291
- }
292
- catch (e) {
293
- const localPluginPath = path.resolve(process.cwd(), pluginName);
294
- const localPluginPathInPlugins = path.resolve(process.cwd(), 'plugins', pluginName);
295
- if (fs.existsSync(localPluginPath)) {
296
- pluginPathToWatch = localPluginPath;
297
- }
298
- else if (fs.existsSync(localPluginPathInPlugins)) {
299
- pluginPathToWatch = localPluginPathInPlugins;
300
- }
301
- }
302
- if (pluginPathToWatch) {
303
- this.watchPlugin(pluginName, pluginPathToWatch);
304
- }
305
- else {
306
- this.logger.warn(`Could not resolve path for plugin ${pluginName} to watch for changes.`);
307
- }
308
- }
309
- return true;
310
- }
311
- catch (err) {
312
- this.pluginLoader.logger.error(`Failed to load plugin "${pluginName}":`, err);
313
- // 加载失败的插件保持 PENDING 状态,以便后续重试
314
- return false;
36
+ getShortPluginName(pluginName) {
37
+ const scopeRegex = /^(@[^/]+\/)/;
38
+ const scopeMatch = pluginName.match(scopeRegex);
39
+ const scope = scopeMatch ? scopeMatch[0] : '';
40
+ const nameWithoutScope = pluginName.replace(scopeRegex, '');
41
+ if (nameWithoutScope.startsWith('yumeri-plugin-')) {
42
+ return `${scope}${nameWithoutScope.substring('yumeri-plugin-'.length)}`;
315
43
  }
44
+ return pluginName;
316
45
  }
317
- /**
318
- * 尝试加载所有处于 PENDING 状态的插件
319
- * @returns Promise<void>
320
- */
321
- async _loadPendingPlugins() {
322
- const pendingPlugins = Object.keys(this.pluginStatus).filter(p => this.pluginStatus[p] === "pending" /* PluginStatus.PENDING */);
323
- if (pendingPlugins.length === 0)
324
- return;
325
- // this.logger.info('Checking pending plugins...');
326
- for (const pluginName of pendingPlugins) {
327
- await this.loadSinglePlugin(pluginName, false); // 递归调用,但不触发顶层的pending检查
46
+ async plugin(pluginInstance, context, config) {
47
+ const shortName = this.getShortPluginName(context.pluginname);
48
+ this.logger.info(`apply plugin ${shortName}`);
49
+ if (pluginInstance.apply) {
50
+ await pluginInstance.apply(context, config);
328
51
  }
329
52
  }
330
- /**
331
- * 卸载插件,并递归卸载依赖于它的其他插件
332
- * @param pluginNameToUnload 要卸载的插件名
333
- */
334
- async unloadPlugin(pluginNameToUnload, ispending = false) {
335
- // 1. 找出所有直接或间接依赖于此插件的插件
336
- const dependents = [];
337
- const pluginsToCheck = [pluginNameToUnload];
338
- while (pluginsToCheck.length > 0) {
339
- const currentPluginName = pluginsToCheck.shift();
340
- const provided = this.plugins[currentPluginName]?.provide || [];
341
- if (provided.length === 0)
342
- continue;
343
- for (const pluginName in this.plugins) {
344
- if (dependents.includes(pluginName) || pluginName === pluginNameToUnload)
345
- continue;
346
- const deps = this.plugins[pluginName].depend || [];
347
- if (provided.some(p => deps.includes(p))) {
348
- if (!dependents.includes(pluginName)) {
349
- dependents.push(pluginName);
350
- pluginsToCheck.push(pluginName); // 递归查找
351
- // this.logger.info(`Plugin "${pluginName}" depends on "${currentPluginName}" and will be unloaded.`);
352
- }
353
- }
354
- }
355
- }
356
- // 2. 卸载所有依赖者
357
- for (const dependentName of dependents) {
358
- await this.unloadPlugin(dependentName, true);
359
- }
360
- // 3. 最后卸载目标插件
361
- await this._unloadSinglePlugin(pluginNameToUnload, ispending);
362
- // 4. 卸载完成后,尝试重新加载处于 PENDING 状态的插件
363
- // await this._loadPendingPlugins();
364
- }
365
- /**
366
- * 执行单个插件的卸载逻辑
367
- * @param pluginName 插件名
368
- * @param ispending 是否处于 PENDING 状态
369
- */
370
- async _unloadSinglePlugin(pluginName, ispending = false) {
371
- if (this.pluginStatus[pluginName] !== "enabled" /* PluginStatus.ENABLED */) {
372
- return; // 只卸载已启用的插件
373
- }
374
- this.logger.info(`Unloading plugin "${pluginName}"...`);
375
- try {
376
- const plugin = this.plugins[pluginName];
377
- if (plugin && plugin.disable)
378
- await plugin.disable(this.getContext(pluginName));
379
- await this.pluginLoader.unloadPlugin(pluginName);
380
- this.unregall(pluginName); // 清理该插件注册的所有内容
381
- delete this.plugins[pluginName];
382
- delete this.pluginModules[pluginName];
383
- this.pluginStatus[pluginName] = ispending ? "pending" /* PluginStatus.PENDING */ : "disabled" /* PluginStatus.DISABLED */;
384
- // Stop watching the plugin directory
385
- if (this.pluginWatchers[pluginName]) {
386
- this.pluginWatchers[pluginName].close();
387
- delete this.pluginWatchers[pluginName];
388
- }
389
- this.emit('plugin-unloaded', pluginName);
390
- }
391
- catch (error) {
392
- this.logger.error(`Failed to unload plugin "${pluginName}":`, error);
393
- }
394
- }
395
- /**
396
- * 重新加载插件
397
- * @param pluginName 插件名称
398
- */
399
- async reloadPlugin(pluginName) {
400
- // this.logger.info(`Reloading plugin "${pluginName}"...`);
401
- // 1. 递归卸载插件及其依赖者
402
- await this.unloadPlugin(pluginName);
403
- // 2. 重新加载该插件
404
- // unloadPlugin 已经将状态设置为 PENDING,所以 loadSinglePlugin 可以直接工作
405
- const success = await this.loadSinglePlugin(pluginName);
406
- if (success) {
407
- // this.logger.info(`Plugin "${pluginName}" reloaded successfully.`);
408
- this.emit('plugin-reloaded', pluginName);
409
- }
410
- else {
411
- this.logger.error(`Failed to reload plugin "${pluginName}". It may have unmet dependencies.`);
412
- }
413
- }
414
- /**
415
- * 监听插件文件变化
416
- * @param pluginName 插件名称
417
- * @param pluginPath 插件路径
418
- */
419
- watchPlugin(pluginName, pluginPath) {
420
- if (this.pluginWatchers[pluginName]) {
421
- return; // Already watching
422
- }
423
- const logger = new logger_1.Logger('hmr');
424
- const watcher = chokidar.watch(pluginPath, {
425
- ignored: /(^|[\/])\../,
426
- persistent: true,
427
- ignoreInitial: true,
428
- awaitWriteFinish: {
429
- stabilityThreshold: 200,
430
- pollInterval: 100,
431
- },
432
- });
433
- watcher.on('change', async (changePath) => {
434
- logger.info(`Plugin file changed: ${changePath}`);
435
- await this.reloadPlugin(pluginName);
436
- });
437
- watcher.on('add', async (changePath) => {
438
- logger.info(`New file added to plugin ${pluginName}: ${changePath}`);
439
- await this.reloadPlugin(pluginName);
440
- });
441
- watcher.on('unlink', async (changePath) => {
442
- logger.info(`File removed from plugin ${pluginName}: ${changePath}`);
443
- await this.reloadPlugin(pluginName);
444
- });
445
- this.pluginWatchers[pluginName] = watcher;
446
- // logger.info(`Watching for changes in plugin: ${pluginName}`);
447
- }
448
- /**
449
- * 注册组件
450
- * @param name 组件名称
451
- * @param component 组件实例
452
- */
453
53
  registerComponent(name, component) {
454
- // if (this.components.hasOwnProperty(name)) {
455
- // this.logger.warn(`Component "${name}" already registered by plugin "${this.providedComponents[name]}".`);
456
- // return;
457
- // }
458
54
  this.components[name] = component;
459
- // this.logger.info(`Component "${name}" registered.`);
460
55
  }
461
- /**
462
- * 获取组件
463
- * @param name 组件名称
464
- * @returns 组件实例
465
- */
466
56
  getComponent(name) {
467
57
  return this.components[name];
468
58
  }
469
- /**
470
- * 注销组件
471
- * @param name 组件名称
472
- */
473
59
  unregisterComponent(name) {
474
60
  delete this.components[name];
475
- // delete this.providedComponents[name];
476
61
  }
477
- /**
478
- * 注册事件监听器
479
- * @param event 事件名称
480
- * @param listener 事件回调函数
481
- */
482
62
  on(event, listener) {
483
63
  if (!this.eventListeners[event]) {
484
64
  this.eventListeners[event] = [];
485
65
  }
486
66
  this.eventListeners[event].push(listener);
487
67
  }
488
- /**
489
- * 触发事件
490
- * @param event 事件名称
491
- * @param args 传递给事件监听器的参数
492
- */
493
68
  async emit(event, ...args) {
494
69
  if (this.eventListeners[event]) {
495
70
  for (const listener of this.eventListeners[event]) {
@@ -502,65 +77,32 @@ class Core {
502
77
  }
503
78
  }
504
79
  }
505
- /**
506
- * 注册全局中间件
507
- * @param name 中间件名称
508
- * @param middleware 中间件函数
509
- * @returns Core 实例
510
- */
511
80
  use(name, middleware) {
512
81
  this.globalMiddlewares[name] = middleware;
513
82
  return this;
514
83
  }
515
- /**
516
- * 注册路由
517
- * @param path 路由路径
518
- * @returns Route 实例
519
- */
520
84
  route(path) {
521
85
  const route = new route_1.Route(path);
522
86
  this.routes[path] = route;
523
87
  return route;
524
88
  }
525
- /**
526
- * 注册 Hook 钩子
527
- * @param name Hook 点名称
528
- * @param hookname 钩子名称
529
- * @param callback 钩子函数
530
- */
531
89
  hook(name, hookname, callback) {
532
90
  if (!this.hooks[name]) {
533
91
  this.hooks[name] = new hook_1.Hook(name);
534
92
  }
535
93
  this.hooks[name].add(hookname, callback);
536
94
  }
537
- /**
538
- * 消除 Hook 钩子
539
- */
540
95
  unhook(name, hookname) {
541
96
  if (this.hooks[name]) {
542
97
  this.hooks[name].remove(hookname);
543
98
  }
544
99
  }
545
- /**
546
- * 执行 Hook 钩子
547
- * @param name Hook 点名称
548
- * @param args 参数
549
- * @return Promise<any[]>
550
- */
551
100
  async hookExecute(name, ...args) {
552
101
  if (this.hooks[name]) {
553
102
  return await this.hooks[name].trigger(...args);
554
103
  }
555
104
  return [];
556
105
  }
557
- /**
558
- * 执行路由
559
- * @param pathname 需要匹配的URL
560
- * @param session 当前会话
561
- * @param queryParams URL参数
562
- * @returns 是否匹配成功
563
- */
564
106
  async executeRoute(pathname, session, queryParams) {
565
107
  for (const routePath in this.routes) {
566
108
  const route = this.routes[routePath];
@@ -580,11 +122,6 @@ class Core {
580
122
  }
581
123
  return false;
582
124
  }
583
- /**
584
- * 获取路由
585
- * @param path 匹配路径
586
- * @return Route 实例或 false
587
- */
588
125
  getRoute(path) {
589
126
  for (const routePath in this.routes) {
590
127
  const route = this.routes[routePath];
package/dist/hook.js CHANGED
@@ -41,9 +41,9 @@ class Hook {
41
41
  * @returns 执行结果
42
42
  */
43
43
  async trigger(...args) {
44
- let result;
44
+ let result = [];
45
45
  for (const handler of Object.values(this.handlers)) {
46
- result.push(handler(...args));
46
+ result.push(await handler(...args));
47
47
  }
48
48
  return result;
49
49
  }
package/dist/i18n.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @time: 2025/10/28 22:13
3
+ * @author: FireGuo
4
+ * WindyPear-Team All right reserved
5
+ **/
6
+ type I18nData = Record<string, Record<string, string>>;
7
+ export declare class I18n {
8
+ private data;
9
+ private fallback;
10
+ constructor(fallback?: string[]);
11
+ register(key: string | Record<string, any>, lang?: Record<string, string>): void;
12
+ setFallback(fallback: string[]): void;
13
+ private flattenAndRegister;
14
+ isRegistered(key: string): boolean;
15
+ delete(key: string): void;
16
+ /**
17
+ * 获取指定key的翻译
18
+ * @param key 文本点
19
+ * @param langs 用户的语言优先级数组
20
+ */
21
+ get(key: string, langs?: string[]): string;
22
+ /**
23
+ * 替换模板字符串中的文本点
24
+ * e.g. "Hello {{app.title}}" -> "Hello 世界"
25
+ */
26
+ replaceAll(input: string, langs?: string[]): string;
27
+ all(): I18nData;
28
+ }
29
+ export {};