diff --git a/i18n.mjs b/i18n.mjs index e34ea37..5f73e3c 100644 --- a/i18n.mjs +++ b/i18n.mjs @@ -13,10 +13,11 @@ import common from './common.mjs'; class I18N { //构造函数,设置默认配置 - constructor(defaultLang, templateDir, langDir) { + constructor(defaultLang, templateDir, langDir, buildDir) { this.defaultLang = typeof(defaultLang) != 'undefined' && defaultLang ? defaultLang : 'en'; this.templateDir = typeof(templateDir) != 'undefined' && templateDir ? templateDir : './public/template/'; this.langDir = typeof(langDir) != 'undefined' && langDir ? langDir : './i18n/'; + this.buildDir = typeof(buildDir) != 'undefined' && buildDir ? buildDir : './public/'; } //从模板文件中解析语言占位变量,并生成语言包文件 @@ -41,10 +42,39 @@ class I18N { } //根据语言包文件以及模板文件,生成对应语言的html文件 - build(lang) { + async build(lang) { const _self = this; - + const langFiles = await _self.getLangFiles(); + //console.log('Lang json files', langFiles); + + if (langFiles && langFiles.length > 0) { + try { + let langData = null; + let newHtml = '', saved = false; + for (const langFile of langFiles) { + const langJson = await readFile(_self.langDir + langFile, { encoding: 'utf8' }); + if (!langJson) { + continue; + } + langData = JSON.parse(langJson); + + const files = await readdir(_self.templateDir); + for (const file of files) { + newHtml = await _self.replaceLangToTemplate(_self.templateDir + file, langData); + if (newHtml) { + saved = await _self.saveBuildHtml(langFile.replace('.json', ''), file, newHtml); + console.log('Template file [%s] lang data replace with [%s] done, html build [%s].', file, langFile, (saved ? 'success' : 'failed')); + } + } + } + } catch (err) { + console.error('Read dir in function build failed', err); + return false; + } + } + + return true; } //判断语言代码格式是否符合国际标准 @@ -52,6 +82,11 @@ class I18N { return /^[a-z]{2}(?:\-[a-z]{2})$/i.test(lang); } + //判断是否是语言包文件 + isIosLangFile(filename) { + return /^[a-z]{2}(?:\-[a-z]{2})\.json$/i.test(filename); + } + //更新语言包文件内容,合并新的数据到已有内容中 async updateLangFile(langFile, langJson) { const _self = this; @@ -65,10 +100,12 @@ class I18N { data[key] = langJson[key]; } - updated = await writeFile(langFile, JSON.stringify(data, null, 4)); + await writeFile(langFile, JSON.stringify(data, null, 4)); }else { - updated = await writeFile(langFile, JSON.stringify(langJson, null, 4)); + await writeFile(langFile, JSON.stringify(langJson, null, 4)); } + + updated = true; } catch (err) { console.error('updateLangFile failed', err); } @@ -93,6 +130,7 @@ class I18N { htmlLang = htmlLang.toLowerCase(); } + //模版语法不能包含:换行符、英文冒号、英文分号 const regLang = /\{([^\}\r\n:;]+)\}/ig; const matches = html_template.matchAll(regLang); for (const match of matches) { @@ -116,6 +154,73 @@ class I18N { return langJson; } + //获取所有语言包json文件 + async getLangFiles(lang) { + const _self = this; + + let langFiles = []; + + try { + const files = await readdir(_self.langDir); + let parseLangRes = null; + for (const file of files) { + if (_self.isIosLangFile(file)) { + if (typeof(lang) == 'undefined') { + langFiles.push(file); + }else if (file.indexOf(lang) > -1) { + langFiles.push(file); + } + } + } + } catch (err) { + console.error('Read dir in function getLangFiles failed', err); + return false; + } + + return langFiles; + } + + //根据语言包替换单个模板文件,返回新的html代码 + async replaceLangToTemplate(templateFilepath, langData) { + const _self = this; + + let html = ''; + try { + const html_template = await readFile(templateFilepath, { encoding: 'utf8' }); + + html = html_template; + for (let key in langData) { + html = html.replaceAll(`{${key}}`, langData[key]); + } + } catch (err) { + console.error('replaceLangToTemplate failed', err); + return false; + } + + return html; + } + + //保存替换了语言包的html文件 + async saveBuildHtml(lang, htmlFilename, htmlContent) { + const _self = this; + let saved = false; + + try { + let langDir = _self.buildDir + lang; + if (!fs.existsSync(langDir)) { + fs.mkdirSync(langDir); + } + + let htmlFile = `${langDir}/${htmlFilename}`; + await writeFile(htmlFile, htmlContent); + saved = true; + } catch (err) { + console.error('saveBuildHtml failed', err); + } + + return saved; + } + } export default I18N; \ No newline at end of file diff --git a/i18n/en-us.json b/i18n/en-us.json index 243e4b4..07ff677 100644 --- a/i18n/en-us.json +++ b/i18n/en-us.json @@ -29,5 +29,11 @@ "HeroUnion download": "HeroUnion download", "HeroBot download": "HeroBot download", "HeroUnion is only responsible for the scheduling of crawlers and tasks.": "HeroUnion is only responsible for the scheduling of crawlers and tasks.", - "The contracts supported by crawlers and the specific content of tasks have nothing to do with the alliance.": "The contracts supported by crawlers and the specific content of tasks have nothing to do with the alliance." + "The contracts supported by crawlers and the specific content of tasks have nothing to do with the alliance.": "The contracts supported by crawlers and the specific content of tasks have nothing to do with the alliance.", + "Website monitor": "Website monitor", + "Web Scraper": "Web Scraper", + "Disclaimer": "Disclaimer", + "Information protected by law will not be crawled": "Information protected by law will not be crawled", + "for example": "for example", + "personal privacy data mobile phone number, ID number, etc.": "personal privacy data mobile phone number, ID number, etc." } \ No newline at end of file diff --git a/public/en/index.html b/public/en-us/index.html similarity index 85% rename from public/en/index.html rename to public/en-us/index.html index bb69e30..c3692e7 100644 --- a/public/en/index.html +++ b/public/en-us/index.html @@ -1,12 +1,12 @@ - +