Skip to content

Commit 07442d0

Browse files
authored
Merge pull request #252 from xuhuanzy/i18n
i18n
2 parents 4de8d43 + 11d3b0c commit 07442d0

File tree

6 files changed

+1677
-9
lines changed

6 files changed

+1677
-9
lines changed

build/schema-i18n.js

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
4+
function buildCleanPath(currentPath, currentObj) {
5+
if (typeof currentPath !== 'string') {
6+
return '';
7+
}
8+
9+
let cleanPath = currentPath
10+
.replace(/\.properties\./g, '.')
11+
.replace(/\.oneOf\.\d+/g, '')
12+
.replace(/\.allOf\.\d+/g, '')
13+
.replace(/\.items/g, '')
14+
.replace(/\.additionalProperties/g, '')
15+
.replace(/^\.|\.$/g, '')
16+
.replace(/\.$/, '');
17+
18+
if (currentPath.includes('.oneOf.') && currentObj && Object.prototype.hasOwnProperty.call(currentObj, 'const')) {
19+
const enumValue = currentObj.const;
20+
cleanPath = cleanPath + '.' + enumValue;
21+
}
22+
23+
return cleanPath;
24+
}
25+
26+
function extractDescriptions(obj, currentPath = '', result = {}) {
27+
if (typeof obj !== 'object' || obj === null) {
28+
return result;
29+
}
30+
31+
for (const [key, value] of Object.entries(obj)) {
32+
if (key === 'description' && typeof value === 'string') {
33+
// 生成简化的路径,忽略 properties、oneOf、allOf 等中间路径
34+
const cleanPath = buildCleanPath(currentPath, obj);
35+
36+
if (cleanPath) {
37+
result[cleanPath] = {
38+
"en": value
39+
};
40+
}
41+
} else if (typeof value === 'object') {
42+
const newPath = currentPath ? `${currentPath}.${key}` : key;
43+
extractDescriptions(value, newPath, result);
44+
}
45+
}
46+
47+
return result;
48+
}
49+
50+
function mergeWithExistingTranslations(newDescriptions, existingI18n) {
51+
const merged = {};
52+
53+
for (const [key, newValue] of Object.entries(newDescriptions)) {
54+
merged[key] = { ...newValue }; // 复制新的内容
55+
56+
// 如果现有文件中存在这个key,将非"en"的所有语言key都附加过来
57+
if (existingI18n[key]) {
58+
for (const [langKey, langValue] of Object.entries(existingI18n[key])) {
59+
if (langKey !== 'en') {
60+
merged[key][langKey] = langValue;
61+
}
62+
}
63+
}
64+
}
65+
66+
return merged;
67+
}
68+
69+
function translateDescriptions(obj, i18nData, currentPath = '') {
70+
if (typeof obj !== 'object' || obj === null) {
71+
return obj;
72+
}
73+
74+
const result = Array.isArray(obj) ? [] : {};
75+
76+
for (const [key, value] of Object.entries(obj)) {
77+
if (key === 'description' && typeof value === 'string') {
78+
// 生成简化的路径来查找翻译
79+
const cleanPath = buildCleanPath(currentPath, obj);
80+
81+
// 查找中文翻译
82+
if (cleanPath && i18nData[cleanPath] && i18nData[cleanPath]['zh-CN']) {
83+
result[key] = i18nData[cleanPath]['zh-CN'];
84+
} else {
85+
result[key] = value; // 保持原文
86+
}
87+
} else if (typeof value === 'object') {
88+
const newPath = currentPath ? `${currentPath}.${key}` : key;
89+
result[key] = translateDescriptions(value, i18nData, newPath);
90+
} else {
91+
result[key] = value;
92+
}
93+
}
94+
95+
return result;
96+
}
97+
98+
function main() {
99+
try {
100+
// 读取 schema.json 文件
101+
const schemaPath = path.join(__dirname, '..', 'syntaxes', 'schema.json');
102+
const schemaContent = fs.readFileSync(schemaPath, 'utf-8');
103+
const schema = JSON.parse(schemaContent);
104+
105+
// 只处理 definitions 部分
106+
const definitions = schema.$defs || {};
107+
108+
// 提取所有 description
109+
const descriptions = extractDescriptions(definitions);
110+
111+
// 排序结果
112+
const sortedDescriptions = {};
113+
Object.keys(descriptions).sort().forEach(key => {
114+
sortedDescriptions[key] = descriptions[key];
115+
});
116+
117+
// 读取现有的 schema.i18n.json 文件
118+
const i18nPath = path.join(__dirname, '..', 'syntaxes', 'schema.i18n.json');
119+
let existingI18n = {};
120+
121+
if (fs.existsSync(i18nPath)) {
122+
try {
123+
const existingContent = fs.readFileSync(i18nPath, 'utf-8');
124+
existingI18n = JSON.parse(existingContent);
125+
console.log('已读取现有的 schema.i18n.json 文件');
126+
} catch (error) {
127+
console.log('读取现有 schema.i18n.json 文件失败,将创建新文件');
128+
}
129+
} else {
130+
console.log('未找到现有的 schema.i18n.json 文件,将创建新文件');
131+
}
132+
133+
// 合并翻译内容
134+
const finalDescriptions = mergeWithExistingTranslations(sortedDescriptions, existingI18n);
135+
136+
// 更新 schema.i18n.json 文件
137+
fs.writeFileSync(i18nPath, JSON.stringify(finalDescriptions, null, 2));
138+
console.log(`已更新 schema.i18n.json 文件`);
139+
140+
// 生成中文版的 schema.zh-cn.json(只处理 definitions 部分)
141+
const translatedDefinitions = translateDescriptions(schema.$defs, finalDescriptions);
142+
const translatedSchema = {
143+
...schema,
144+
$defs: translatedDefinitions
145+
};
146+
147+
const zhCnPath = path.join(__dirname, '..', 'syntaxes', 'schema.zh-cn.json');
148+
fs.writeFileSync(zhCnPath, JSON.stringify(translatedSchema, null, 2));
149+
console.log(`已生成中文版 schema.zh-cn.json 文件`);
150+
151+
console.log('\n✅ 处理完成!');
152+
} catch (error) {
153+
console.error('错误:', error.message);
154+
}
155+
}
156+
157+
main();

