Haven’t on the nuggets for a long time, have been busy with new business, don’t have the time (actually they know these are just excuses, is lazy), brought a small plugin again today, used to extract all i18n language text in the project and generate all languages translation file, if it can manually modify the translation interface turns bad, Plugin will not overwrite existing translation language, perfectly compatible with old project code, hope to improve some work efficiency, leave work early, hahaha.

background

Because all the new projects need to be bilingual in Chinese and English, my former colleagues wrote the language configuration in the Chinese and English language configuration files by writing them by themselves, such as this.$t(” project “). When the new requirements came down, my hands were almost broken. So I made a plug-in to automatically generate language configuration files, so it’s nice to leave work early.

Those who want to see the code go directly to the Pikaz-Translate repository

Train of thought

$t(“”),i18n.t(“”)), and then generate JSON files. And through the translation interface will be Chinese JSON file, translated into English JSON file, not much to say, on the code.

Recurse all files in the directory and extract the text

const path = require('path')
const fs = require('fs')

// node execution path
const dirPath = process.cwd()

// Json file key
const langKey = []

/ * * *@description: folder traversal *@param {content} Content/Folder path *@return {type}* /
const fileTra = (content) = > {
    // Read the file according to the file path, return the file list
    return new Promise((resolve, reject) = > {
        fs.readdir(content, async function (err, files) {
            if (err) {
                console.warn(err)
                reject(err)
            } else {
                // Iterate over the list of files read
                for (let i = 0; i < files.length; i++) {
                    // Get the absolute path to the current file
                    const filedir = path.join(content, files[i])
                    // Obtain file information based on the file path
                    const isFile = await fileRead(filedir)
                    // If it is a folder, recursively traverse the files under that folder
                    if(! isFile) {await fileTra(filedir)
                    } else {
                        // Read the file
                        const fileContent = fs.readFileSync(filedir, 'utf-8')
                        // Extract i18N language text
                        const lang = getTranslateKey(fileContent)
                        lang.forEach((item) = > {
                            if (langKey.indexOf(item) === -1 || item === ' ') {
                                langKey.push(item)
                            }
                        })
                    }
                }
                resolve(files)
            }
        })
    })
}

/ * * *@description: matches the contents of t(") or t("") *@param {type}
 * @return {type}* /
const getTranslateKey = (source) = > {
    let result = []
    const reg = / ($| \ \.) t\((\'|\")([^\)\'\"]+)(\'|\")(,([^\)\'\"]+))? \)/gm
    let matchKey
    while ((matchKey = reg.exec(source))) {
        result.push(matchKey[3])}return result
}

/ * * *@description: Determine whether it is a file or folder *@param {String} Filedir/File path *@return {type}* /
const fileRead = (filedir) = > {
    return new Promise((resolve, reject) = > {
        fs.stat(filedir, function (err, stats) {
            if (err) {
                console.warn('Obtaining file stats failed')
                reject(err)
            } else {
                / / file
                const isFile = stats.isFile()
                / / folder
                const isDir = stats.isDirectory()
                if (isFile) {
                    resolve(true)}if (isDir) {
                    resolve(false}}})})}/ * * *@description: Translate Chinese JSON file into English JSON file *@param {String} En/Chinese language file path *@param {String} En/English language file path *@param {String} Lang/language type, default English *@return {type}* /
const pikazI18nTranslate = async (zh, en, lang = 'en') = > {const zhPath = path.join(dirPath, zh)
    let zhJson = fs.readFileSync(zhPath, 'utf-8')
    zhJson = zhJson ? JSON.parse(zhJson) : {}
    const enPath = path.join(dirPath, en)
    let enJson = fs.readFileSync(enPath, 'utf-8')
    enJson = enJson ? JSON.parse(enJson) : {}
    const key = []
    Object.keys(zhJson).forEach((k) = > {
        if (Object.keys(enJson).indexOf(k) === -1) {
            key.push(k)
        }
    })
    for (let i = 0; i < key.length; i++) {
        const e = await translate(key[i], lang)
        enJson[key[i]] = e
    }
    return new Promise((resolve, reject) = > {
        const err = fs.writeFileSync(enPath, JSON.stringify(enJson), 'utf8')
        if (err) {
            reject(err)
        }
        resolve()
    })
}
Copy the code

Translate the Chinese JSON file into English

const axios = require('axios')

/ * * *@description: Translation interface *@param {String} En/Translated text *@param {String} Lang/Translated language *@param {String} I/Number of requests, no more requests after three times *@return {type}* /
const translate = (zh, lang) = > {
    return new Promise((resolve, reject) = > {
        axios
            .get('http://fanyi.youdao.com/translate', {
                params: {
                    doctype: 'json'.type: lang,
                    i: zh,
                },
            })
            .then(async (res) => {
                resolve(res.data.translateResult[0] [0].tgt)
            })
            .catch((err) = > {
                reject(err)
            })
    })
}

/ * * *@description: Translate Chinese JSON file into English JSON file *@param {String} En/Chinese language file path *@param {String} En/English language file path *@param {String} Lang/language type, default English *@return {type}* /
const pikazI18nTranslate = async (zh, en, lang = 'en') = > {const zhPath = path.join(dirPath, zh)
    let zhJson = fs.readFileSync(zhPath, 'utf-8')
    zhJson = zhJson ? JSON.parse(zhJson) : {}
    const enPath = path.join(dirPath, en)
    let enJson = fs.readFileSync(enPath, 'utf-8')
    enJson = enJson ? JSON.parse(enJson) : {}
    const key = []
    Object.keys(zhJson).forEach((k) = > {
        if (Object.keys(enJson).indexOf(k) === -1) {
            key.push(k)
        }
    })
    for (let i = 0; i < key.length; i++) {
        const e = await translate(key[i], lang)
        enJson[key[i]] = e
    }
    return new Promise((resolve, reject) = > {
        const err = fs.writeFileSync(enPath, JSON.stringify(enJson), 'utf8')
        if (err) {
            reject(err)
        }
        resolve()
    })
}
Copy the code

complete

The main logic looks like this, and there are a few points to note:

The first: The i18N language text in the project is better used in Chinese, such as this.$t(” use Chinese “), which is better semantic, but also more convenient to view the project and generate language configuration file, if the old project is used in English, don’t worry, just call the function pikazI18nLang to extract the text, Then write the corresponding Chinese and English, of course, will be more troublesome, but the old project, can only endure…

The second: Translation interface using the public interface, for the same IP request frequency limit, if a translation is not successful, can try to perform a second, or open proxy change their IP, of course, want to pursue a better translation quality, pay for the translation of the API is better, of course, this simple change on its own can fork translation function.

Quick tips

In the vscode editor, open the user fragment

Select New global snippet file with a filename such as i18N

Write to the fragment file

{
	"Print to $t": {
		"prefix": "t"."body": [
			"$$t('$1')",]."description": "Log output to $t"}}Copy the code

$t(“) : $t(“) : $t(“) :

The effect

I18n text in the file in the target directory to be extracted

Call the plug-in function in a JS file

Execute the script file

Final effect:

Generated Chinese JSON file content

The content of the generated English JSON file

Complete project code

pikaz-translate

The plugin has been uploaded to NPM, and it’s easy to use with pikaz-Translate, complete documentation as always, and sample code.

The last

Tanabata, I wish you a happy Tanabata, single dog can only continue to coding, pleasure in pain, ha ha.