Browse Source

i18n build html done

master
filesite 6 days ago
parent
commit
7166691efc
  1. 115
      i18n.mjs
  2. 8
      i18n/en-us.json
  3. 45
      public/en-us/index.html
  4. 45
      public/index.html
  5. 8
      public/template/index.html
  6. 10
      test/i18n.test.mjs

115
i18n.mjs

@ -13,10 +13,11 @@ import common from './common.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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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;

8
i18n/en-us.json

@ -29,5 +29,11 @@ @@ -29,5 +29,11 @@
"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."
"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."
}

45
public/en/index.html → public/en-us/index.html

@ -1,12 +1,12 @@ @@ -1,12 +1,12 @@
<!doctype html>
<html class="no-js" lang="en-US">
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width">
<title>HeroUnion - Open source web crawler union.</title>
<meta name="author" content="filesite.io">
<meta name="description" content="HeroUnion: Open source web crawler union.">
<meta name="author" content="HeroUnion.website">
<meta name="description" content="{HeroUnion: Open source web crawler union.}">
<style>
*,body{margin:0;padding:0}
body{padding:8px;max-width:640px;margin:0 auto}
@ -37,6 +37,11 @@ @@ -37,6 +37,11 @@
.danger{background-color:red}
.disable{background-color:gray}
.langswitcher{position:relative}
.langswitcher button{padding:2px 4px;cursor:pointer}
.dropmenu{display:none;position:absolute;right:0;top:28px;padding:5px;width:80px;background-color:#FFF;border:1px solid #EEE}
.dropmenu li{list-style:none;padding:0;margin:3px 0;text-align:center}
@media(max-width:480px) {
h1 small{display:block}
}
@ -46,12 +51,15 @@ @@ -46,12 +51,15 @@
<h1 class="text-center">HeroUnion<small> - Open source web crawler union</small></h1>
<hr class="mt-d5">
<p class="text-right mt-d5">
<a href="/" class="mx-d2">English</a>
<a href="/zh/" class="mx-d2">简体中文</a>
</p>
<div class="text-right mt-d5 langswitcher">
<button data-status="closed">English</button>
<ul class="dropmenu">
<li><a href="/">English</a></li>
<li><a href="/zh/">简体中文</a></li>
</ul>
</div>
<h3 class="mt-2">HeroUnion Stats - It's running <span class="run_time">...</span></h3>
<h3 class="mt-2">HeroUnion Stats It's running <span class="run_time">...</span></h3>
<h4 class="mt-d5">Tasks Stats (Last <span class="cache_time">...</span>)</h4>
<div class="stats taskStatus">
@ -119,7 +127,7 @@ @@ -119,7 +127,7 @@
<pre><code id="herounion_stats">...</code></pre>
<h3 class="mt-2">Covenant of the Alliance</h3>
<p class="mt-1">Please abide by the following conventions and stick to it for a better tomorrow for yourself and the whole society! </p>
<p class="mt-1">Please abide by the following conventions and stick to it for a better tomorrow for yourself and the whole society!</p>
<ul class="mt-d5">
<li>Comply with local/national laws and regulations</li>
<li>Information protected by law will not be crawled (for example: personal privacy data mobile phone number, ID number, etc.)</li>
@ -156,15 +164,30 @@ @@ -156,15 +164,30 @@
<footer class="mt-4">
<p>
<strong>Disclaimer:</strong>
<br>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.
<br>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.
</p>
<p class="mt-2 text-center">&copy;copyright <a href="https://herounion.website/" target="_blank">HeroUnion.Website</a></p>
</footer>
<script src="/js/jquery-3.7.1.min.js"></script>
<script type="text/javascript">
var toggleLangSwitcher = function(evt) {
var btn = evt.target;
if (!btn) {return false;}
var status = $(btn).attr('data-status');
if (status == 'closed') {
$('.langswitcher .dropmenu').show();
$(btn).attr('data-status', 'opened');
}else {
$('.langswitcher .dropmenu').hide();
$(btn).attr('data-status', 'closed');
}
};
$('.langswitcher button').click(toggleLangSwitcher);
var formatSeconds = function(secs) {
var str = secs + '秒';
var str = secs + ' seconds';
if (secs > 86400) {
str = Math.floor(secs/86400) + ' days';
}else if (secs > 3600) {

45
public/index.html

@ -1,12 +1,12 @@ @@ -1,12 +1,12 @@
<!doctype html>
<html class="no-js" lang="en-US">
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width">
<title>HeroUnion - Open source web crawler union.</title>
<meta name="author" content="filesite.io">
<meta name="description" content="HeroUnion: Open source web crawler union.">
<meta name="author" content="HeroUnion.website">
<meta name="description" content="{HeroUnion: Open source web crawler union.}">
<style>
*,body{margin:0;padding:0}
body{padding:8px;max-width:640px;margin:0 auto}
@ -37,6 +37,11 @@ @@ -37,6 +37,11 @@
.danger{background-color:red}
.disable{background-color:gray}
.langswitcher{position:relative}
.langswitcher button{padding:2px 4px;cursor:pointer}
.dropmenu{display:none;position:absolute;right:0;top:28px;padding:5px;width:80px;background-color:#FFF;border:1px solid #EEE}
.dropmenu li{list-style:none;padding:0;margin:3px 0;text-align:center}
@media(max-width:480px) {
h1 small{display:block}
}
@ -46,12 +51,15 @@ @@ -46,12 +51,15 @@
<h1 class="text-center">HeroUnion<small> - Open source web crawler union</small></h1>
<hr class="mt-d5">
<p class="text-right mt-d5">
<a href="/" class="mx-d2">English</a>
<a href="/zh/" class="mx-d2">简体中文</a>
</p>
<div class="text-right mt-d5 langswitcher">
<button data-status="closed">English</button>
<ul class="dropmenu">
<li><a href="/">English</a></li>
<li><a href="/zh/">简体中文</a></li>
</ul>
</div>
<h3 class="mt-2">HeroUnion Stats - It's running <span class="run_time">...</span></h3>
<h3 class="mt-2">HeroUnion Stats It's running <span class="run_time">...</span></h3>
<h4 class="mt-d5">Tasks Stats (Last <span class="cache_time">...</span>)</h4>
<div class="stats taskStatus">
@ -119,7 +127,7 @@ @@ -119,7 +127,7 @@
<pre><code id="herounion_stats">...</code></pre>
<h3 class="mt-2">Covenant of the Alliance</h3>
<p class="mt-1">Please abide by the following conventions and stick to it for a better tomorrow for yourself and the whole society! </p>
<p class="mt-1">Please abide by the following conventions and stick to it for a better tomorrow for yourself and the whole society!</p>
<ul class="mt-d5">
<li>Comply with local/national laws and regulations</li>
<li>Information protected by law will not be crawled (for example: personal privacy data mobile phone number, ID number, etc.)</li>
@ -156,15 +164,30 @@ @@ -156,15 +164,30 @@
<footer class="mt-4">
<p>
<strong>Disclaimer:</strong>
<br>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.
<br>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.
</p>
<p class="mt-2 text-center">&copy;copyright <a href="https://herounion.website/" target="_blank">HeroUnion.Website</a></p>
</footer>
<script src="/js/jquery-3.7.1.min.js"></script>
<script type="text/javascript">
var toggleLangSwitcher = function(evt) {
var btn = evt.target;
if (!btn) {return false;}
var status = $(btn).attr('data-status');
if (status == 'closed') {
$('.langswitcher .dropmenu').show();
$(btn).attr('data-status', 'opened');
}else {
$('.langswitcher .dropmenu').hide();
$(btn).attr('data-status', 'closed');
}
};
$('.langswitcher button').click(toggleLangSwitcher);
var formatSeconds = function(secs) {
var str = secs + '秒';
var str = secs + ' seconds';
if (secs > 86400) {
str = Math.floor(secs/86400) + ' days';
}else if (secs > 3600) {

8
public/template/index.html

@ -130,7 +130,7 @@ @@ -130,7 +130,7 @@
<p class="mt-1">{Please abide by the following conventions and stick to it for a better tomorrow for yourself and the whole society!}</p>
<ul class="mt-d5">
<li>{Comply with local/national laws and regulations}</li>
<li>{Information protected by law will not be crawled (for example: personal privacy data mobile phone number, ID number, etc.)}</li>
<li>{Information protected by law will not be crawled} ({for example}: {personal privacy data mobile phone number, ID number, etc.})</li>
<li>{Data that requires login or VIP status to access will not be crawled}</li>
<li>{Data that is explicitly prohibited from being collected by the target website will not be crawled}</li>
<li>{The commercial core data of the target website is not crawled}</li>
@ -143,12 +143,12 @@ @@ -143,12 +143,12 @@
<h3 class="mt-2">{HeroUnion App}</h3>
<ul class="mt-d5">
<li>
<strong>{Website monitor:}</strong>
<strong>{Website monitor}:</strong>
<a href="https://monitor.filesite.io/d/ddntdyyhv943ke/e7bd91-e7ab99-e79b91-e68ea7?orgId=1" target="_blank">FileSite.io Monitor</a>,
<a href="https://github.com/filesite-io/monit-via-herounion" target="_blank">Monitor source code download</a>
</li>
<li>
<strong>{Web Scraper:}</strong>
<strong>{Web Scraper}:</strong>
<a href="https://tajian.tv/" target="_blank">TaJian.tv - video box</a>
<a href="https://github.com/filesite-io/machete" target="_blank">Machete source code download</a>
</li>
@ -163,7 +163,7 @@ @@ -163,7 +163,7 @@
<footer class="mt-4">
<p>
<strong>{Disclaimer:}</strong>
<strong>{Disclaimer}:</strong>
<br>{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.}
</p>

10
test/i18n.test.mjs

@ -8,9 +8,19 @@ import common from '../common.mjs'; @@ -8,9 +8,19 @@ 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);
});
test('Build test', async (t) => {
const i18n = new I18N();
const res = await i18n.build();
assert.ok(res);
});

Loading…
Cancel
Save