GithubHelp home page GithubHelp logo

di18n's Introduction

di18n

自动转换、基于配置的前端国际化方案。

为什么存在

在前端国际化开发中,很多社区方案给我们带来了极大便利,但是仍有2个问题没有解决:

  • 需要手工将代码中的主语言(比如中文)替换成国际化标记;
  • 语言包应该是一种配置,不必强耦合到项目代码里。

为此,我们开发了 di18n,它能自动扫描代码中的主语言,将其替换成国际化标记;同时将语言抽取成配置,可以放到服务端保存及更新。

工作原理

di18n 会先按如下步骤扫描源码:

  • 使用 Babel 解析得到 AST,遍历 AST,并对特殊的节点进行检查,抽取出需要翻译的字符串;
  • 自动为每一个字符串分配一个 key 因随机 key 可读性差,已改成使用主语言(如中文)文案为 key;
  • 自动调用 Google 翻译服务(可选),得到一个英文的字符串。

注:对于 React,上面提到的特殊节点包括: JSXText StringLiteral TemplateLiteral 等。

扫描之后,对于源代码:

  • 构造 CallExpression 表达式 intl.t('key1')
  • 替换原有节点 path.replaceWith(newNode)
  • 将新的 AST 通过 Babel 转换为代码;
  • 使用 Prettier 格式化代码;
  • 将新的代码落盘。

对于国际化资源:

  • 将 key-value 转换为 i18n 配置文件格式。

流程图

安装

$ npm i -D di18n-cli

# or

$ yarn add  -D di18n-cli

初始化

React

$ npx di18n init

注意:TypeScript 需要将配置文件 di18n.config.js 的 prettier.parser 改为 "typescript"

Vue

$ npx di18n init --vue

转换

$ npx di18n sync

License

MIT

di18n's People

Contributors

yshaojun avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

di18n's Issues

是否支持英文转中文?

我的react-native应用原始是英文的,使用

npx di18n sync

之后生成的locales/zh-CN.json和locales/en-US.json都是空文件
发现代码中如果有中文,可以生成翻译文件,英文字符串则不会生成
请问是否支持di18n sync十分支持扫描英文字符串?

运行 npx di18n init 报错

错误信息如下:

node:internal/modules/cjs/loader:988
  throw err;
  ^

Error: Cannot find module 'vue-template-compiler'
Require stack:
- /Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/src/transform/transformVue.js
- /Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/src/transform/transformZeroToDi18n.js
- /Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/src/index.js
- /Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/index.js
- /Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-cli/src/command/convert.js
- /Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-cli/src/index.js
- /Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-cli/index.js
- /Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-cli/bin/index.js
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:985:15)
    at Function.Module._load (node:internal/modules/cjs/loader:833:27)
    at Module.require (node:internal/modules/cjs/loader:1057:19)
    at require (node:internal/modules/cjs/helpers:103:18)
    at Object.<anonymous> (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/src/transform/transformVue.js:1:18)
    at Module._compile (node:internal/modules/cjs/loader:1155:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1209:10)
    at Module.load (node:internal/modules/cjs/loader:1033:32)
    at Function.Module._load (node:internal/modules/cjs/loader:868:12)
    at Module.require (node:internal/modules/cjs/loader:1057:19) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/src/transform/transformVue.js',
    '/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/src/transform/transformZeroToDi18n.js',
    '/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/src/index.js',
    '/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/index.js',
    '/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-cli/src/command/convert.js',
    '/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-cli/src/index.js',
    '/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-cli/index.js',
    '/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-cli/bin/index.js'
  ]
}

默认不是 react 吗,为啥报了个 vue 相关的错误

国际化i18nObject的前缀可以去掉吗?

你好,intl.$t('支持鼠标滚动缩放')现在翻译出来是这样的,想把他变成这样的效果:$t('支持鼠标滚动缩放'),可以直接在config里面配置吗?如果不可以,应该修改哪个地方的源码可以达到这样的效果?

di18n-react依赖问题

请问di18n-react是didi自己开发的库还是对其他国际化库进行了一层封装,我在github没有搜索到这个repo,希望能看下使用文档

国际化中复数的处理

比如 ${n}个苹果,翻译的时候需要根据n来决定是apples还是apple,这种情况有什么好的解决办法吗

ts 枚举中 用中文做key 或者 变量名为中文 sync 的时候会报错

例:

export enum UpgradeModeEnum {
  '提示更新',
  '强制更新',
}

