0.1.23 • Published 4 months ago

abler-lang v0.1.23

Weekly downloads
-
License
ISC
Repository
-
Last release
4 months ago

彭彭自用包:abler-lang

多语言处理工具

安装

npm i abler-lang -s 

功能

  1. 生成语言资源文件

    从项目源文件中提取含有中文字符的字符串,将其翻译为英文和繁体中文,生成语言资源文件。

    使用多语言资源文件生成器 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,则将同时生成 以上模板文件和资源文件。

  2. 翻译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-lang");
    
    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": "正在監聽:"
        }
    }
  1. Hook既有函数,实现自动翻译

    可用Translator.hookMethod方法为己有对象方法安装翻译钩子,当这些函数被调用时,若存在字符串参数,则将自动进行翻译处理,如:调用Translator.hookMethod(console, "log").hookMethod(console, "error")为console.log和console.error安装翻译钩子后,之前调用这两个函数的代码不必修改,即具备翻译能力。

  2. 修改js源码使之适应多语言

    对js源代码进行多语言适应性调整,使用 JsUtil.mlAdaptFiles,参见示例 mlAdaptFiles。

    具体调整包括:

    • 模板字符串转换为普通字符串并通过t_f()调用以实现翻译后格式化,如:
    `必须指定命令行参数: ${cmdAdapt} 或 ${cmdGenLangRes}`
    转换为
    t_f("必须指定命令行参数: %s 或 %s", cmdAdapt, cmdGenLangRes)

    其中 t_f 从 abler-lang 导入,若不存在导入语句将自动添加。

    console.log函数、throw 语句内部的普通字符串添加t()调用以实现语言翻译,如:

    console.log("命令行参数:" + process.argv[1] + " " + process.argv[2]);
    转换为
    console.log(t("命令行参数:") + process.argv[1] + " " + process.argv[2]);

    其中 t 从 abler-lang 导入,mlAdaptFiles将添加必要的导入语句。

用法示例

const path = require("path");
const util = require("util");
const {LangResGenerator, JsUtil, t_f, Translator} = require("abler-lang");
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-lang",
            tModule: "abler-lang",
        },
        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));
    }
}();
0.1.23

4 months ago

0.1.22

4 months ago

0.1.20

4 months ago

0.1.21

4 months ago

0.1.18

4 months ago

0.1.19

4 months ago

0.1.16

4 months ago

0.1.17

4 months ago

0.1.10

5 months ago

0.1.11

5 months ago

0.1.12

5 months ago

0.1.13

5 months ago

0.1.14

5 months ago

0.1.15

5 months ago

0.1.8

5 months ago

0.1.7

5 months ago

0.1.9

5 months ago

0.1.4

5 months ago

0.1.6

5 months ago

0.1.5

5 months ago

0.1.3

5 months ago

0.1.2

5 months ago

0.1.1

5 months ago

0.1.0

5 months ago