code-18n v3.0.1
code-18n
What is this?
code-18n
开箱即用的项目国际化工具。
访问https://vite-i18n.netlify.app/可以在项目中快速使用 code-18n
。
Type
目前支持转换的语言
Type | Support |
---|---|
js | - x |
jsx | - x |
ts | - x |
tsx | - x |
vue | - x |
Usage
code-18n
导出一个很简单的函数,参数是 source
和 config
,返回值是一个对象,详见 文档。
import { transformCode } from 'code-18n'
const source = 'const language = "中文"'
const { code } = transformCode(source, {
type: 'js',
})
console.log(code) // const language = $t('StringLiteral_17_21');
console.log(stack) // [ { StringLiteral_17_21: "中文" } ]
如果发生解析错误,或许是因为使用了非常规语法,比如 展开语法 [Spread syntax]
(默认支持)、修饰器 [Decorator]
,不用担心,你可以按照如下配置对代码进行适配。其它语法错误可以关注 babel,进行对应的配置。
transformCode(source, {
type: 'js',
parserOptions: {
babel: {
plugins: [['decorators', { decoratorsBeforeExport: true }]],
},
},
})
Installation
yarn add -D code-18n
npm install --save-dev code-18n
CLI
code-18n
提供了简单高效的命令行,输入 code-18n --help
查看所有支持的操作。之所以没用 code
作为唤醒关键词,是因为 vscode 提供了 code
命令行。
命令行默认会读取执行路径下的 .code-18n.js
文件。如果在命令行中指定了 type
,那么会覆盖配置文件中的 type
。
详细配置如下:
const recast = require('recast')
const option = {
// 参考 https://github.com/Linkontoask/code-i18n/blob/next/types/interface/index.d.ts#L11
}
module.exports = {
...options,
ignore: [],
prettier: (code, ast) => {
if (ast) {
return recast.print(ast, {
tabWidth: 2
}).code
}
return code
}
}
在进行下列操作之前,需要全局安装
yarn global add code-18n
npm install -g code-18n
Usage: code-18n [options]
Convert your code to help you code quickly (internationalization)
Options:
-v, --version output the version number
--debug Output more information for debugging the program (default: false)
--config <path> Specify the configuration file
-c, --code <code> Convert the specified code
-n, --name <file name> Convert the specified file
-d, --dir <directory> Convert files under the specified path
-s, --stack <file name> Specify the output location of the collected language pack (json)
-w, --write [path] Specify the write path (only used in --code and --name) or overwrite the current
file (default: false)
-t, --type <js | jsx | ts | tsx | vue> Specify the current code type, must be specified when using --code
-h, --help display help for command
有的时候,我只想看看一个简单的代码转换,我们只需要输入如下信息
code-18n -c "const message = '我爱中国'" -t js
#┌─────────┬──────┬────────────────────────────────────────────────┬──────────────────────────────────────────┐
#│ (index) │ name │ code │ stack │
#├─────────┼──────┼────────────────────────────────────────────────┼──────────────────────────────────────────┤
#│ 0 │ null │ "const message = $t ...... teral_1_16_1_22');" │ '{"StringLiteral_1_16_1_22":"我爱中国"}' │
#└─────────┴──────┴────────────────────────────────────────────────┴──────────────────────────────────────────┘
其中的信息被裁剪了,因为在 console
屏幕上没办法展示所有信息,这个时候可以添加 --write
参数,将代码输出到文件中
code-18n -c "const message = '我爱中国'" -t js --write china.js
// china.js
const message = $t('StringLiteral_1_16_1_22');
code-18n
还可以转换对应的文件,并且极其简单
code-18n -n china.js -w
转换目录下所有 js
文件,并且写入
code-18n -d . -t js -w
到这里,你会发现,还没有生成语言包。我们在命令行中添加 -s <path>
就可以了,他会把代码中所有中文信息输出到一个 json 文件中。
code-18n -d . -t js -s zh-cn.json -w
Documentation
下面使用 typescript 的形式介绍 code-18n
使用方法。其中有些文档需要参考这些地方 vue-eslint-parser、babel-parser、espree
import { ParserOptions as BabelParserOptions } from '@babel/parser'
import { Linter } from 'eslint'
interface ParserOptions {
vue?: Linter.ParserOptions
babel?: BabelParserOptions
}
interface Config {
type: 'js' | 'jsx' | 'ts' | 'tsx' | 'vue'
identifier?: string
ruleKey?: (node: t.Node) => string | number
parserOptions?: ParserOptions
}
export declare function transformCode(
code: string,
config: Config
): {
code: string
stack: Record<string, string>[]
}
现在,parserOptions
已经存在默认值,当你发生有任何语法错误的时候检查此默认值是否符合预期。比如当你发现有 optional expression
(可选链) 错误的时候,你需要配置如下信息。通常在解析 vue
文件的时候才会出现这些问题。
transformCode(source, {
parserOptions: {
vue: {
ecmaVersion: 11,
},
},
})
有的时候我们在编写 vue
代码的时候需要使用 jsx
的语法,现在你必须将 parserOptions
的 vue 属性进行更改。
transformCode(source, {
parserOptions: {
vue: {
ecmaFeatures: {
jsx: true,
},
},
},
})
我们还可以像 eslint
一样,过滤掉一些不需要转换的文件或代码行。
// code-18n-disabled
const country = '中国'
const city = '重庆'
// 上面所有中文都不会转换
const country = '中国'
// code-18n-disabled-next-line
const city = '重庆' // 这行代码不会转换
好了,说了这么多,下面就是 parserOptions
的默认值。
const DEFAULT_PARSER_OPTIONS = {
// https://github.com/eslint/espree#options
vue: {
sourceType: 'module',
ecmaVersion: 11,
ecmaFeatures: {
experimentalObjectRestSpread: true,
},
},
babel: {
sourceType: 'module',
},
}
Example
这里使用一段代码来介绍 code-18n
的项目用法。通常在写代码的过程中,需要时刻注意文本的硬编码,因为这会让产品失去不同语言的用户。市场上我发现了一些开源项目,他们通过 webpack 的能力,在 build
期间,向最终产物添加不可逆的转换代码,这很不友好,并且在发生错误的同时很难去甄别。
code-18n
是将源码中的字符串替换成可执行函数,在开发的同时即可阅读语言部分的源码,并且可以将已经发布的产品国际化处理。这都得益于日趋强大的开源社区,在这里感谢 babel
和 eslint
组织。
下面是帮助我们将项目中所有中文字符转换成 $t('xxxx')
的函数,如果发生错误将打印对应的文件路径和错误日志
const glob = require('glob')
const path = require('path')
const fs = require('fs')
const { transformCode } = require('../../code-18n/index')
const root = path.resolve(__dirname)
glob(
'test/**',
{
cwd: root,
},
(err, matches) => {
const paths = matches
.filter((matche) => ['js', 'jsx', 'ts', 'tsx', 'vue'].includes(path.extname(matche).slice(1)))
.map((item) => path.join(root, item))
const content = paths.map((p) => fs.readFileSync(p, 'utf-8'))
content
.map((item, index) => (/[\u4e00-\u9fa5]/.test(item) ? { content: item, path: paths[index] } : false))
.filter((a) => a)
.forEach((source) => {
try {
const filetype = path.extname(source.path).slice(1)
const { code } = transformCode(source.content, {
type: filetype,
parserOptions: {
vue: {
ecmaVersion: 11,
ecmaFeatures: {
jsx: true,
},
},
},
})
fs.writeFileSync(source.path, code, { encoding: 'utf-8' })
} catch (e) {
console.log(source.path, e)
}
})
}
)
Features
这里展示的是 AST
中对应的 Node,更多信息参考 estree。
- StringLiteral
- TemplateLiteral
- JSXText
- JSXAttribute
- Vue
- Literal
- VText
- VAttribute
- VLiteral
- TemplateLiteral
Tests
运行 yarn test
进行测试。
当前测试覆盖率表。
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
---|---|---|---|---|---|
All files | 100 | 90.57 | 100 | 100 | |
core | 100 | 90.57 | 100 | 100 | |
parser.ts | 100 | 100 | 100 | 100 | |
transform.ts | 100 | 91.3 | 100 | 100 | 68,107 |
vue.ts | 100 | 89.29 | 100 | 100 | 38,147,170 |
utils | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 |