Tools used
quicktype
Step1: Automatically generates the corresponding interface based on the JSON file
For example, here is a JSON file (string.json) :
/ / string. Json {" strings ": {" login" : {" zh_CN ":" login ", "en_US" : "login in"}, "login_out" : {" zh_CN ":" exit ", "en_US" : "Login out" }, } }Copy the code
We want it to automatically generate the following interface and store it in the strings.interface. Ts file:
Export interface StringsInterface {strings: {login: String, login_out: String}; } export interface String { zh_CN? : string; en_US? : string; }Copy the code
You can run the following commands on the terminal:
quicktype ./strings.json -o ./strings.interface.ts
Copy the code
The generated interface looks like this:
export interface StringsInterface { strings: { [key: string]: String }; } export interface String { zh_CN? : string; en_US? : string; }Copy the code
We need to fix strings.interface. Ts.
Step1: new 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(' invalid 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);Copy the code
Step2: run the following command on the terminal:
quicktype ./strings.auto.json -o ./i18n/strings.interface.ts --just-types && node ./fix_strings_interface.js
Copy the code
Step2: Write the method – identify the complex number, and modify the conversion string
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; }Copy the code
Step3: write a multi-language configuration call method
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; Export function getLanguage() {... } /** * multilanguage fetch, * @param options JavaScript Object, support string format, Support lodash _. Tempalte * @example t(strings. early_bird) or 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; }Copy the code