前端实战-根据JSON文件自动生成对应的interface

2,174 阅读1分钟

用到的工具

quicktype

step1:根据JSON文件自动生成对应的interface

比如下面有个json文件(string.json):

// string.json
{
    "strings":{
        "login": {
            "zh_CN": "登录",
            "en_US": "Login in"
        },
        "login_out": {
            "zh_CN": "退出",
            "en_US": "Login out"
        },
    }
}

想让它自动生成以下的interface,并将其自动保存在strings.interface.ts文件里:

export interface StringsInterface {
    strings: { 
        login: Stringlogin_out: String
    };
}

export interface String {
    zh_CN?:       string;
    en_US?:       string;
}

可以在终端执行命令:

quicktype ./strings.json -o ./strings.interface.ts

此时会发现生成的interface是这样的:

export interface StringsInterface {
    strings: { [key: string]: String };
}

export interface String {
    zh_CN?:       string;
    en_US?:       string;
}

需要修正一下strings.interface.ts,解决方法:

step1: 新建fix_strings_interface.js

const fs = require("fs");

const stringInterfacePath = "/strings.interface.ts";
const stringJSONPath = "/strings.auto.json";

const jsonStr = fs.readFileSync(stringJSONPath);
const stringsObj = JSON.parse(jsonStr);
const tmpStart = `
export interface StringsInterface {
  strings: {
`;
const tmpEnd = `
  };
}
`;

const testRegx = /^\w+$/i;
const tmpBody = Object.keys(stringsObj.strings)
  .filter((item) => {
    if (testRegx.test(item)) {
      return true;
    } else {
      console.warn(`不合法的 key:${item}`);
      return false;
    }
  })
  .map((item) => `    ${item}: String;`)
  .join("\n");
const tmp = tmpStart + tmpBody + tmpEnd;
const splitText = `export interface String {`;
const interfaceStr = fs.readFileSync(stringInterfacePath).toString();
const [_, rest] = interfaceStr.split(splitText);
const newInterfaceStr = [tmp, splitText, rest].join("\n");

fs.writeFileSync(stringInterfacePath, newInterfaceStr);

step2:在终端执行命令:

quicktype ./strings.auto.json -o ./i18n/strings.interface.ts --just-types && node ./fix_strings_interface.js

step2:编写方法——识别复数,并修改转化字符串

export function plural(str: string, revert: boolean) {

    const plural = {
      '(quiz)$'               : '$1zes',
      '^(ox)$'                : '$1en',
      '([m|l])ouse$'          : '$1ice',
      '(matr|vert|ind)ix|ex$' : '$1ices',
      '(x|ch|ss|sh)$'         : '$1es',
      '([^aeiouy]|qu)y$'      : '$1ies',
      '(hive)$'               : '$1s',
      '(?:([^f])fe|([lr])f)$' : '$1$2ves',
      '(shea|lea|loa|thie)f$' : '$1ves',
      sis$                  : 'ses',
      '([ti])um$'             : '$1a',
      '(tomat|potat|ech|her|vet)o$': '$1oes',
      '(bu)s$'                : '$1ses',
      '(alias)$'              : '$1es',
      '(octop)us$'            : '$1i',
      '(ax|test)is$'          : '$1es',
      '(us)$'                 : '$1es',
      '([^s]+)$'              : '$1s',
    };
  
    const singular = {
      '(quiz)zes$'             : '$1',
      '(matr)ices$'            : '$1ix',
      '(vert|ind)ices$'        : '$1ex',
      '^(ox)en$'               : '$1',
      '(alias)es$'             : '$1',
      '(octop|vir)i$'          : '$1us',
      '(cris|ax|test)es$'      : '$1is',
      '(shoe)s$'               : '$1',
      '(o)es$'                 : '$1',
      '(bus)es$'               : '$1',
      '([m|l])ice$'            : '$1ouse',
      '(x|ch|ss|sh)es$'        : '$1',
      '(m)ovies$'              : '$1ovie',
      '(s)eries$'              : '$1eries',
      '([^aeiouy]|qu)ies$'     : '$1y',
      '([lr])ves$'             : '$1f',
      '(tive)s$'               : '$1',
      '(hive)s$'               : '$1',
      '(li|wi|kni)ves$'        : '$1fe',
      '(shea|loa|lea|thie)ves$': '$1f',
      '(^analy)ses$'           : '$1sis',
      '((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$': '$1$2sis',
      '([ti])a$'               : '$1um',
      '(n)ews$'                : '$1ews',
      '(h|bl)ouses$'           : '$1ouse',
      '(corpse)s$'             : '$1',
      '(us)es$'                : '$1',
      s$                     : '',
    };
  
    const irregular = {
      move   : 'moves',
      foot   : 'feet',
      goose  : 'geese',
      sex    : 'sexes',
      child  : 'children',
      man    : 'men',
      tooth  : 'teeth',
      person : 'people',
    };
  
    const uncountable = [
      'sheep',
      'fish',
      'deer',
      'moose',
      'series',
      'species',
      'money',
      'rice',
      'information',
      'equipment',
    ];
  
    // save some time in the case that singular and plural are the same
    if (uncountable.indexOf(str.toLowerCase()) >= 0) {
      return str;
    }
  
    // check for irregular forms
    for (const word in irregular) {
  
      let pattern;
      let replace;
      if (revert) {
        pattern = new RegExp(irregular[word] + '$', 'i');
        replace = word;
      } else {pattern = new RegExp(word + '$', 'i');
        replace = irregular[word];
      }
      if (pattern.test(str)) {
        return str.replace(pattern, replace);
      }
    }
  
    let array;
    if (revert) {
      array = singular;
    } else {
      array = plural;
    }
  
    // check for matches using regular expressions
    for (const reg in array) {
  
      const pattern = new RegExp(reg, 'i');
  
      if (pattern.test(str)) {
        return str.replace(pattern, array[reg]);
      }
    }
  
    return str;
  }

step3:编写多语言配置调用方法

import { StringsInterface, String as StringInterface } from './strings.interface';
import { template } from 'lodash';
import stringsConfigJson from '../config/strings.auto.json';
import { plural } from './plural';
export type { String as StringInterface } from './strings.interface';

export const ERROR_STR = '[ERROR STR]';
export const StringsConfig: StringsInterface = stringsConfigJson as any as StringsInterface;

export const Strings = StringsConfig.strings; // 字符串的key集合传出去
export function getLanguage() {
  ...
}

/**
 * 多语言获取,传入对象或key
 * @param StringObject 对应strings.json文件的字符串对象
 * @param options JavaScript Object,  支持字符串格式化(string format),支持lodash _.tempalte
 * @example t(Strings.early_bird) 或 t('early_bird')
 */
function getText(stringObj: StringInterface | string, options: any = null, isPlural: boolean = false): string {
  if(!stringObj){
    console.error('Cannot find this string key');
    return ERROR_STR;
  }
  const lang = getLanguage(); // default Language

  let obj: StringInterface;
  if (typeof stringObj === 'string' || stringObj instanceof String) {
      const key: string = stringObj as string;
    obj = StringsConfig[key];
    if (obj === undefined) {
      return key;
    }
  }

  obj = stringObj as StringInterface;
  const text = lang in obj ? obj[lang] : obj['zh_CN'] || ERROR_STR;
  const str = options ? template(text)(options) : text;
  if (isPlural) {
    return plural(str, false);
  }
  return str;
}