如果有上面这种写法,在运行 npx di18n sync 时会报错且中断执行。

报错信息如下:

/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/types/lib/definitions/utils.js:112
    throw new TypeError(`Property ${key} of ${node.type} expected node to be of a type ${JSON.stringify(types)} but instead got ${JSON.stringify(val == null ? void 0 : val.type)}`);
          ^

TypeError: Property id of TSEnumMember expected node to be of a type ["Identifier","StringLiteral"] but instead got "CallExpression"
    at Object.validate (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/types/lib/definitions/utils.js:112:11)
    at validateField (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/types/lib/validators/validate.js:21:9)
    at validate (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/types/lib/validators/validate.js:15:3)
    at NodePath._replaceWith (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/path/replacement.js:132:5)
    at NodePath.replaceWith (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/path/replacement.js:118:8)
    at StringLiteral (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/src/transform/transformJs.js:261:18)
    at NodePath._call (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/path/context.js:45:20)
    at NodePath.call (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/path/context.js:35:17)
    at NodePath.visit (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/path/context.js:80:31)
    at TraversalContext.visitQueue (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/context.js:86:16)
    at TraversalContext.visitSingle (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/context.js:65:19)
    at TraversalContext.visit (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/context.js:109:19)
    at traverseNode (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/traverse-node.js:18:17)
    at NodePath.visit (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/path/context.js:86:52)
    at TraversalContext.visitQueue (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/context.js:86:16)
    at TraversalContext.visitMultiple (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/context.js:61:17)
    at TraversalContext.visit (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/context.js:107:19)
    at traverseNode (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/traverse-node.js:18:17)
    at NodePath.visit (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/path/context.js:86:52)
    at TraversalContext.visitQueue (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/context.js:86:16)
    at TraversalContext.visitSingle (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/context.js:65:19)
    at TraversalContext.visit (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/context.js:109:19)
    at traverseNode (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/traverse-node.js:18:17)
    at NodePath.visit (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/path/context.js:86:52)
    at TraversalContext.visitQueue (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/context.js:86:16)
    at TraversalContext.visitMultiple (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/context.js:61:17)
    at TraversalContext.visit (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/context.js:107:19)
    at traverseNode (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/traverse-node.js:18:17)
    at NodePath.visit (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/path/context.js:86:52)
    at TraversalContext.visitQueue (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/context.js:86:16)
    at TraversalContext.visitSingle (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/context.js:65:19)
    at TraversalContext.visit (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/context.js:109:19)
    at traverseNode (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/traverse-node.js:18:17)
    at traverse (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/node_modules/@babel/traverse/lib/index.js:49:34)
    at transformJs (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/src/transform/transformJs.js:489:3)
    at transformTs (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/src/transform/transformTs.js:23:10)
    at transformReact (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/src/transform/transformZeroToDi18n.js:22:32)
    at transformZeroToDi18n (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-core/src/transform/transformZeroToDi18n.js:98:3)
    at /Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-cli/src/command/collect.js:215:5
    at Array.forEach (<anonymous>)
    at collectChineseWords (/Users/weixiaolin/project/recipe_recording_app/node_modules/di18n-cli/src/command/collect.js:214:15)

react项目会报Cannot find module 'vue-template-compiler'

正常react项目不会在使用npm包的宿主项目中安装vue相关compiler。看了下是因为di18n-core 包的package.json 有声明对等依赖:
"peerDependencies": { "vue-template-compiler": "> ^2.5.16" }
后续/packages/di18n-core/src/transform/transformToDi18n.js 这边判断了源码类型进行转换会用到这个依赖。
现状:
安装vue-template-compiler后能正常使用。
期望:
react项目能够不安装vue-依赖也能正常跑,不会找不到包

vue3 废弃了vue-template-compiler,所以init失败了,那么请问vue3的版本怎么操作呢

npx di18n init --vue

Vue packages version mismatch:

  • [email protected] (/Users/zhoumin/fxq/prothentic-official-website/node_modules/vue/index.js)
  • [email protected] (/Users/zhoumin/fxq/prothentic-official-website/node_modules/vue-template-compiler/package.json)

This may cause things to work incorrectly. Make sure to use the same version for both.
If you are using vue-loader@>=10.0, simply update vue-template-compiler.
If you are using vue-loader@<10.0 or vueify, re-installing vue-loader/vueify should bump vue-template-compiler to the latest.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.