i18n-plan 前端多语言方案

想要给大家介绍一个 i18n 插件,写这个插件的起源也是因为项目中对 i18n 的需求,这个插件覆盖了我们项目中遇到的大部分 i18n 需求,说不定也能覆盖你的,try 一 try 不后悔

集成 ChatGPT 和 YouDao,自动翻译功能开箱即用

如果对你有用,可以给个 star 吗 i18n-plan

200x200.png

i18n-plan

中文/English

i18n-plan 是一个简单的 i18n Javascript 插件,支持基于 Node.js 和浏览器的 App,并且应该适用于所有 Javascript 框架。

i18n-plan 能做什么

  • 生成和更新本地语言资源,只需执行一个命令即可
  • 提供导出和导入功能以便高效地管理本地语言资源。可以将本地语言资源导出为 .xls 文件,也可以通过导入 .xls 文件对本地语言资源进行更新。此功能可以让团队协作管理本地语言资源
  • 目前已集成 ChatGPT 和 YouDao,自动翻译功能开箱即用。此外还提供自定义选项可以将其他翻译器集成到 i18n-plan 的流程中
  • 在业务代码中通过相应的键获取文本内容
  • 使用模板字符串,在翻译中注入动态数据

开始教程

安装

yarn add i18n-plan
或
npm -i i18n-plan

用法

创建配置文件

// 配置文件应该由 `module.exports` 导出
module.exports = {
    lans: ["en-US", "es-MX"],
    refer: "en-US",
    output: "build/locales"
}

管理本地语言资源

  • 在项目根目录创建配置文件后,就可以开始使用了
  • 你可以继续在项目中添加一些 .lan.json 文件。 .lan.jsoni18n-plan 的命名约定,表示该 json 文件是语言资源的一部分
