monaco-editor-nls-adapter 1.0.0 → 2.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/README.md +84 -26
- package/README_zh.md +84 -26
- package/index.d.ts +36 -18
- package/index.js +84 -15
- package/loader.js +15 -1
- package/package.json +31 -3
- package/proxy.js +4 -5
- package/transform.js +53 -17
- package/vite-plugin.js +20 -8
- package/locales/qps-ploc.json +0 -12669
package/README.md
CHANGED
|
@@ -13,10 +13,24 @@ Multi-language NLS adapter for Monaco Editor 0.50.0+ (Self-hosted). Bridge the g
|
|
|
13
13
|
|
|
14
14
|
- **Self-hosted Locales**: No external CDN dependencies; all language data is bundled locally.
|
|
15
15
|
- **Monaco 0.50.0+ Ready**: Fully compatible with the latest internal NLS signatures of Monaco Editor.
|
|
16
|
+
- **SourceMap Support**: Powered by `magic-string` for accurate source-to-bundle mapping and worry-free debugging.
|
|
16
17
|
- **Zero-Config Lazy Loading**: Support for asynchronous initialization with Webpack/Vite chunk splitting.
|
|
17
18
|
- **TypeScript Support**: First-class TS definitions for an excellent developer experience.
|
|
18
|
-
- **
|
|
19
|
+
- **Flexible API**: Advanced interfaces like `getCurrentLocale` and `setMessages` (custom data).
|
|
19
20
|
- **Cross-Bundler**: Native support for **Webpack** (Loader) and **Vite/Rollup** (Plugin).
|
|
21
|
+
- **Zero Configuration**: Automatic detection of `pnpm` and monorepo paths out of the box.
|
|
22
|
+
- **Ultra-lightweight**: Redundant test files removed for even faster installation.
|
|
23
|
+
|
|
24
|
+
## 📦 Supported Frameworks
|
|
25
|
+
|
|
26
|
+
This adapter is compatible with all modern frontend frameworks:
|
|
27
|
+
|
|
28
|
+
- **Vue 2**: Seamless integration with Vue CLI and Webpack projects.
|
|
29
|
+
- **Vue 3**: Full support for Vite and Vue CLI configurations.
|
|
30
|
+
- **React**: Compatible with native React apps and `@monaco-editor/react` (supports disabling CDN).
|
|
31
|
+
- **Angular**: Compatible with Angular CLI (Webpack/Vite) build environments.
|
|
32
|
+
- **SSR Frameworks**: Ready for **Next.js** and **Nuxt** server-side rendering environments.
|
|
33
|
+
- **Universal**: Theoretically supports any web project built with **Webpack**, **Vite**, or **Rollup**.
|
|
20
34
|
|
|
21
35
|
## 🚀 Installation
|
|
22
36
|
|
|
@@ -31,16 +45,23 @@ npm install monaco-editor-nls-adapter
|
|
|
31
45
|
In your `webpack.config.js`, add the adapter's loader to process Monaco Editor's ESM files.
|
|
32
46
|
|
|
33
47
|
```javascript
|
|
48
|
+
const { loader } = require('monaco-editor-nls-adapter');
|
|
49
|
+
|
|
34
50
|
module.exports = {
|
|
35
51
|
module: {
|
|
36
52
|
rules: [
|
|
37
53
|
{
|
|
38
54
|
test: /\.js$/,
|
|
39
|
-
// Crucial: Only process monaco-editor
|
|
40
|
-
include: /
|
|
55
|
+
// Crucial: Only process monaco-editor ESM files
|
|
56
|
+
include: /monaco-editor[\\/]esm/,
|
|
41
57
|
use: [
|
|
42
58
|
{
|
|
43
|
-
loader:
|
|
59
|
+
loader: loader,
|
|
60
|
+
options: {
|
|
61
|
+
// Optional: Custom monaco path fragment
|
|
62
|
+
// Detected automatically in most project structures (npm, pnpm, yarn)
|
|
63
|
+
// monacoPath: 'monaco-editor/esm'
|
|
64
|
+
}
|
|
44
65
|
}
|
|
45
66
|
]
|
|
46
67
|
}
|
|
@@ -49,17 +70,42 @@ module.exports = {
|
|
|
49
70
|
}
|
|
50
71
|
```
|
|
51
72
|
|
|
52
|
-
### 2.
|
|
73
|
+
### 2. Vue CLI (`vue.config.js`)
|
|
74
|
+
|
|
75
|
+
For projects using Vue CLI, you can configure the loader via `chainWebpack`:
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
const { loader } = require('monaco-editor-nls-adapter');
|
|
79
|
+
|
|
80
|
+
module.exports = {
|
|
81
|
+
chainWebpack: config => {
|
|
82
|
+
config.module
|
|
83
|
+
.rule('monaco-editor-nls')
|
|
84
|
+
.test(/\.js$/)
|
|
85
|
+
.include.add(/monaco-editor[\\/]esm/)
|
|
86
|
+
.end()
|
|
87
|
+
.use('nls-loader')
|
|
88
|
+
.loader(loader)
|
|
89
|
+
.end();
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 3. Vite / Rollup (Plugin)
|
|
53
95
|
|
|
54
96
|
In your `vite.config.js` or `vite.config.ts`:
|
|
55
97
|
|
|
56
98
|
```javascript
|
|
57
99
|
import { defineConfig } from 'vite';
|
|
58
|
-
import
|
|
100
|
+
import { vitePlugin } from 'monaco-editor-nls-adapter';
|
|
59
101
|
|
|
60
102
|
export default defineConfig({
|
|
61
103
|
plugins: [
|
|
62
|
-
|
|
104
|
+
vitePlugin({
|
|
105
|
+
// Optional: Custom monaco path fragment
|
|
106
|
+
// Automatically detected (works with pnpm and monorepos)
|
|
107
|
+
// monacoPath: 'monaco-editor/esm'
|
|
108
|
+
})
|
|
63
109
|
]
|
|
64
110
|
});
|
|
65
111
|
```
|
|
@@ -70,35 +116,47 @@ export default defineConfig({
|
|
|
70
116
|
|
|
71
117
|
Call `init` or `initAsync` **before** importing `monaco-editor` or creating any editor instances.
|
|
72
118
|
|
|
73
|
-
```typescript
|
|
74
119
|
import * as nlsAdapter from 'monaco-editor-nls-adapter';
|
|
75
120
|
|
|
76
|
-
|
|
77
|
-
* Option 1: Synchronous (Standard)
|
|
78
|
-
* Recommended for small clusters or if you don't mind the initial bundle size.
|
|
79
|
-
*/
|
|
121
|
+
// 1. Synchronous (Standard)
|
|
80
122
|
nlsAdapter.init('zh-hans');
|
|
81
123
|
|
|
82
|
-
|
|
83
|
-
* Option 2: Asynchronous (Performance Optimization)
|
|
84
|
-
* Leverages Webpack/Vite dynamic imports for code splitting.
|
|
85
|
-
*/
|
|
124
|
+
// 2. Asynchronous (Code Splitting)
|
|
86
125
|
// await nlsAdapter.initAsync('zh-hans');
|
|
87
126
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
*/
|
|
91
|
-
// nlsAdapter.init(); // Sync
|
|
92
|
-
// await nlsAdapter.initAsync(); // Async
|
|
127
|
+
// 3. Get current locale
|
|
128
|
+
console.log(nlsAdapter.getCurrentLocale()); // 'zh-hans'
|
|
93
129
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
130
|
+
// 4. Custom Messages (Override built-in locales)
|
|
131
|
+
/*
|
|
132
|
+
nlsAdapter.setMessages({
|
|
133
|
+
'vs/editor/common/editorContextKeys': {
|
|
134
|
+
'editor.action.clipboardCopyAction': 'Copy (Custom)'
|
|
135
|
+
}
|
|
99
136
|
});
|
|
137
|
+
*/
|
|
138
|
+
|
|
139
|
+
import * as monaco from 'monaco-editor';
|
|
140
|
+
// ... create editor as usual
|
|
100
141
|
```
|
|
101
142
|
|
|
143
|
+
### Framework Integration (React / Vue)
|
|
144
|
+
|
|
145
|
+
This package works seamlessly with major frameworks. Special note for **React** (@monaco-editor/react): Make sure to use `loader.config({ monaco })` to disable CDN and map to your local, localized monaco instance.
|
|
146
|
+
|
|
147
|
+
See: [Framework Integration Best Practices (Examples)](./examples/framework-integration.md)
|
|
148
|
+
|
|
149
|
+
### API Reference
|
|
150
|
+
|
|
151
|
+
| Function | Description |
|
|
152
|
+
| --- | --- |
|
|
153
|
+
| `init(locale?: string): boolean` | Synchronous initialization. Tries to detect browser language if omitted. Returns success status. |
|
|
154
|
+
| `initAsync(locale?: string): Promise<boolean>` | Asynchronous initialization with dynamic imports. Returns success status. |
|
|
155
|
+
| `getCurrentLocale(): string` | Returns the currently active locale code. Returns `custom` if set via `setMessages`. |
|
|
156
|
+
| `setMessages(data: object)` | Manually inject translation data. Must follow Monaco's NLS structure. |
|
|
157
|
+
| `vitePlugin(options?: object)` | Vite plugin function. |
|
|
158
|
+
| `loader: string` | Absolute path to the Webpack loader. |
|
|
159
|
+
|
|
102
160
|
## 🗂 Supported Locales
|
|
103
161
|
|
|
104
162
|
| Code | Language |
|
package/README_zh.md
CHANGED
|
@@ -14,9 +14,23 @@
|
|
|
14
14
|
- **自托管语言包**: 无需依赖外部 CDN;所有语言数据在本地打包。
|
|
15
15
|
- **适配 Monaco 0.50.0+**: 完全兼容 Monaco Editor 最新的内部 NLS 调用签名。
|
|
16
16
|
- **性能优化 (懒加载)**: 通过 Webpack/Vite 的动态导入实现按需分包加载。
|
|
17
|
+
- **SourceMap 支持**: 基于 `magic-string` 实现转换后的精准还原,调试无忧。
|
|
17
18
|
- **TypeScript 支持**: 完善的类型定义,为开发提供极佳的智能感知。
|
|
18
|
-
-
|
|
19
|
+
- **灵活的 API**: 提供 `getCurrentLocale` 和 `setMessages` (自定义数据) 等高级接口。
|
|
19
20
|
- **跨构建工具支持**: 原生支持 **Webpack** (Loader) 以及 **Vite/Rollup** (Plugin)。
|
|
21
|
+
- **智能路径探测**: 自动识别 `pnpm` 和 monorepo 路径,**零配置**即可使用。
|
|
22
|
+
- **轻量化**: 移除了冗余测试文件,发布包体积进一步精简。
|
|
23
|
+
|
|
24
|
+
## 📦 支持的框架
|
|
25
|
+
|
|
26
|
+
本适配器与主流前端框架均可完美兼容:
|
|
27
|
+
|
|
28
|
+
- **Vue 2**: 完美适配 Vue CLI 和 Webpack 项目。
|
|
29
|
+
- **Vue 3**: 深度支持 Vite 和 Vue CLI 配置。
|
|
30
|
+
- **React**: 适配原生 React 应用及 `@monaco-editor/react` (支持禁用 CDN)。
|
|
31
|
+
- **Angular**: 支持 Angular CLI (Webpack/Vite) 构建环境。
|
|
32
|
+
- **SSR 框架**: 兼容 **Next.js** 和 **Nuxt** 等服务端渲染环境。
|
|
33
|
+
- **通用**: 理论上支持任何基于 **Webpack**、**Vite** 或 **Rollup** 构建的 web 项目。
|
|
20
34
|
|
|
21
35
|
## 🚀 安装
|
|
22
36
|
|
|
@@ -31,16 +45,23 @@ npm install monaco-editor-nls-adapter
|
|
|
31
45
|
在 `webpack.config.js` 中,添加此适配器的 loader 来处理 Monaco Editor 的 ESM 源码。
|
|
32
46
|
|
|
33
47
|
```javascript
|
|
48
|
+
const { loader } = require('monaco-editor-nls-adapter');
|
|
49
|
+
|
|
34
50
|
module.exports = {
|
|
35
51
|
module: {
|
|
36
52
|
rules: [
|
|
37
53
|
{
|
|
38
54
|
test: /\.js$/,
|
|
39
|
-
// 重要:仅处理 monaco-editor 的 esm
|
|
40
|
-
include: /
|
|
55
|
+
// 重要:仅处理 monaco-editor 的 esm 目录
|
|
56
|
+
include: /monaco-editor[\\/]esm/,
|
|
41
57
|
use: [
|
|
42
58
|
{
|
|
43
|
-
loader:
|
|
59
|
+
loader: loader,
|
|
60
|
+
options: {
|
|
61
|
+
// 可选:自定义 monaco 路径片段
|
|
62
|
+
// 插件会自动探测 node_modules 下的 monaco-editor/esm,通常无需配置
|
|
63
|
+
// monacoPath: 'monaco-editor/esm'
|
|
64
|
+
}
|
|
44
65
|
}
|
|
45
66
|
]
|
|
46
67
|
}
|
|
@@ -49,17 +70,42 @@ module.exports = {
|
|
|
49
70
|
}
|
|
50
71
|
```
|
|
51
72
|
|
|
52
|
-
### 2.
|
|
73
|
+
### 2. Vue CLI (`vue.config.js`)
|
|
74
|
+
|
|
75
|
+
对于使用 Vue CLI 的项目,建议使用 `chainWebpack` 进行配置:
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
const { loader } = require('monaco-editor-nls-adapter');
|
|
79
|
+
|
|
80
|
+
module.exports = {
|
|
81
|
+
chainWebpack: config => {
|
|
82
|
+
config.module
|
|
83
|
+
.rule('monaco-editor-nls')
|
|
84
|
+
.test(/\.js$/)
|
|
85
|
+
.include.add(/monaco-editor[\\/]esm/)
|
|
86
|
+
.end()
|
|
87
|
+
.use('nls-loader')
|
|
88
|
+
.loader(loader)
|
|
89
|
+
.end();
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 3. Vite / Rollup (Plugin)
|
|
53
95
|
|
|
54
96
|
在 `vite.config.js` 中,添加此插件:
|
|
55
97
|
|
|
56
98
|
```javascript
|
|
57
99
|
import { defineConfig } from 'vite';
|
|
58
|
-
import
|
|
100
|
+
import { vitePlugin } from 'monaco-editor-nls-adapter';
|
|
59
101
|
|
|
60
102
|
export default defineConfig({
|
|
61
103
|
plugins: [
|
|
62
|
-
|
|
104
|
+
vitePlugin({
|
|
105
|
+
// 可选:自定义 monaco 路径片段
|
|
106
|
+
// 插件会自动探测物理路径(支持 pnpm),通常无需配置
|
|
107
|
+
// monacoPath: 'monaco-editor/esm'
|
|
108
|
+
})
|
|
63
109
|
]
|
|
64
110
|
});
|
|
65
111
|
```
|
|
@@ -70,35 +116,47 @@ export default defineConfig({
|
|
|
70
116
|
|
|
71
117
|
在导入 `monaco-editor` 或创建任何实例**之前**,先调用 `init` 或 `initAsync`。
|
|
72
118
|
|
|
73
|
-
```typescript
|
|
74
119
|
import * as nlsAdapter from 'monaco-editor-nls-adapter';
|
|
75
120
|
|
|
76
|
-
|
|
77
|
-
* 方式 1: 同步初始化 (标准用法)
|
|
78
|
-
* 适用于语言包体量较小,或不介意首屏全量包含翻译数据的场景。
|
|
79
|
-
*/
|
|
121
|
+
// 1. 同步初始化 (标准用法)
|
|
80
122
|
nlsAdapter.init('zh-hans');
|
|
81
123
|
|
|
82
|
-
|
|
83
|
-
* 方式 2: 异步初始化 (性能优化推荐)
|
|
84
|
-
* 利用 Webpack/Vite 的动态 import 实现分包,仅加载当前所需语言。
|
|
85
|
-
*/
|
|
124
|
+
// 2. 异步初始化 (分包懒加载)
|
|
86
125
|
// await nlsAdapter.initAsync('zh-hans');
|
|
87
126
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
*/
|
|
91
|
-
// nlsAdapter.init(); // 同步
|
|
92
|
-
// await nlsAdapter.initAsync(); // 异步
|
|
127
|
+
// 3. 获取当前语言
|
|
128
|
+
console.log(nlsAdapter.getCurrentLocale()); // 'zh-hans'
|
|
93
129
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
130
|
+
// 4. 使用自定义翻译数据 (不使用内置语言包)
|
|
131
|
+
/*
|
|
132
|
+
nlsAdapter.setMessages({
|
|
133
|
+
'vs/editor/common/editorContextKeys': {
|
|
134
|
+
'editor.action.clipboardCopyAction': '复制 (Custom)'
|
|
135
|
+
}
|
|
99
136
|
});
|
|
137
|
+
*/
|
|
138
|
+
|
|
139
|
+
import * as monaco from 'monaco-editor';
|
|
140
|
+
// ... 之后正常创建编辑器
|
|
100
141
|
```
|
|
101
142
|
|
|
143
|
+
### 框架集成 (React / Vue)
|
|
144
|
+
|
|
145
|
+
本项目与主流框架完美配合。特别注意:若使用 **React** (@monaco-editor/react),请务必通过 `loader.config({ monaco })` 禁用 CDN 并映射到本地实例。
|
|
146
|
+
|
|
147
|
+
详细的框架集成指南请参考:[框架集成最佳实践 (Examples)](./examples/framework-integration.md)
|
|
148
|
+
|
|
149
|
+
### API 详述
|
|
150
|
+
|
|
151
|
+
| 函数 | 说明 |
|
|
152
|
+
| --- | --- |
|
|
153
|
+
| `init(locale?: string): boolean` | 同步初始化。如果不传参数,尝试探测浏览器语言。返回是否加载成功。 |
|
|
154
|
+
| `initAsync(locale?: string): Promise<boolean>` | 异步初始化。利用动态 import 拆分语言包。返回是否加载成功。 |
|
|
155
|
+
| `getCurrentLocale(): string` | 获取当前已生效的语言代码。如果是自定义数据,返回 `custom`。 |
|
|
156
|
+
| `setMessages(data: object)` | 手动注入翻译字典。格式需符合 Monaco 的 NLS 结构。 |
|
|
157
|
+
| `vitePlugin(options?: object)` | Vite 插件函数。 |
|
|
158
|
+
| `loader: string` | Webpack Loader 的绝对路径。 |
|
|
159
|
+
|
|
102
160
|
## 🗂 支持的语言列表
|
|
103
161
|
|
|
104
162
|
| 语言代码 | 对应语言 |
|
package/index.d.ts
CHANGED
|
@@ -1,16 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
localize2(path: string, data: any, defaultMessage: string, ...args: any[]): { value: string; original: string };
|
|
4
|
-
setLocaleData(data: Record<string, any>): void;
|
|
5
|
-
getConfiguredDefaultLocale(): string | undefined;
|
|
6
|
-
loadMessageBundle(file: string): (path: string, data: any, defaultMessage: string, ...args: any[]) => string;
|
|
7
|
-
config(opt: any): (file: string) => any;
|
|
8
|
-
create(key: string, data: any): {
|
|
9
|
-
localize: (idx: any, defaultValue: string, ...args: any[]) => string;
|
|
10
|
-
localize2: (idx: any, defaultValue: string, ...args: any[]) => { value: string; original: string };
|
|
11
|
-
getConfiguredDefaultLocale: () => string | undefined;
|
|
12
|
-
};
|
|
13
|
-
}
|
|
1
|
+
import { NLSProxy } from './proxy';
|
|
2
|
+
import monacoNlsPlugin from './vite-plugin';
|
|
14
3
|
|
|
15
4
|
/**
|
|
16
5
|
* 支持的语言代码类型
|
|
@@ -21,18 +10,47 @@ export type LocaleCode =
|
|
|
21
10
|
|
|
22
11
|
/**
|
|
23
12
|
* 初始化 Monaco Editor 的语言包
|
|
24
|
-
* @param locale 语言代码,如 'zh-hans'
|
|
13
|
+
* @param locale 语言代码,如 'zh-hans'
|
|
14
|
+
* @param force 是否强制重新初始化
|
|
15
|
+
* @returns 是否加载成功
|
|
25
16
|
*/
|
|
26
|
-
export function init(locale?: LocaleCode | string):
|
|
17
|
+
export function init(locale?: LocaleCode | string, force?: boolean): boolean;
|
|
27
18
|
|
|
28
19
|
/**
|
|
29
20
|
* 异步初始化 Monaco Editor 的语言包
|
|
30
|
-
* 使用动态 import(),支持 Webpack 分包和懒加载。
|
|
31
21
|
* @param locale 语言代码
|
|
22
|
+
* @param force 是否强制重新加载
|
|
23
|
+
* @returns 是否加载成功
|
|
32
24
|
*/
|
|
33
|
-
export function initAsync(locale?: LocaleCode | string): Promise<
|
|
25
|
+
export function initAsync(locale?: LocaleCode | string, force?: boolean): Promise<boolean>;
|
|
34
26
|
|
|
35
27
|
/**
|
|
36
|
-
*
|
|
28
|
+
* 获取当前已生效的语言代码
|
|
29
|
+
*/
|
|
30
|
+
export function getCurrentLocale(): string;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 手动设置翻译数据字典
|
|
34
|
+
* @param messages 符合 Monaco NLS 格式的 JSON 对象
|
|
35
|
+
*/
|
|
36
|
+
export function setMessages(messages: Record<string, any>): void;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* NLS 代理对象声明
|
|
37
40
|
*/
|
|
38
41
|
export const proxy: NLSProxy;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Vite 插件导出
|
|
45
|
+
*/
|
|
46
|
+
export const vitePlugin: typeof monacoNlsPlugin;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Webpack Loader 绝对路径导出 (用于 webpack.config.js)
|
|
50
|
+
*/
|
|
51
|
+
export const loader: string;
|
|
52
|
+
|
|
53
|
+
// 重新导出子模块中的类型,方便从主模块引用
|
|
54
|
+
export { NLSProxy } from './proxy';
|
|
55
|
+
export { PluginOptions } from './vite-plugin';
|
|
56
|
+
export { transform } from './transform';
|
package/index.js
CHANGED
|
@@ -11,17 +11,39 @@ const LOCALE_MAP = {
|
|
|
11
11
|
'zh-hk': 'zh-hant',
|
|
12
12
|
'en-us': 'en',
|
|
13
13
|
'en-gb': 'en',
|
|
14
|
-
'en': 'en'
|
|
14
|
+
'en': 'en',
|
|
15
|
+
'ja-jp': 'ja',
|
|
16
|
+
'ja': 'ja',
|
|
17
|
+
'ko-kr': 'ko',
|
|
18
|
+
'ko': 'ko',
|
|
19
|
+
'de-de': 'de',
|
|
20
|
+
'de': 'de',
|
|
21
|
+
'fr-fr': 'fr',
|
|
22
|
+
'fr': 'fr',
|
|
23
|
+
'es-es': 'es',
|
|
24
|
+
'es': 'es',
|
|
25
|
+
'it-it': 'it',
|
|
26
|
+
'it': 'it',
|
|
27
|
+
'ru-ru': 'ru',
|
|
28
|
+
'ru': 'ru',
|
|
29
|
+
'pt-br': 'pt-br'
|
|
15
30
|
}
|
|
16
31
|
|
|
32
|
+
let CURRENT_LOCALE = ''
|
|
33
|
+
let IS_LOADING = false
|
|
34
|
+
|
|
17
35
|
/**
|
|
18
36
|
* 使用指定的语言代码初始化 Monaco Editor 的本地化。
|
|
19
37
|
* 此方法会从本地 /locales 目录加载 JSON 数据。
|
|
20
38
|
* @param {string} locale 语言代码 (例如 'zh-hans', 'ja', 'ko')。如果不传,将尝试检测浏览器语言。
|
|
39
|
+
* @param {boolean} force 是否强制重新初始化,即使语言相同。
|
|
21
40
|
*/
|
|
22
|
-
function init(locale) {
|
|
41
|
+
function init(locale, force = false) {
|
|
42
|
+
// SSR 环境安全检查
|
|
43
|
+
const isBrowser = typeof window !== 'undefined' && typeof navigator !== 'undefined'
|
|
44
|
+
|
|
23
45
|
// 如果没有传递 locale,尝试从浏览器环境获取
|
|
24
|
-
if (!locale &&
|
|
46
|
+
if (!locale && isBrowser) {
|
|
25
47
|
locale = navigator.language || navigator.userLanguage
|
|
26
48
|
}
|
|
27
49
|
|
|
@@ -31,43 +53,90 @@ function init(locale) {
|
|
|
31
53
|
targetLocale = LOCALE_MAP[targetLocale]
|
|
32
54
|
}
|
|
33
55
|
|
|
56
|
+
// 幂等检查:如果已经加载过该语言且非强制,则直接返回
|
|
57
|
+
if (CURRENT_LOCALE === targetLocale && !force) {
|
|
58
|
+
return true
|
|
59
|
+
}
|
|
60
|
+
|
|
34
61
|
try {
|
|
35
62
|
const data = require(`./locales/${targetLocale}.json`)
|
|
36
63
|
proxy.setLocaleData(data)
|
|
64
|
+
CURRENT_LOCALE = targetLocale
|
|
65
|
+
return true
|
|
37
66
|
} catch (e) {
|
|
38
|
-
|
|
67
|
+
if (isBrowser) {
|
|
68
|
+
console.warn(`[monaco-editor-nls-adapter] 无法加载本地语言包: ${targetLocale}。回退到默认设置。`, e)
|
|
69
|
+
}
|
|
70
|
+
return false
|
|
39
71
|
}
|
|
40
72
|
}
|
|
41
73
|
|
|
42
74
|
/**
|
|
43
75
|
* 异步初始化 Monaco Editor 的本地化。
|
|
44
|
-
* 使用动态 import(),允许 Webpack 将语言包拆分为独立的 chunk
|
|
45
|
-
* @param {string} locale
|
|
46
|
-
* @
|
|
76
|
+
* 使用动态 import(),允许 Webpack 将语言包拆分为独立的 chunk。
|
|
77
|
+
* @param {string} locale 语言代码。
|
|
78
|
+
* @param {boolean} force 是否强制重新加载。
|
|
79
|
+
* @returns {Promise<boolean>}
|
|
47
80
|
*/
|
|
48
|
-
async function initAsync(locale) {
|
|
49
|
-
|
|
50
|
-
|
|
81
|
+
async function initAsync(locale, force = false) {
|
|
82
|
+
const isBrowser = typeof window !== 'undefined' && typeof navigator !== 'undefined'
|
|
83
|
+
|
|
84
|
+
if (!locale && isBrowser) {
|
|
51
85
|
locale = navigator.language || navigator.userLanguage
|
|
52
86
|
}
|
|
53
87
|
|
|
54
|
-
// 小写化并查找映射
|
|
55
88
|
let targetLocale = (locale || 'zh-hans').toLowerCase()
|
|
56
89
|
if (LOCALE_MAP[targetLocale]) {
|
|
57
90
|
targetLocale = LOCALE_MAP[targetLocale]
|
|
58
91
|
}
|
|
59
92
|
|
|
93
|
+
if (CURRENT_LOCALE === targetLocale && !force) {
|
|
94
|
+
return true
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (IS_LOADING && !force) return false
|
|
98
|
+
IS_LOADING = true
|
|
99
|
+
|
|
60
100
|
try {
|
|
61
|
-
// 使用动态 import
|
|
62
|
-
const module = await import(`./locales/${targetLocale}.json`)
|
|
101
|
+
// 使用动态 import 实现懒加载,并添加 Webpack 魔术注释以优化分包命名
|
|
102
|
+
const module = await import(/* webpackChunkName: "nls-[request]" */ `./locales/${targetLocale}.json`)
|
|
63
103
|
proxy.setLocaleData(module.default || module)
|
|
104
|
+
CURRENT_LOCALE = targetLocale
|
|
105
|
+
return true
|
|
64
106
|
} catch (e) {
|
|
65
|
-
|
|
107
|
+
if (isBrowser) {
|
|
108
|
+
console.warn(`[monaco-editor-nls-adapter] 无法异步加载语言包: ${targetLocale}。`, e)
|
|
109
|
+
}
|
|
110
|
+
return false
|
|
111
|
+
} finally {
|
|
112
|
+
IS_LOADING = false
|
|
66
113
|
}
|
|
67
114
|
}
|
|
68
115
|
|
|
116
|
+
/**
|
|
117
|
+
* 获取当前已生效的语言代码
|
|
118
|
+
*/
|
|
119
|
+
function getCurrentLocale() {
|
|
120
|
+
return CURRENT_LOCALE
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* 手动设置翻译数据字典
|
|
125
|
+
* @param {Object} data 符合 Monaco NLS 格式的 JSON 对象
|
|
126
|
+
*/
|
|
127
|
+
function setMessages(data) {
|
|
128
|
+
proxy.setLocaleData(data)
|
|
129
|
+
CURRENT_LOCALE = 'custom'
|
|
130
|
+
}
|
|
131
|
+
|
|
69
132
|
module.exports = {
|
|
70
133
|
init: init,
|
|
71
134
|
initAsync: initAsync,
|
|
72
|
-
|
|
135
|
+
getCurrentLocale: getCurrentLocale,
|
|
136
|
+
setMessages: setMessages,
|
|
137
|
+
setLocaleData: proxy.setLocaleData, // 向后兼容
|
|
138
|
+
proxy: proxy,
|
|
139
|
+
// 插件导出 (便于在 config 文件中使用)
|
|
140
|
+
vitePlugin: require('./vite-plugin'),
|
|
141
|
+
loader: __dirname + '/loader.js'
|
|
73
142
|
}
|
package/loader.js
CHANGED
|
@@ -6,6 +6,20 @@ const { transform } = require('./transform')
|
|
|
6
6
|
module.exports = function (source) {
|
|
7
7
|
if (this.cacheable) this.cacheable()
|
|
8
8
|
|
|
9
|
+
// 获取 loader options (Webpack 5 推荐 this.getOptions)
|
|
10
|
+
const options = (typeof this.getOptions === 'function') ? this.getOptions() : this.query
|
|
11
|
+
|
|
9
12
|
// 使用共享的 transform 逻辑
|
|
10
|
-
|
|
13
|
+
const result = transform(source, this.resourcePath, options || {})
|
|
14
|
+
|
|
15
|
+
// 如果返回包含 SourceMap 的对象,则使用 this.callback 提示 Webpack
|
|
16
|
+
if (result && typeof result === 'object') {
|
|
17
|
+
if (this.callback) {
|
|
18
|
+
this.callback(null, result.code, result.map)
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
return result.code
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return result
|
|
11
25
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "monaco-editor-nls-adapter",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Multi-language NLS adapter for Monaco Editor 0.50.0+ (Self-hosted)",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"module": "index.js",
|
|
6
7
|
"types": "index.d.ts",
|
|
8
|
+
"sideEffects": false,
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./index.d.ts",
|
|
12
|
+
"import": "./index.js",
|
|
13
|
+
"require": "./index.js"
|
|
14
|
+
},
|
|
15
|
+
"./proxy": {
|
|
16
|
+
"types": "./proxy.d.ts",
|
|
17
|
+
"require": "./proxy.js"
|
|
18
|
+
},
|
|
19
|
+
"./loader": {
|
|
20
|
+
"types": "./loader.d.ts",
|
|
21
|
+
"require": "./loader.js"
|
|
22
|
+
},
|
|
23
|
+
"./vite-plugin": {
|
|
24
|
+
"types": "./vite-plugin.d.ts",
|
|
25
|
+
"require": "./vite-plugin.js"
|
|
26
|
+
},
|
|
27
|
+
"./transform": {
|
|
28
|
+
"types": "./transform.d.ts",
|
|
29
|
+
"require": "./transform.js"
|
|
30
|
+
},
|
|
31
|
+
"./locales/*": "./locales/*"
|
|
32
|
+
},
|
|
7
33
|
"files": [
|
|
8
34
|
"index.js",
|
|
9
35
|
"index.d.ts",
|
|
@@ -11,7 +37,7 @@
|
|
|
11
37
|
"proxy.js",
|
|
12
38
|
"transform.js",
|
|
13
39
|
"vite-plugin.js",
|
|
14
|
-
"locales
|
|
40
|
+
"locales/",
|
|
15
41
|
"README.md",
|
|
16
42
|
"README_zh.md"
|
|
17
43
|
],
|
|
@@ -37,5 +63,7 @@
|
|
|
37
63
|
"peerDependencies": {
|
|
38
64
|
"monaco-editor": ">= 0.50.0"
|
|
39
65
|
},
|
|
40
|
-
"dependencies": {
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"magic-string": "^0.30.0"
|
|
68
|
+
}
|
|
41
69
|
}
|
package/proxy.js
CHANGED
|
@@ -10,19 +10,18 @@ function _format(message, args) {
|
|
|
10
10
|
return message
|
|
11
11
|
}
|
|
12
12
|
return String(message).replace(/\{(\d+)\}/g, function (match, rest) {
|
|
13
|
-
const index = rest
|
|
13
|
+
const index = parseInt(rest, 10)
|
|
14
14
|
return typeof args[index] !== 'undefined' ? args[index] : match
|
|
15
15
|
})
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
function localize(path, data, defaultMessage, ...args) {
|
|
19
|
-
// 针对 Monaco 0.50.0 签名的参数修正:
|
|
20
|
-
// 1. 当通过 loader 调用时,path 是被注入的。
|
|
21
|
-
// 2. 当通过 create 调用时,path 也会被显式作为第一个参数传入。
|
|
22
19
|
const key = (data && typeof data === 'object') ? data.key : data
|
|
23
20
|
const localeData = CURRENT_LOCALE_DATA || {}
|
|
24
21
|
|
|
25
|
-
|
|
22
|
+
const fileData = localeData[path] || {}
|
|
23
|
+
let message = fileData[key]
|
|
24
|
+
|
|
26
25
|
// 强化回退逻辑:如果翻译为空或未找到,则回退到默认消息
|
|
27
26
|
if (message === undefined || message === null || message === '') {
|
|
28
27
|
message = defaultMessage
|