浏览代码

chore: do not modify i18n on push

Gerald 5 年之前
父节点
当前提交
63b4912780
共有 4 个文件被更改,包括 78 次插入75 次删除
  1. 1 1
      .github/workflows/transifex.yml
  2. 6 8
      gulpfile.js
  3. 1 0
      package.json
  4. 70 66
      scripts/i18n.js

+ 1 - 1
.github/workflows/transifex.yml

@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@v1
     - name: Update locale files
-      run: yarn && yarn i18n
+      run: yarn && yarn copyI18n
     - name: Upload to Transifex
       run: 'curl -i -L --user api:$TRANSIFEX_TOKEN -X PUT -F file=@dist/_locales/en/messages.json https://www.transifex.com/api/2/project/violentmonkey-nex/resource/messagesjson/content/'
       env:

+ 6 - 8
gulpfile.js

@@ -92,23 +92,20 @@ function copyFiles() {
 }
 
 function checkI18n() {
-  return gulp.src(paths.templates)
-  .pipe(i18n.extract({
+  return i18n.read({
     base: 'src/_locales',
     extension: '.json',
-  }));
+  });
 }
 
 function copyI18n() {
-  return gulp.src(paths.templates)
-  .pipe(plumber(logError))
-  .pipe(i18n.extract({
+  return i18n.read({
     base: 'src/_locales',
     touchedOnly: true,
     useDefaultLang: true,
     markUntouched: false,
     extension: '.json',
-  }))
+  })
   .pipe(gulp.dest(`${DIST}/_locales`));
 }
 
@@ -139,5 +136,6 @@ const pack = gulp.parallel(manifest, copyFiles, copyI18n);
 exports.clean = clean;
 exports.dev = gulp.series(gulp.parallel(pack, jsDev), watch);
 exports.build = gulp.series(clean, gulp.parallel(pack, jsProd));
-exports.i18n = gulp.parallel(updateI18n, copyI18n);
+exports.i18n = updateI18n;
 exports.check = checkI18n;
+exports.copyI18n = copyI18n;

+ 1 - 0
package.json

@@ -8,6 +8,7 @@
     "build:firefox": "cross-env TARGET=firefox yarn build",
     "analyze": "cross-env RUN_ENV=analyze npm run build",
     "i18n": "gulp i18n",
+    "copyI18n": "gulp copyI18n",
     "lint": "yarn lint:js && yarn lint:yml",
     "lint:js": "eslint --ext .js,.vue .",
     "lint:yml": "gulp check",

+ 70 - 66
scripts/i18n.js

@@ -1,14 +1,10 @@
-const fs = require('fs');
+const fs = require('fs').promises;
 const path = require('path');
-const util = require('util');
 const Vinyl = require('vinyl');
 const PluginError = require('plugin-error');
 const through = require('through2');
 const yaml = require('js-yaml');
 
