abler-i18n
v0.1.25
Published
多语言处理工具
Downloads
17
Readme
彭彭自用包:abler-i18n
多语言处理工具
安装
npm i abler-i18n -s
功能
生成语言资源文件
从项目源文件中提取含有中文字符的字符串,将其翻译为英文和繁体中文,生成语言资源文件。
使用多语言资源文件生成器 LangResGenerator,参见示例 generateLanguageResource。
【注】生成语言资源文件的过程中,可能需要翻译文本,这将访问腾讯的机器翻译(TMT),因此需要提供访问 TMT的secretId和secretKey。
生成的语言资源保存在指定的.json文件中,如:指定的资源文件名称为lang-res.json,应用系统应该创建一个lang-res.js来引用.json文件的内容,以下是lang-res.js的模板:
const fs = require('fs'); // 人工填写的 const languageTextResource = { // 语言代码暂以TMT(腾讯机器翻译)为准 _sourceLang: "zh", //源代码中的字符串语言 _targetLangs: ["en", "zh-TW", "fr"], // 需要的目标语言 _envDefaultLang: "en", //当前运行环境下系统的默认语言, 系统启动时装入配置信息之后设置 "简体中文(zh)": { "en": "English", "zh-TW": "繁体中文", "...": "(其它语言)" } }; // 自动生成的 if (fs.existsSync("./lang-res.json")) { const autoLangRes = require("./lang-res.json"); Object.assign(languageTextResource, autoLangRes); } function translate(msg, toLang) { toLang = toLang || languageTextResource?._envDefaultLang; if (msg && toLang && (toLang !== languageTextResource._sourceLang)) { const res = languageTextResource[msg]; if (res) { msg = res[toLang] || msg; } } return msg; } module.exports = {translate, res: languageTextResource};
如果指定的资源文件后缀是.js,则将同时生成 以上模板文件和资源文件。
翻译API
Translator类提供的翻译方法:
localTranslate:利用本地语言资源文件进行翻译,方法接口:
/** * 本地翻译, 调用: * localTranslate(text, fromLang, toLang) * localTranslate(text, toLang) * localTranslate(text) * @returns {string|*} 若没有翻译则返回null */ localTranslate(text, fromLang, toLang)
translateText:通过请求远程翻译服务(TMT)API进行翻译,方法接口:
/** * 请求TMT完成翻译 * @param text 待翻译文本 * @param sourceLanguage 原语言代码 * @param targetLanguage 目标语言代码 * @param result 保存返回结果的对象 * @returns {Promise<void>} */ async translateText(text, sourceLanguage, targetLanguage, result)
函数 t:翻译文本,暂时只进行本地翻译,根据语言资源中的设置( _sourceLang 和 _envDefaultLang)确定是否需要翻译,函数接口:
/** * 翻译文本 * @param text 待翻译的文本 * @returns {string} 翻译后的文本,若无需翻译或者无法翻译,则返回未翻译文本 */ function t(text)
函数t_f:翻译并格式化,函数接口:
/** * Translate and Format,格式化之前先检查是否需要翻译 * @param args 参数与util.format一致 * @returns {string} 格式化后的字符串 */ function t_f(...args)
processTranslationRequest 可供路由直接调用的翻译服务处理方法,用法:
const {Translator} = require("abler-i18n"); router.post('/util/translator', function (req, res, next) { responseOf(res, Translator.processTranslateRequest(getQueryOptions(req, res), commonUtil.parametersOK)); });
postman中请求:
{ "text": "正在监听:", "source": "zh", "target": "en,zh-TW" }
响应:
{ "success": true, "stateCode": 0, "message": "", "datetime": "2023-12-26T13:26:41.016Z", "_elapse": 0.568, "data": { "正在监听:": { "en": "Listening:", "zh-TW": "正在監聽:" } }
Hook既有函数,实现自动翻译
可用Translator.hookMethod方法为己有对象方法安装翻译钩子,当这些函数被调用时,若存在字符串参数,则将自动进行翻译处理,如:调用Translator.hookMethod(console, "log").hookMethod(console, "error")为console.log和console.error安装翻译钩子后,之前调用这两个函数的代码不必修改,即具备翻译能力。
修改js源码使之适应多语言
对js源代码进行多语言适应性调整,使用 JsUtil.mlAdaptFiles,参见示例 mlAdaptFiles。
具体调整包括:
- 将模板字符串转换为普通字符串并通过**t_f()**调用以实现翻译后格式化,如:
`必须指定命令行参数: ${cmdAdapt} 或 ${cmdGenLangRes}` 转换为 t_f("必须指定命令行参数: %s 或 %s", cmdAdapt, cmdGenLangRes)
其中 t_f 从 abler-i18n 导入,若不存在导入语句将自动添加。
将console.log函数、throw 语句内部的普通字符串添加**t()**调用以实现语言翻译,如:
console.log("命令行参数:" + process.argv[1] + " " + process.argv[2]); 转换为 console.log(t("命令行参数:") + process.argv[1] + " " + process.argv[2]);
其中 t 从 abler-i18n 导入,mlAdaptFiles将添加必要的导入语句。
用法示例
const path = require("path");
const util = require("util");
const {LangResGenerator, JsUtil, t_f, Translator} = require("abler-i18n");
const langRes = require("./config/lang-res").res;
const tmtCredentialFile = "../../local-conf/tmt-credential.json";
const regExp_zh = /[\u4e00-\u9fa5]/;
async function generateLanguageResource() {
const logFileName = path.resolve(__dirname, __filename+".log");
const transOptions = {
langRes,
credential: require(tmtCredentialFile),
region: "ap-chengdu",
logFileName
}
const resGenCfg = {
searchRules: [
{
searchDir: path.resolve(process.cwd(), "node_modules", "abler-*"),
excludedDirs: ["node_modules"]
},
{
searchDir: process.cwd(),
excludedDir: [".idea", "node_modules", "public", "mgr", "temp"],
excludedFile: ["lang-res.js", "rollup.config.js", ".eslintrc.js"]
}
],
strFilter: regExp_zh,
langResFileName: path.resolve(process.cwd(), "config", lang-res.json"),
_sourceLang: langRes._sourceLang || "zh",
_targetLangs: langRes._targetLangs || ["en", "zh-TW"],
_envDefaultLang: langRes._envDefaultLang || langRes._sourceLang || "zh",
logFileName: logFileName,
};
const generator = new LangResGenerator(transOptions, resGenCfg);
generator.logger.hookConsoleLog();
return await generator.generateLangRes();
}
async function mlAdaptFiles() {
const cfg = {
searchRules: [
{
searchDir: process.cwd(),
// pattern: "./**/*.js",
excludedDir: [".idea", "node_modules", "temp", "dist", "lang"],
excludedFile: ["lang-res.js", "rollup.config.js", ".eslintrc.js"]
}
],
adaptOption: {
genFilePrefix: path.resolve(process.cwd(), "temp") + path.sep,
// genFileSuffix: ""
t_fModule: "abler-i18n",
tModule: "abler-i18n",
},
logFileName: path.resolve(__dirname, __filename+".log"),
};
const jsUtil = new JsUtil(cfg.searchRules, regExp_zh, cfg.logFileName);
jsUtil.logger.hookConsoleLog();
return await jsUtil.mlAdaptFiles(null, cfg.adaptOption);
}
!async function main() {
langRes._envDefaultLang = "en";
const defTransOpt = {
langRes
};
Translator
.defaultTranslator(defTransOpt)
// .hookMethod(util, "format")
.hookMethod(console, "log")
.hookMethod(console, "error");
console.log(util.format("%s %s %s", process.argv[0], process.argv[1], process.argv[2]));
//console.log("命令行参数:" + process.argv[1] + " " + process.argv[2]);
console.log(t("命令行参数:") + process.argv[1] + " " + process.argv[2]);
for (let i in process.argv) {
//console.log(` 参数${i}: ${process.argv[i]}`);
console.log(t_f(" 参数%s: %s", i, process.argv[i]));
}
let cmd = process.argv[2];
const cmdAdaptAll = "mlAdaptAll";
const cmdGenLangRes = "genLangRes";
if (cmd === cmdAdaptAll) {
await mlAdaptFiles();
} else if (cmd === cmdGenLangRes) {
await generateLanguageResource();
} else {
//console.log(`必须指定命令行参数: ${cmdAdaptAll} 或 ${cmdGenLangRes}`);
console.log(t_f("必须指定命令行参数: %s 或 %s", cmdAdaptAll, cmdGenLangRes));
}
}();