1.0.10 • Published 1 year ago

hzinfo-i18n-router-loader v1.0.10

Weekly downloads
-
License
MIT
Repository
-
Last release
1 year ago

hzinfo-i18n-router-loader

一键式实现项目的国际化 语言包 处理的过程,vue2的loader


HTML

<div>你好,世界</div>

资源文件

//zh_md5
module.exports = {
  "a018615b35588a01": "你好,世界" //key是根据中文生成16的MD5
}
// zh_md5_key_route_map
// 如果 路由下有该文件的key 会自动匹配生成
module.exports = {
	"/demo/list": [
	"a018615b35588a01"
	],
	"/demo/about": [
	
	]
};

页面在中文下展示为

你好世界

在英文下展示为

Hello, world

介绍

该loader的主要目的是将国际化资源与项目代码分离维护,这样我们去查找对应文案的时候更加简单方便,如上述demo所示,我们原文件中不需要去使用 <div>{{ $t('a018615b35588a01') }}</div> 的方式去显示声明国际化,通过loader自动进行替换完成我们的国际化工作,这样对开发查找页面文案之类带来了极大的方便。本组件还支持在vue的props中以及单独的js文件中进行国际化处理。

安装

npm i hzinfo-i18n-router-loader --save-dev

yarn add hzinfo-i18n-router-loader --dev

使用

本组件分为两部分,一部分是cli,目的是为了生成资源文件,一部分是loader,目的是为了替换项目中的中文为国际化的代码,我们最好在打包测试/上线前执行以下cli命令,生成资源文件,然后拷贝一份资源文件给翻译组进行各国语言的翻译,之后将资源文件配置到vue-18n@5.x上,再进行打包即可。

cli的使用

cli可使用的所有命令

i18n generate

自动抓取中文

项目根目录执行

npx i18n generate 
对src目录下的vue/js/ts/tsx/jsx文件进行中文提取并生成国际化资源文件
### 跳过中文抓取
js文件和vue文件内被<i18n-ignore (跳过的内容) i18n-ignore>  包括的内容将不会进行抓取