|-- project
|   |
|   |-- build
|   |   |-- locales
|   |
|   |-- page1
|   |   |-- index.js
|   |   |-- index.css
|   |   +-- page1.lan.json // new
|   |
|   `-- page2
|       |-- index.js
|       |-- index.css
|       +-- page2.lan.json // new
  • 现在我们创建了两个 .lan.json 文件: page1.lan.jsonpage2.lan.json, 假设文件内容是:
// page1.lan.json
{
    "name": "hello, I'm the page one",
    "templateString": "now is ${date}"
}
// page2.lan.json
{
    "name": "while I'm the page two"
}
  • 现在可以在终端中执行 npx i18n-plan 命令来生成语言资源。 查看有关 import / export / translation 命令详情
  • 在搜集过程中, 程序会从根目录开始搜寻所有以 .lan.json 为后缀的文件。根据上面的配置文件, 在 build/locales 目录中,会生成两个文件: en-US.json and es-MX.json.
  • lan.json 文件的名称会作为它的集合的 key。如果两个及以上的 .lan.json 文件有着相同的名称,那么这些文件的内容会被合并。
{
    "page1": {
        "name": "hello, I'm the page one",
        "templateString": "now is ${date}"
    },
    "page2": {
        "name": "while I'm the page two"
    }
}

翻译

{
    translation: {
        auto: true,
        retryTime: 0,
        interval: 1000,
        inBatch: false,
        resolve: {}
    },
}
  • 现在你可以在 resolve 配置翻译相关的设置

ChatGPT

  • Api keyOrganization key 是必需的
  • 如果你所在的地区需要通过 VPN 才能访问 ChatGPT, 那么 proxy 配置是必需的
interface TranslationResolveChatgpt {
    translator: "chatgpt"
    rules?: string[]
    options: {
        organization: string
        apiKey: string
    }
    proxy?: tunnel.ProxyOptions
}

resolve: {
    translator: "chatgpt",
    rules: [],
    options: {
        organization: "",
        apiKey: "",
    },
    proxy: {
        host: "127.0.0.1",
        port: 10809,
    },
},

有道翻译


interface TranslationResolveYoudao {
    translator: "youdao"
    options: {
        key: string
        appkey: string
        api?: string
        vocabId?: string
    }
}
    
resolve: {
    translator: "youdao",
    options: {
        key: "",
        appkey: "",
    },
},

自定义集成

-你可以集成你需要的翻译服务到 i18n-plan 流程中,比如谷歌翻译或者 DeepL

type Translator= (props: { config: Config; from: string; to: string; content:  I18NPLAN.TranslationContent[] }) => Promise<I18NPLAN.TranslationContent[] | TranslationError>
type TranslationContent = { key: string[]; value: string; lanName: string }
type TranslationError = {
    errorCode: number
    error: any
}

resolve: {
    custom: ({ config, from, to, content }) => {
        return new Promise((resolve, reject) => {
            resolve(content.map(item => ({...item, value: "from the custom translation"})))
        })
    },
}

在 App 中使用

  • 按照以上示例,我们已经生成了语言资源包, 那么现在我们可以在业务代码使用了

setLan

  • 该函数可以用于保存语言资源。语言资源可以通过 import 来导入,如果担心包体积太大也可以通过 Ajax 请求来动态获取
  • 可以被调用多次来合并语言资源
  • 包含两个参数:
参数 描述
lanRes Json 格式的语言资源
isReset 是否重置已有资源,反正合并。默认: false
function setLan(lanRes: I18NPLAN.Lan, isRestore?: boolean): I18NPLAN.Lan

getLan

  • 此函数根据路径返回键对应的值
  • 包含两个参数:
参数 描述
key key 的路径
params 一个对象,用于填充模板字符
function  getLan(key: string | string[], params?: Record<string, I18NPLAN.BasicLanValue>): I18NPLAN.BasicLanValue | undefined

示例

import { setLan, getLan } from "i18n-plan"
console.log(
    setLan({
        page1: {
            name: "hello, I'm the page one",
            templateString: "what's the time? It's ${date}",
        },
    })
)
console.log(getLan("page1,templateString", { date: new Date().toLocaleTimeString() })) // what's the time? It's 11:28:45 AM
console.log(
    setLan({
        page2: {
            name: "while I'm the page two",
        },
    })
)
console.log(getLan("page2,name")) // while I'm the page two
console.log(setLan({}, true)) // {}

可执行命令

  • 收集和更新本地语言资源
  • 该命令将在根目录中查找 '.lan.json' 文件,并将文件中的所有条目合并以生成参考语言资源。该文件将作为更新其他语言的基础。
npx i18n-plan
  • 翻译给定的 key 对应的内容
//  如果你想要翻译 `page1` 和 `page2` 中的 `name`
{
    "page1": {
        "name": "hello, I'm the page one",
        "templateString": "what's the time? It's ${date}"
    },
    "page2": {
        "name": "while I'm the page two",
    }
}
// 期望的文件内容是:
 {
    "keys": ["page1,name", "page2,name"]
 }

npx i18n-plan translate path=<指向 .json 文件的绝对路径>
  • 导出和导入
npx i18n-plan export path=<指向 .xls 文件的绝对路径>
npx i18n-plan import path=<指向 .xls 文件的绝对路径>

配置文件

module.exports = {
    /*
        定义翻译的目标语言。此设置中列出的每一项都是输出文件的名称。
        当与翻译功能一起使用时,每一项都将作为翻译的目标语言发送给翻译服务,所以该值必须与翻译器要求的语言代码一致
    */
    lans: ["en-US", "es-MX", "zh-CN"],
    // 指定将用作生成其他语言参考的主要语言
    refer: "en-US",
    // 指定输出目录,相对于根目录的路径
    output: "locales",
    // 是否缓存历史增删项. 如果设为 true,你可以在 `_cache.json` 文件中找到增删项的 key
    generateCache: true,
    // 翻译配置
    translation: {
        /* 
            默认: false
            是否在同步语言资源后自动化翻译。如果设置为 true,则新增加项将自动放入翻译队列中
        */
        auto: true,
        /*
            默认: 0
            如果有翻译项失败,进行重试的次数
        */
         retryTime: 0,
        /*
            默认: 1000
            设置请求的时间间隔。建议避免发送过于频繁的请求
        */
         interval: 1000,
        /*
            默认: false
            是逐个翻译项目,还是一次性翻译某种语言的所有项目。只适用于 ChatGPT 和自定义翻译
        */
        inBatch: true,
        /* 
            两个翻译服务开箱即用:有道和ChatGPT,此外,还提供了一个自定义函数,可以将其他翻译服务(如谷歌或DeepL)集成到我们的流程中
        */
        resolve: {
            translator: "chatgpt",
            // 设置一个正则表达式数组,指导 ChatGPT 跳过与其匹配的特定文本,可以让 ChatGPT 排除某些单词或格式保留其原始文本
            rules: ["(<[a-zA-Z /]+>)"],
            options: {
                // organization key
                organization: "",
                // apiKey
                apiKey: "",
            },
            // 如果你所在的地区需要通过 VPN 才能访问 ChatGPT, 那么 `proxy` 配置是必需的
            proxy: {
                host: "127.0.0.1",
                port: 10809,
            },
        },
        resolve: {
            translator: "youdao",
            options: {
                api: "https://openapi.youdao.com/api",
                // key
                key: "",
                // appkey
                appkey: "",
                // 有道翻译使用自己的词典来过滤特殊单词或格式。请查看官方文档以获取详细信息
                vocabId: "",
            },
        },
        /*
            这个自定义函数允许您根据您的喜好集成其他的翻译服务
        */ 
        resolve: {
            /*
                type Translator= (props: { config: Config; from: string; to: string; content:  I18NPLAN.TranslationContent[] }) => Promise<I18NPLAN.TranslationContent[] | TranslationError>
                type TranslationContent = { key: string[]; value: string; lanName: string }
                type TranslationError = {
                    errorCode: number
                    error: any
                }
            */
            custom: ({ config, from, to, content }) => {
                return new Promise((resolve, reject) => {
                    resolve(content.map(item => ({...item, value: "来自自定义翻译器"})))
                })
            },
        }
    },
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容