Skip to content

Commit

Permalink
Feature/localization kv val (VSC-226) (VSC-246) (#41)
Browse files Browse the repository at this point in the history
* add gulp i18n validation and src missing key log
  • Loading branch information
brianignacio5 authored Feb 26, 2020
1 parent 665c61c commit 59ddb2a
Show file tree
Hide file tree
Showing 8 changed files with 427 additions and 118 deletions.
44 changes: 43 additions & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const vsce = require('vsce');
const nls = require('vscode-nls-dev');
const { readdirSync, statSync } = require('fs');
const { join } = require('path');
const glob = require("glob");

// If all VS Code languages are supported you can use nls.coreLanguages
const languages = []; // [{ folderName: 'zh-CN', id: 'zh-CN' }, { folderName: 'es', id: 'es' }];
Expand Down Expand Up @@ -51,9 +52,50 @@ function vscePackage(done) {
done();
}

const build = gulp.series(clean, addI18n);
function getPathParts(pathToUse) {
const parts = pathToUse.replace(join(__dirname, "i18n"), "").split(/(?:\\|\/)/g);
parts.splice(0, 2);
parts[parts.length - 1] = parts[parts.length - 1].replace(/(\.).*/g, "");
return parts;
}

const reduceSchemaObj = (schemaObj, parts) => {
return parts.reduce((obj, key) =>
(obj && obj[key] !== undefined) ? obj[key] : undefined, schemaObj);
}

function validateLocalizationFiles(done) {
const schema = require("./schema.i18n.json");
languages.forEach((l) => {
const langDirPath = join(__dirname, "i18n", l.folderName, "**", "*.i18n.json");
glob(langDirPath, (err, locFiles) => {
if (err) {
throw err;
}
locFiles.forEach((locFile) => {
const localeJson = require(locFile);
const parts = getPathParts(locFile);
const schemaKeys = reduceSchemaObj(schema, parts);
schemaKeys.forEach((schemaKey) => {
if (!localeJson.hasOwnProperty(schemaKey)) {
throw `${schemaKey} not defined in ${locFile}`;
}
});
Object.keys(localeJson).forEach((fileKey) => {
if (schemaKeys.indexOf(fileKey) < 0) {
console.log(`Unknown property ${fileKey} defined in ${locFile}`);
}
});
});
});
});
done();
}

const build = gulp.series(clean, addI18n, validateLocalizationFiles);
exports.clean = clean;
exports.build = build;
exports.validateLocalization = validateLocalizationFiles;
exports.publish = gulp.series(build, vscePublish);
exports.vscePkg = gulp.series(build, vscePackage);
exports.default = build;
6 changes: 5 additions & 1 deletion i18n/en/out/espIdf/menuconfig/MenuconfigPanel.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@
"menuconfig.saveValues": "Saved changes in GUI menuconfig",
"menuconfig.discardValues": "Discarded changes in GUI menuconfig",
"menuconfig.wrongIdfPath": "Wrong IDF_PATH in workspace settings. Would you like to set it?",
"menuconfig.enterIdfPath": "Enter IDF_PATH Path"
"menuconfig.enterIdfPath": "Enter IDF_PATH Path",
"menuconfig.changesNotSaved": "Changes in GUI Menuconfig have not been saved. Would you like to save them?",
"menuconfig.save": "Save",
"menuconfig.discard": "Don't save",
"menuconfig.returnGuiconfig": "Return to GUI Menuconfig"
}
4 changes: 0 additions & 4 deletions i18n/es/out/extension.i18n.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
{
"extension.defaultFoldersGeneratedMessage": "Se han creado las carpetas plantilla.",
"extension.openFolderFirst": "Abre una carpeta primero.",
"extension.notSerialPortFoundMessage": "No se ha encontrado un puerto serial",
"extension.selectSerialPortMessage":"Selecciona el puerto serial de tu dispositivo ESP-IDF",
"extension.noPortSelectedMessage": "No se ha elegido ningún puerto",
"extension.portHasBeenSelectedMessage": "Se ha actualizado el puerto a ",
"espIdf.pickAWorkspaceFolder.text": "Seleccione el folder actual",
"extension.noFolderMessage": "Ningún espacio de trabajo seleccionado",
"selectFrameworkMessage": "Seleccione una plataforma para definir ruta",
Expand Down
5 changes: 1 addition & 4 deletions i18n/zh-CN/out/extension.i18n.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
{
"extension.defaultFoldersGeneratedMessage": "已生成默认文件夹",
"extension.openFolderFirst": "请先打开文件夹",
"extension.notSerialPortFoundMessage": "找不到可用串口",
"extension.selectSerialPortMessage":"请选择可用的串口",
"extension.noPortSelectedMessage": "串口未选中",
"extension.portHasBeenSelectedMessage": "串口已选中 ",
"espIdf.pickAWorkspaceFolder.text": "请选择当前工作文件夹",
"extension.noFolderMessage": "未选择工作区",
"selectFrameworkMessage": "选择框架并设定路径",
Expand All @@ -20,6 +16,7 @@
"extension.enterIdfPathMessage": "请输入 IDF_PATH 路径",
"extension.enterIdfToolsPathMessage": "请输入 IDF_TOOLS_PATH 路径",
"extension.enterDevicePortMessage": "请输入设备端口路径",
"extension.enterDeviceTargetMessage": "输入要使用的 Espressif 设备",
"extension.enterDeviceBaudRateMessage": "请输入设备波特率",
"extension.cmdNotWebIDE": "所选命令在WebIDE中不可用",
"extension.enterOpenOcdConfigMessage": "在OpenOCD脚本目录中输入配置文件列表",
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,7 @@
"package": "vsce package --yarn -o esp-idf-extension.vsix",
"release": "vsce publish --yarn -p ${VS_MARKETPLACE_TOKEN}",
"gulp_clean": "gulp clean",
"validateLocalization": "gulp validateLocalization",
"webpack": "webpack --mode production"
},
"devDependencies": {
Expand Down
123 changes: 123 additions & 0 deletions schema.i18n.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
{
"out": {
"espIdf": {
"menuconfig": {
"MenuconfigPanel": [
"menuconfig.panelName",
"menuconfig.loadDefaultValues",
"menuconfig.discardValues",
"menuconfig.saveValues",
"menuconfig.wrongIdfPath",
"menuconfig.enterIdfPath",
"menuconfig.changesNotSaved",
"menuconfig.save",
"menuconfig.discard",
"menuconfig.returnGuiconfig"
]
},
"serial": {
"SerialPort": [
"serial.notSerialPortFoundMessage",
"serial.noPortSelectedMessage",
"serial.portHasBeenSelectedMessage",
"serial.selectSerialPortMessage"
]
},
"size": {
"idfSize": [
"idfSize.canceledError",
"idfSize.filesMsg",
"idfSize.buildFirstError",
"idfSize.overviewMsg",
"idfSize.archivesMsg",
"idfSize.commandError"
]
}
},
"extension": [
"extension.defaultFoldersGeneratedMessage",
"extension.openFolderFirst",
"espIdf.pickAWorkspaceFolder.text",
"extension.noFolderMessage",
"selectFrameworkMessage",
"extension.noOptionMessage",
"extension.noPathUpdatedMessage",
"extension.selectConfigMessage",
"extension.noParamUpdatedMessage",
"extension.defaultSdkconfigGeneratedMessage",
"extension.openFolderSdkconfigMessage",
"extension.waitProcessIsFinishedMessage",
"extension.elfNotFoundMessage",
"extension.gdbNotFoundMessage",
"extension.enterIdfPathMessage",
"extension.enterIdfToolsPathMessage",
"extension.enterDevicePortMessage",
"extension.enterDeviceTargetMessage",
"extension.enterDeviceBaudRateMessage",
"extension.enterOpenOcdConfigMessage",
"extension.enterCustomPathsMessage",
"extension.cmdNotWebIDE"
],
"idfComponentsDataProvider": [
"idfComponentDataProvider.proj_desc_not_found"
],
"idfConfiguration": [
"idfConfiguration.hasBeenUpdated"
],
"utils": [
"utils.currentFolder",
"utils.openComponentTitle"
]
},
"views": {
"menuconfig": [
"save",
"discard",
"reset"
]
},
"package": [
"espIdf.createFiles.title",
"espIdf.setPath.title",
"espIdf.setTarget.title",
"espIdf.configDevice.title",
"menuconfig.start.title",
"espIdf.setDefaultConfig.title",
"espIdf.selectPort.title",
"espIdf.buildDevice.title",
"espIdf.flashDevice.title",
"espIdf.monitorDevice.title",
"espIdf.onboarding.title",
"espIdf.examples.title",
"espIdf.buildFlashMonitor.title",
"espIdf.pickAWorkspaceFolder.title",
"espIdf.size.title",
"espIdf.apptrace.title",
"espIdf.openOCDCommand.title",
"debug.initConfig.name",
"debug.initConfig.description",
"param.adapterTargetName",
"param.openOcdConfigFilesList",
"param.projectName",
"param.baudRate",
"param.port",
"param.pythonBinPath",
"param.pythonSystemBinPath",
"param.espIdfPath",
"param.toolsPath",
"param.exportPaths",
"param.exportVars",
"param.useIDFKConfigStyle",
"param.showOnboardingOnInit",
"view.components.name",
"configuration.title",
"espIdf.apptrace.archive.refresh.title",
"espIdf.apptrace.archive.showReport.title",
"espIdf.apptrace.customize.title",
"trace.poll_period.description",
"trace.trace_size.description",
"trace.stop_tmo.description",
"trace.wait4halt.description",
"trace.skip_size.description"
]
}
38 changes: 35 additions & 3 deletions src/localizationDictionary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { Logger } from "./logger/logger";

export class LocDictionary {
private dictionary: object;
private schemaProperties: string[];
private localizationFile: string;

/**
* Representation of a language dictionary for a source file.
Expand All @@ -29,10 +31,11 @@ export class LocDictionary {
const localeConf = JSON.parse(process.env.VSCODE_NLS_CONFIG);
const locDirPath = path.join(extensionName, "i18n", localeConf.locale, type);
const subPath = this.getLocalizationFilePath(absolutePath);
const locJsonPath = path.join(locDirPath, subPath + ".i18n.json");
if (fs.existsSync(locDirPath) && fs.existsSync(locJsonPath)) {
this.localizationFile = path.join(locDirPath, subPath + ".i18n.json");
if (fs.existsSync(locDirPath) && fs.existsSync(this.localizationFile)) {
try {
this.dictionary = JSON.parse(fs.readFileSync(locJsonPath).toString());
this.dictionary = JSON.parse(fs.readFileSync(this.localizationFile).toString());
this.schemaProperties = this.getDictionaryType();
} catch (error) {
Logger.errorNotify("Failed to load localization, by default will only display in English", error);
}
Expand All @@ -43,13 +46,42 @@ export class LocDictionary {
if (this.dictionary && this.dictionary.hasOwnProperty(key)) {
return this.dictionary[key];
}
if (this.schemaProperties && this.schemaProperties.hasOwnProperty(key)) {
Logger.infoNotify(`${this.localizationFile} doesn't contain localization for ${key}`);
}
return defaultMsg;
}

public getDictionary() {
return this.dictionary;
}

public getSchemaParts(pathToUse: string): string[] {
const extensionName = __dirname.replace(path.sep + "dist", "");
const parts = pathToUse.replace(path.join(extensionName, "i18n"), "").split(/(?:\\|\/)/g);
parts.splice(0, 2);
parts[parts.length - 1] = parts[parts.length - 1].replace(/(\.).*/g, "");
return parts;
}

public getDictionaryType() {
const extensionName = __dirname.replace(path.sep + "dist", "");
const dictionarySchema = JSON.parse(fs.readFileSync(path.join(extensionName, "schema.i18n.json")).toString());
const parts = this.getSchemaParts(this.localizationFile);
const keys = this.reduceSchemaObj(dictionarySchema, parts);
if (keys) {
return keys;
} else {
const err = new Error(`Error with parsing localization schema for ${this.localizationFile}`);
Logger.errorNotify(err.message, err);
}
}

private reduceSchemaObj = (schemaObj, parts: string[]) => {
return parts.reduce((obj, key) =>
(obj && obj[key] !== undefined) ? obj[key] : undefined, schemaObj);
}

private getLocalizationFilePath(absolutePath: string) {
const parts = absolutePath.replace("src" + path.sep, "").split(/(?:\\|\/)/g);
parts[parts.length - 1] = parts[parts.length - 1].replace(/(\.).*/g, "");
Expand Down
Loading

0 comments on commit 59ddb2a

Please sign in to comment.