使用实例
js语法
```bash
// <i18n-ignore
const str = "我的世界"
// i18n-ignore>

template内使用

<!-- <i18n-ignore -->
<div>我的世界</div>
<!-- i18n-ignore> -->

loader的使用

loader中需要对vue.config.js 的chainWebpack对象进行配置

chainWebpack: (config) => {
 config.module
      .rule('vue')
      .use('hzinfo-i18n-router-loader')
      .loader('hzinfo-i18n-router-loader')
      .options({
 
        localeFile: path.join(process.cwd(), './src/lang/zh_md5.js') 
      })
      .end()
}
config.module
      .rule('js')
      .exclude
      .add(/node_modules/)
      // .add(/main.js/)
      .end()
      .use('hzinfo-i18n-router-loader')
      .loader('hzinfo-i18n-router-loader')
      .options({
        localeFile: path.join(process.cwd(), 'src/lang/zh_md5.js')
      })
      .end()

main.js 修改子应用 这个方法

 function storeTest(props) {
   props.onGlobalStateChange &&
     props.onGlobalStateChange(
       (value, prev) => {
         console.log(`[onGlobalStateChange - ${props.name}]:`, value, prev);
         if (value.themeName) store.commit('SET_THEME_NAME', value.themeName);
         if (value.fontSize) store.commit('SET_FONT_SIZE', value.fontSize);
         if (value.colorName) store.commit('SET_COLOR_NAME', value.colorName);
         if (value.languageData){
           function setLang(obj){
             const language = getStore({name:'language'})
             console.log(language)
             const zh = i18n.getLocaleMessage(language||'zh')
             i18n.setLocaleMessage(language||'zh',{
               ...zh,
               ...obj,
             })
           }
           setLang(value.languageData)
           Vue.prototype.$forceUpdate()
         }
       },
       true,
     );
   props.setGlobalState &&
     props.setGlobalState({
       ignore: props.name,
       user: {
         name: props.name,
       },
     });
 }

jsonLang.js 与路由文件jsonAes.js 同级 修改package.json 的 script

 "build": "vue-cli-service build && node jsonAes.js && node jsonLang.js",

jsonLang.js的代码

let fs = require('fs');
const path = require('path');
const { name } = require('./package');
const file = require('./node_modules/hzinfo-i18n-router-loader/lib/const')
let CryptoJS = require("crypto-js");
const i18nPath = path.join(process.cwd(), file.config.dir+file.config.file);
const zhMd5KeyRouteMap = require(i18nPath+'_key_route_map.js')
const zhMd5 = require(i18nPath+'.js')


// 初始化一个空对象,用于存储合并后的结果
let mergedResult = {};
console.log(zhMd5KeyRouteMap)
console.log(zhMd5)
// 遍历每个文件
const hasKeys = []

Object.keys(zhMd5KeyRouteMap).forEach(filePath => {
 
  zhMd5KeyRouteMap[filePath].forEach(item=>{
    mergedResult[`${name}${filePath}.${item}`] = zhMd5[item]
    hasKeys.push(item)
  })

});
// 路由未使用的剩余key直接存到子应用上面
Object.keys(zhMd5).filter(key=>!hasKeys.includes(key)).forEach(item=>{
  mergedResult[`${name}.${item}`] = zhMd5[item]
})
console.log(mergedResult);

let key = '1234567890HZINFO1234567890ABCDEF';
let sRoutes =  JSON.stringify(mergedResult);

key = CryptoJS.enc.Utf8.parse(key)
let encryptedData = CryptoJS.AES.encrypt(sRoutes, key, {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7
})
encryptedData = encryptedData.ciphertext.toString()

fs.writeFile('./dist/cdn/common/i18n.json', encryptedData, 'utf8', function (err) {
  if (err){
    console.log(err)
  };
});

axios改动

  • axios.interceptors.request.use中加入
// i18n 的 请求头标识传入
  const language = getStore({name:'language'})
  const langs = {
    'zh':'zh_CN',
    'en':'en_US'
  }
  config.headers["Hz-Language"] = langs[language]||language||'zh_CN' ;

原有lang文件的index文件移到i18n文件夹,并且进行修改解决js文件循环引用问题

import Vue from 'vue'
import VueI18n from 'vue-i18n'
import elementEnLocale from 'element-ui/lib/locale/lang/en' // element-ui lang
import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN'// element-ui lang
import enLocale from '../lang/en'
import zhLocale from '../lang/zh'
function validatenull(val) {
    if (typeof val == 'boolean') {
        return false;
    }
    if (typeof val == 'number') {
        return false;
    }
    if (val instanceof Array) {
        if (val.length == 0) return true;
    } else if (val instanceof Object) {
        if (JSON.stringify(val) === '{}') return true;
    } else {
        if (val == 'null' || val == null || val == 'undefined' || val == undefined || val == '') return true;
        return false;
    }
    return false;
}
const getStore = (params = {}) => {
  const keyName = 'saber-'
  let {
    name,
    debug
  } = params;
  name = keyName + name
  let obj = {},
    content;
  obj = window.sessionStorage.getItem(name);
  if (validatenull(obj)) obj = window.localStorage.getItem(name);
  if (validatenull(obj)) return;
  try {
    obj = JSON.parse(obj);
  } catch{
    return obj;
  }
  if (debug) {
    return obj;
  }
  if (obj.dataType == 'string') {
    content = obj.content;
  } else if (obj.dataType == 'number') {
    content = Number(obj.content);
  } else if (obj.dataType == 'boolean') {
    content = eval(obj.content);
  } else if (obj.dataType == 'object') {
    content = obj.content;
  }
  return content;
}
Vue.use(VueI18n)
const Avue = window.AVUE;
const messages = {
  en: {
    ...enLocale,
    ...elementEnLocale,
    ...Avue.locale.en,
  },
  zh: {
    ...zhLocale,
    ...elementZhLocale,
    ...Avue.locale.zh,
  }
}

const i18n = new VueI18n({
  locale: getStore({ name: 'language' }) || 'zh',
  messages
})

export default i18n

index.html 去掉中文 loading样式稍微调整一下 去掉

 .avue-home__loading {
      height: 50px;
      width: 50px;
    }
.avue-home__main {
      height: 100px;
      user-select: none;
      width: 100%;
      flex-grow: 1;
      display: flex;
      justify-content: center;
      align-items: center;
      flex-direction: column;
    }

国际化资源配置

此处一定要注意!!!否则是个坑。

国际化的配置一定一定要在所有逻辑之前,建议采用 i18n.js 文件单独配置,然后在入口文件最先引入这个文件即可! 要确保('@/i18n')这个路径可以取到i18n对象

我是将i18n文件单独放到i18n文件夹下的

注意

  • vue的template中不要出現双引号与单引号重复包裹的字符串 例如:
   <template slot-scope="{disabled,size}" slot="templateParamForm">
          <el-input type="textarea" v-model="form.templateParam" :showWordLimit='true' maxlength="1000" :rows="5"
                    placeholder='请输入JSON格式字符串,例如 {"a":1,"b":2}' allow-auth="true"></el-input>
        </template>

这样使用 将会造成打包以及启动项目 报Syntax Error: SyntaxError: Unexpected token 错误

  • 建议字符串的连接用模板字符串方式,这样其中涉及到的一些动态参数也会自动生成 {0} {1} 这样的参数注入
  • import 与import语句之间不要加入中文
例如:
import {getDeviceInstanceList} from '@/api/analysis/new'

const dayDic = [
  {
    dictKey: 0,
    dictValue: '月底'
  },
  ...new Array(31).fill(1).map((item, index) => {
    return {
      dictKey: index + 1,
      dictValue: index + 1 + '日'
    }
  })
]
const monDic = new Array(12).fill(1).map((item, index) => {
  return {
    dictKey: index + 1,
    dictValue: index + 1 + '月'
  }
})
const hoursDic = new Array(24).fill(1).map((item, index) => {
  return {
    dictKey: index,
    dictValue: index + '时'
  }
})
import MyProject from '@/views/components/myProject'
  • npx i18n generate时请手动删除之前生成的2个多语言文件
  • 避免js文件与i18n文件夹下的index.js循环引用
1.0.10

1 year ago

1.0.9

1 year ago

1.0.8

1 year ago

1.0.7

1 year ago

1.0.6

1 year ago

1.0.5

1 year ago

1.0.4

1 year ago

1.0.3

1 year ago

1.0.2

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago