國際化自動化腳本&eslint配置

最近搞了國際化,有點感想。
把一些想法和實現(xiàn)寫出來。

期望如果可以通過自動化的腳本做到一鍵全局翻譯,并且以后的迭代,如果寫了中文。eslint會報錯,配合husky不允許提交,這樣的話就可以讓項目更好的使用國際化。

web實現(xiàn)國際化現(xiàn)在是一個很簡單的事情,i18n的插件也很多,大多都是安裝一下,配置一下就可以很快的實現(xiàn)國際化。我們使用了vue-i18n。

其實難點不在國際化的安裝,而在國際化json文件的配置,大家需要把所有文件review一遍,把所有的中文抽出來,換成變量比如$t、{{ t() }}。在不同的文件里面還需要有不同的注意事項。比如vue template 在這個里面需要使用{{ t() }} 或者 :t() 。setup 語法里面 需要導入一些插件,并且使用它 可能是$t的方式。還有jsx、tsx 里面配置還會不一樣 比如 $bei.t()。 $bei是我們掛載的全局變量。

出于這樣的想法去思考的話,期望有一個腳本是實現(xiàn)這樣的事情。我去開發(fā)了一個nodejs的腳本,可以走三方翻譯, 找到文件里面的中文,抽出來放到一個json文件,而且做replace。我是實現(xiàn)了比較簡單的功能。我只替換template里面的中文并且都是替換為{{ t() }} ,這個對于提效來講很一般,大家都還需要在很多東西,屬性的需要替換為: setup和tsx需要格外去改。

我們?nèi)it上了找到了一個插件@ifreeovo/i18n-extract-cli
https://github.com/IFreeOvO/i18n-cli
貼個地址還是比較好用的,通過一些簡單的配置,可以實現(xiàn)全局自動化i18n。

它的實現(xiàn)邏輯也是比較有趣。它通過glob遍歷所有的文件,利用nodejs讀取文件內(nèi)容,使用babel解析為抽象語法樹。
解析非vue文件只用做字符串替換就可以。
vue文件需要注意的東西多一點,把vue 文件抽離為html css js 。 css文件直接跳過, js 依然使用babel處理。 html的使用htmlparser2 解析為html去處理這個很有趣,內(nèi)容會轉成child 屬性會轉成props。這樣可以很簡單的實現(xiàn)屬性和內(nèi)容的區(qū)分。找到中文之后,去調(diào)用三方翻譯,實現(xiàn)翻譯功能,保存到文件中。最后使用pritter實現(xiàn)格式化即可。

再說后半部分
使用@intlify/eslint-plugin-vue-i18n 去做vue的eslint校驗,
使用eslint-plugin-i18n 去做jsx和tsx的eslint校驗。
貼一個簡單的eslint配置文件

// @see: http://eslint.cn

