npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

abler-i18n

v0.1.25

Published

多语言处理工具

Downloads

17

Readme

彭彭自用包:abler-i18n

多语言处理工具

安装

npm i abler-i18n -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-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": "正在監聽:"
        }
    }
  3. Hook既有函数,实现自动翻译

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

  4. 修改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));
    }
}();