-const readFile = util.promisify(fs.readFile);
-const readdir = util.promisify(fs.readdir);
-
 const transformers = {
   '.yml': data => yaml.safeLoad(data),
   '.json': data => JSON.parse(data),
@@ -20,30 +16,38 @@ class Locale {
     this.lang = lang;
     this.base = base;
     this.data = {};
+    this.desc = {};
   }
 
-  load() {
+  async load() {
     const localeDir = `${this.base}/${this.lang}`;
-    const data = {};
-    return readdir(localeDir)
-    .then(files => [this.defaultLocale].concat(files.filter(file => file !== this.defaultLocale)))
-    .then(files => files.reduce((promise, file) => promise.then(() => {
+    let files = await fs.readdir(localeDir);
+    files = [this.defaultLocale].concat(files.filter(file => file !== this.defaultLocale));
+    for (const file of files) {
       const ext = path.extname(file);
       const transformer = transformers[ext];
       if (transformer) {
-        return readFile(`${localeDir}/${file}`, 'utf8')
-        .then(res => { Object.assign(data, transformer(res)); }, err => {});
+        try {
+          const res = await fs.readFile(`${localeDir}/${file}`, 'utf8');
+          Object.assign(this.data, transformer(res));
+        } catch {
+          // ignore
+        }
       }
-    }), Promise.resolve()))
-    .then(() => Object.keys(data).reduce((desc, key) => {
-      this.data[key] = data[key].message;
-      desc[key] = desc[key] || data[key].description;
-      return desc;
-    }, {}));
+    }
+    Object.keys(this.data)
+    .forEach(key => {
+      this.desc[key] = this.desc[key] || this.data[key].description;
+    });
   }
 
-  get(key, def) {
-    return this.data[key] || def;
+  getMessage(key, def) {
+    const item = this.data[key];
+    return item && item.message || def;
+  }
+
+  get(key) {
+    return this.data[key];
   }
 
   dump(data, { extension }) {
@@ -62,67 +66,62 @@ class Locale {
 }
 
 class Locales {
-  constructor(base) {
+  constructor(options) {
+    this.options = options;
     this.defaultLang = 'en';
     this.newLocaleItem = 'NEW_LOCALE_ITEM';
-    this.base = base || '.';
+    this.base = options.base || '.';
     this.langs = [];
+    this.locales = {};
     this.data = {};
-    this.desc = {};
   }
 
-  load() {
-    return readdir(this.base)
-    .then(langs => {
-      this.langs = langs;
-      return Promise.all(langs.map(lang => {
-        const locale = this.data[lang] = new Locale(lang, this.base);
-        return locale.load();
-      }));
-    })
-    .then(data => {
-      const desc = data[this.langs.indexOf(this.defaultLang)];
-      Object.keys(desc).forEach(key => {
-        this.desc[key] = {
-          touched: false,
-          value: desc[key],
-        };
-      });
+  async load() {
+    const langs = await fs.readdir(this.base);
+    this.langs = langs;
+    await Promise.all(langs.map(async lang => {
+      const locale = new Locale(lang, this.base);
+      await locale.load();
+      this.locales[lang] = locale;
+    }));
+    const defaultData = this.locales[this.defaultLang];
+    Object.keys(defaultData.desc).forEach(key => {
+      this.data[key] = {
+        ...defaultData.data[key],
+        touched: this.options.markUntouched ? false : defaultData.get(key).touched !== false,
+      };
     });
   }
 
   getData(lang, options) {
     options = options || {};
     const data = {};
-    const langData = this.data[lang];
-    const defaultData = options.useDefaultLang && lang != this.defaultLang && this.data[this.defaultLang];
-    Object.keys(this.desc).forEach(key => {
-      if (options.touchedOnly && !this.desc[key].touched) return;
+    const langData = this.locales[lang];
+    const defaultData = options.useDefaultLang && lang != this.defaultLang && this.locales[this.defaultLang];
+    Object.keys(this.data).forEach(key => {
+      if (options.touchedOnly && !this.data[key].touched) return;
       data[key] = {
-        description: this.desc[key].value || this.newLocaleItem,
-        message: langData.get(key) || defaultData && defaultData.get(key) || '',
+        description: this.data[key].description || this.newLocaleItem,
+        message: langData.getMessage(key) || defaultData && defaultData.getMessage(key) || '',
       };
-      if (options.markUntouched && !this.desc[key].touched) data[key].touched = false;
+      if (options.markUntouched && !this.data[key].touched) data[key].touched = false;
     });
     return data;
   }
 
   dump(options) {
+    options = { ...this.options, ...options };
     return this.langs.map(lang => {
       const data = this.getData(lang, options);
-      const locale = this.data[lang];
-      const out = locale.dump(data, options);
-      return new Vinyl({
-        path: out.path,
-        contents: new Buffer(out.data),
-      });
+      const locale = this.locales[lang];
+      return locale.dump(data, options);
     });
   }
 
   touch(key) {
-    let item = this.desc[key];
-    if (!item) item = this.desc[key] = {
-      value: this.newLocaleItem,
+    let item = this.data[key];
+    if (!item) item = this.data[key] = {
+      description: this.newLocaleItem,
     };
     item.touched = true;
   }
@@ -140,10 +139,9 @@ function extract(options) {
     '.html': 'default',
     '.vue': 'default',
   };
+  const locales = new Locales(options);
 
-  const locales = new Locales(options.base);
-
-  function extract(data, types) {
+  function extractFile(data, types) {
     if (!Array.isArray(types)) types = [types];
     data = String(data);
     types.forEach(function (type) {
@@ -162,7 +160,7 @@ function extract(options) {
     if (file.isStream()) return this.emit('error', new PluginError('VM-i18n', 'Stream is not supported.'));
     const extname = path.extname(file.path);
     const type = types[extname];
-    type && extract(file.contents, type);
+    if (type) extractFile(file.contents, type);
     cb();
   }
 
@@ -172,12 +170,11 @@ function extract(options) {
       keys.forEach(key => {
         locales.touch(key);
       });
-      return locales.dump({
-        touchedOnly: options.touchedOnly,
-        useDefaultLang: options.useDefaultLang,
-        markUntouched: options.markUntouched,
-        extension: options.extension,
-      });
+      return locales.dump()
+      .map(out => new Vinyl({
+        path: out.path,
+        contents: new Buffer(out.data),
+      }));
     })
     .then(files => {
       files.forEach(file => {
@@ -191,6 +188,13 @@ function extract(options) {
   return through.obj(bufferContents, endStream);
 }
 
+function read(options) {
+  const stream = extract(options);
+  process.nextTick(() => stream.end());
+  return stream;
+}
+
 module.exports = {
   extract,
+  read,
 };