module.exports = {
  root: true,
  env: {
    browser: true,
    node: true,
    es6: true
  },
  // 指定如何解析語法
  parser: "vue-eslint-parser",
  // 優(yōu)先級低于 parse 的語法解析配置
  parserOptions: {
    parser: "@typescript-eslint/parser",
    ecmaVersion: 2020,
    sourceType: "module",
    jsxPragma: "React",
    ecmaFeatures: {
      jsx: true
    }
  },
  // 繼承某些已有的規(guī)則
  extends: [
    "plugin:vue/vue3-recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:prettier/recommended",
    "plugin:@intlify/vue-i18n/recommended-legacy"
  ],
  plugins: ["i18n"],
  /**
   * "off" 或 0    ==>  關閉規(guī)則
   * "warn" 或 1   ==>  打開的規(guī)則作為警告(不影響代碼執(zhí)行)
   * "error" 或 2  ==>  規(guī)則作為一個錯誤(代碼不能執(zhí)行,界面報錯)
   */
  rules: {
    // eslint (http://eslint.cn/docs/rules)
    "no-var": "error", // 要求使用 let 或 const 而不是 var
    "no-multiple-empty-lines": ["error", { max: 1 }], // 不允許多個空行
    "prefer-const": "off", // 使用 let 關鍵字聲明但在初始分配后從未重新分配的變量,要求使用 const
    "no-use-before-define": "off", // 禁止在 函數(shù)/類/變量 定義之前使用它們

    // typeScript (https://typescript-eslint.io/rules)
    "@typescript-eslint/no-unused-vars": ["error", { ignoreRestSiblings: true }], // 禁止定義未使用的變量  忽略解構對象中的一些用不到的變量
    "@typescript-eslint/no-empty-function": "error", // 禁止空函數(shù)
    "@typescript-eslint/prefer-ts-expect-error": "error", // 禁止使用 @ts-ignore
    "@typescript-eslint/ban-ts-comment": "error", // 禁止 @ts-<directive> 使用注釋或要求在指令后進行描述
    "@typescript-eslint/no-inferrable-types": "off", // 可以輕松推斷的顯式類型可能會增加不必要的冗長
    "@typescript-eslint/no-namespace": "off", // 禁止使用自定義 TypeScript 模塊和命名空間
    "@typescript-eslint/no-explicit-any": "off", // 禁止使用 any 類型
    "@typescript-eslint/ban-types": "off", // 禁止使用特定類型
    "@typescript-eslint/no-var-requires": "off", // 允許使用 require() 函數(shù)導入模塊
    "@typescript-eslint/no-non-null-assertion": "off", // 不允許使用后綴運算符的非空斷言(!)

    // vue (https://eslint.vuejs.org/rules)
    "vue/script-setup-uses-vars": "error", // 防止<script setup>使用的變量<template>被標記為未使用,此規(guī)則僅在啟用該 no-unused-vars 規(guī)則時有效
    "vue/v-slot-style": "error", // 強制執(zhí)行 v-slot 指令樣式
    "vue/no-mutating-props": "error", // 不允許改變組件 prop
    "vue/custom-event-name-casing": "error", // 為自定義事件名稱強制使用特定大小寫
    "vue/html-closing-bracket-newline": "error", // 在標簽的右括號之前要求或禁止換行
    "vue/attribute-hyphenation": "error", // 對模板中的自定義組件強制執(zhí)行屬性命名樣式:my-prop="prop"
    "vue/attributes-order": "off", // vue api使用順序,強制執(zhí)行屬性順序
    "vue/no-v-html": "off", // 禁止使用 v-html
    "vue/require-default-prop": "off", // 此規(guī)則要求為每個 prop 為必填時,必須提供默認值
    "vue/multi-word-component-names": "off", // 要求組件名稱始終為 “-” 鏈接的單詞
    "vue/no-setup-props-destructure": "off", // 禁止解構 props 傳遞給 setup
    // Optional.
    "@intlify/vue-i18n/no-dynamic-keys": "error",
    "@intlify/vue-i18n/no-raw-text": [
      "error",
      {
        ignoreText: [
          "-",
          "[",
          "]",
          ",",
          "!",
          "?"
        ], // 忽略某些字符
        attributes: {
          "/.+/": [
            "content",
            "title",
            "aria-label",
            "aria-placeholder",
            "aria-roledescription",
            "aria-valuetext",
            "placeholder",
            "label",
            "value",
            "description"
          ]
        }
      }
    ],
    "@intlify/vue-i18n/no-deprecated-i18n-component": "error",
    "@intlify/vue-i18n/no-deprecated-i18n-place-attr": "error",
    "@intlify/vue-i18n/no-deprecated-i18n-places-prop": "error",
    "@intlify/vue-i18n/no-duplicate-keys-in-locale": "error",
    "@intlify/vue-i18n/no-unknown-locale": "error",
    "@intlify/vue-i18n/no-deprecated-modulo-syntax": "error",
    "@intlify/vue-i18n/no-html-messages": "error",
    "@intlify/vue-i18n/no-deprecated-v-t": "error",
    "@intlify/vue-i18n/prefer-sfc-lang-attr": "error",
    "i18n/no-chinese-character": [
      "error",
      {
        includeIdentifier: true,
        excludeModuleImports: true,
        excludeArgsForFunctions: ["$t", "t", "$bei.t"]
      }
    ]
  },
  settings: {
    "vue-i18n": {
      localeDir: "./src/languages/modules/*.{js,json,json5,yaml,yml}", // extension is glob formatting!
      messageSyntaxVersion: "^9.10.1"
    }
  }
};
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容