Browse Source

i18n function init done

master
filesite 1 week ago
parent
commit
2ffd6ff470
  1. 121
      i18n.mjs
  2. 33
      i18n/en-us.json
  3. 16
      test/i18n.test.mjs

121
i18n.mjs

@ -0,0 +1,121 @@ @@ -0,0 +1,121 @@
/**
* 多国语言管理
*
* node i18n.mjs init [默认语言代号]
* node i18n.mjs build [语言代号]
*/
import fs from 'node:fs';
import { readdir, readFile, writeFile } from 'node:fs/promises';
import path from 'node:path';
import common from './common.mjs';
class I18N {
//构造函数,设置默认配置
constructor(defaultLang, templateDir, langDir) {
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/';
}
//从模板文件中解析语言占位变量,并生成语言包文件
async init(lang) {
const _self = this;
try {
const files = await readdir(_self.templateDir);
let parseLangRes = null;
for (const file of files) {
parseLangRes = await _self.parseLangFromTemplate(_self.templateDir + file);
if (parseLangRes) {
console.log('Template file [%s] parse lang config done', file);
}
}
} catch (err) {
console.error('Read dir in function init failed', err);
return false;
}
return true;
}
//根据语言包文件以及模板文件,生成对应语言的html文件
build(lang) {
const _self = this;
}
//判断语言代码格式是否符合国际标准
isIosLangCode(lang) {
return /^[a-z]{2}(?:\-[a-z]{2})$/i.test(lang);
}
//更新语言包文件内容,合并新的数据到已有内容中
async updateLangFile(langFile, langJson) {
const _self = this;
let updated = false;
try {
let json = await readFile(langFile, { encoding: 'utf8'});
if (json) {
let data = JSON.parse(json);
for (const key in langJson) {
data[key] = langJson[key];
}
updated = await writeFile(langFile, JSON.stringify(data, null, 4));
}else {
updated = await writeFile(langFile, JSON.stringify(langJson, null, 4));
}
} catch (err) {
console.error('updateLangFile failed', err);
}
return updated;
}
//解析单个模板文件,并生成语言包文件
async parseLangFromTemplate(templateFilepath) {
const _self = this;
let langJson = {},
total = 0;
try {
const html_template = await readFile(templateFilepath, { encoding: 'utf8' });
const regHtmlLang = /[\s\S]*<html lang="([^"]+)">[\s\S]*/i;
let htmlLang = html_template.replace(regHtmlLang, "$1");
if (htmlLang == html_template || _self.isIosLangCode(htmlLang) == false) {
htmlLang = _self.defaultLang;
}else {
htmlLang = htmlLang.toLowerCase();
}
const regLang = /\{([^\}\r\n:;]+)\}/ig;
const matches = html_template.matchAll(regLang);
for (const match of matches) {
langJson[match[1]] = match[1];
total ++;
}
//更新语言包文件
if (total > 0) {
let langFile = _self.langDir + `${htmlLang}.json`;
const saved = await _self.updateLangFile(langFile, langJson);
if (!saved) {
return false;
}
}
} catch (err) {
console.error('parseLangFromTemplate failed', err);
return false;
}
return langJson;
}
}
export default I18N;

33
i18n/en-us.json

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
{
"HeroUnion - Open source web crawler union.": "HeroUnion - Open source web crawler union.",
"HeroUnion.website": "HeroUnion.website",
"HeroUnion<small> - Open source web crawler union</small>": "HeroUnion<small> - Open source web crawler union</small>",
"HeroUnion Stats": "HeroUnion Stats",
"It's running": "It's running",
"Tasks Stats": "Tasks Stats",
"Last": "Last",
"Waiting": "Waiting",
"Running": "Running",
"Total": "Total",
"Done": "Done",
"Failed": "Failed",
"Notify Stats": "Notify Stats",
"Bot Stats": "Bot Stats",
"Idle": "Idle",
"Busy": "Busy",
"Offline": "Offline",
"JSON Data": "JSON Data",
"Covenant of the Alliance": "Covenant of the Alliance",
"Please abide by the following conventions and stick to it for a better tomorrow for yourself and the whole society!": "Please abide by the following conventions and stick to it for a better tomorrow for yourself and the whole society!",
"Comply with local/national laws and regulations": "Comply with local/national laws and regulations",
"Data that requires login or VIP status to access will not be crawled": "Data that requires login or VIP status to access will not be crawled",
"Data that is explicitly prohibited from being collected by the target website will not be crawled": "Data that is explicitly prohibited from being collected by the target website will not be crawled",
"The commercial core data of the target website is not crawled": "The commercial core data of the target website is not crawled",
"Low concurrency, low frequency, does not affect the normal operation of the target website": "Low concurrency, low frequency, does not affect the normal operation of the target website",
"Bots": "Bots",
"HeroUnion App": "HeroUnion App",
"HeroUnion download": "HeroUnion download",
"HeroBot download": "HeroBot download",
"HeroUnion<strong> is only responsible for the scheduling of crawlers and tasks</strong>.": "HeroUnion<strong> is only responsible for the scheduling of crawlers and tasks</strong>.",
"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."
}

16
test/i18n.test.mjs

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
/**
* i18n测试用例
*/
import test from 'node:test';
import assert from 'node:assert';
import common from '../common.mjs';
import I18N from '../i18n.mjs';
test('Init test', async (t) => {
const i18n = new I18N();
const res = await i18n.init();
assert.ok(res);
});
Loading…
Cancel
Save