package.json

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,16 @@
106106
"language": "lua"
107107
}
108108
],
109+
"jsonValidation": [
110+
{
111+
"fileMatch": ".emmyrc.json",
112+
"url": "emmyrc-schema://schemas/emmyrc"
113+
},
114+
{
115+
"fileMatch": ".emmyrc.json",
116+
"url": "./syntaxes/schema.json"
117+
}
118+
],
109119
"debuggers": [
110120
{
111121
"type": "emmylua_attach",
@@ -1059,12 +1069,6 @@
10591069
"editor.wordBasedSuggestions": "off"
10601070
}
10611071
},
1062-
"jsonValidation": [
1063-
{
1064-
"fileMatch": ".emmyrc.json",
1065-
"url": "./syntaxes/schema.json"
1066-
}
1067-
],
10681072
"colors": [],
10691073
"semanticTokenScopes": [
10701074
{
@@ -1213,4 +1217,4 @@
12131217
"vscode-languageclient": "9.0.1",
12141218
"concat-map": "0.0.2"
12151219
}
1216-
}
1220+
}

src/emmyrcSchemaContentProvider.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import * as vscode from 'vscode';
2+
import * as path from 'path';
3+
import * as fs from 'fs';
4+
5+
/**
6+
* 提供`.emmyrc.json`的 i18n
7+
*/
8+
export class EmmyrcSchemaContentProvider implements vscode.TextDocumentContentProvider {
9+
private readonly schemaBaseDir: string;
10+
11+
constructor(context: vscode.ExtensionContext) {
12+
this.schemaBaseDir = path.join(context.extensionPath, 'syntaxes');
13+
}
14+
15+
async provideTextDocumentContent(uri: vscode.Uri): Promise<string> {
16+
const schemaIdentifier = path.posix.basename(uri.path);
17+
const locale = vscode.env.language;
18+
let schemaFileName: string;
19+
20+
if (schemaIdentifier === 'emmyrc') {
21+
switch (locale) {
22+
case 'zh-cn':
23+
case 'zh-CN':
24+
case 'zh':
25+
schemaFileName = 'schema.zh-cn.json';
26+
break;
27+
case 'en':
28+
case 'en-US':
29+
case 'en-GB':
30+
default:
31+
schemaFileName = 'schema.json';
32+
break;
33+
}
34+
} else {
35+
return '';
36+
}
37+
38+
// 检查schema文件是否存在, 如果不存在则使用默认的
39+
let schemaFilePath = path.join(this.schemaBaseDir, schemaFileName);
40+
if (!fs.existsSync(schemaFilePath)) {
41+
schemaFilePath = path.join(this.schemaBaseDir, 'schema.json');
42+
}
43+
44+
try {
45+
return await fs.promises.readFile(schemaFilePath, 'utf8');
46+
} catch (error: any) {
47+
return JSON.stringify({
48+
"$schema": "https://json-schema.org/draft/2020-12/schema#",
49+
"title": "Error Loading Schema",
50+
"description": `Could not load schema: ${schemaFileName}. Error: ${error.message}.`
51+
});
52+
}
53+
}
54+
}

src/extension.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { get } from './configRenames';
1818
import * as Annotator from './annotator';
1919
import { LuaRocksManager } from './luarocks/LuaRocksManager';
2020
import { LuaRocksTreeProvider, PackageTreeItem } from './luarocks/LuaRocksTreeProvider';
21+
import { EmmyrcSchemaContentProvider } from './emmyrcSchemaContentProvider';
2122
interface DebuggerConfig {
2223
readonly type: string;
2324
readonly provider: vscode.DebugConfigurationProvider;
@@ -32,6 +33,11 @@ let luaRocksTreeProvider: LuaRocksTreeProvider | undefined;
3233
export async function activate(context: vscode.ExtensionContext) {
3334
console.log('EmmyLua extension activated!');
3435

36+
// 提供`.emmyrc.json`的 i18n
37+
context.subscriptions.push(
38+
vscode.workspace.registerTextDocumentContentProvider('emmyrc-schema', new EmmyrcSchemaContentProvider(context))
39+
);
40+
3541
extensionContext = new EmmyContext(
3642
process.env['EMMY_DEV'] === 'true',
3743
context
@@ -433,7 +439,7 @@ async function showPackageInfo(item: PackageTreeItem): Promise<void> {
433439
const quickPick = vscode.window.createQuickPick();
434440
quickPick.title = `Package: ${packageInfo.name}`;
435441
quickPick.placeholder = 'Package Information';
436-
442+
437443
const items: vscode.QuickPickItem[] = [
438444
{
439445
label: `$(package) ${packageInfo.name}`,
@@ -553,4 +559,4 @@ async function checkLuaRocksInstallation(): Promise<void> {
553559
vscode.env.openExternal(vscode.Uri.parse('https://luarocks.org/#quick-start'));
554560
}
555561
}
556-
}
562+
}

0 commit comments

Comments
 (0)