Update the build system to automatically update languages.json

The `languages.json` file is regenerated whenever the web interface is
started or built. This PR also updates the language list with the
languages added by #145.

See #148

Signed-off-by: Mcat12 <newtoncat12@yahoo.com>
This commit is contained in:
Mcat12
2019-02-15 19:12:45 -08:00
parent 4eb60085f5
commit e5c820ced0
3 changed files with 3 additions and 173 deletions

View File

@@ -67,14 +67,13 @@
},
"scripts": {
"start": "npm run build-css && npm-run-all -p watch-css start-js",
"start-js": "react-scripts start",
"start-js": "npm run generate-language-list && react-scripts start",
"start-fake": "npm run make-fake-data && REACT_APP_FAKE_API=1 npm run start",
"build": "npm-run-all build-css build-js",
"build-fake": "npm run make-fake-data && REACT_APP_FAKE_API=1 npm run build",
"build-js": "react-scripts build",
"build-js": "npm run generate-language-list && react-scripts build",
"build-css": "node-sass-chokidar --include-path ./node_modules ./src/scss -o ./src/scss",
"watch-css": "node-sass-chokidar --include-path ./node_modules ./src/scss -o ./src/scss --watch --recursive",
"update-translations": "node scripts/update-translations.js && npm run generate-language-list",
"generate-language-list": "node scripts/generate-language-list.js",
"make-fake-data": "node scripts/make-fake-data.js",
"test": "react-scripts test --env=jsdom",

View File

@@ -1,169 +0,0 @@
/* Pi-hole: A black hole for Internet advertisements
* (c) 2019 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* Web Interface
* Update translations from POEditor
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
const fs = require("fs-extra");
const fetch = require("node-fetch");
const MultiProgress = require("multi-progress");
const PROJECT_ID = 66305;
const I18N_FOLDER = "public/i18n";
const multi = new MultiProgress(process.stderr);
const apiToken = process.env.POEDITOR_API_TOKEN;
if (!apiToken) {
console.log("Please set the POEDITOR_API_TOKEN environment variable");
process.exit(1);
}
/**
* Convert a key-value map into a format for application/x-www-form-urlencoded
*
* @param data the key-value map
* @returns {string} the encoded data
*/
function makeFormData(data) {
return Object.keys(data)
.map(key => `${key}=${data[key]}`)
.join("&");
}
/**
* Return a list of languages which are at least 90% translated
*/
function getTranslatedLanguages() {
return fetch("https://api.poeditor.com/v2/languages/list", {
method: "POST",
body: makeFormData({
api_token: apiToken,
id: PROJECT_ID
}),
headers: { "Content-Type": "application/x-www-form-urlencoded" }
})
.then(response => response.json())
.then(data => {
return data.result.languages
.filter(lang => lang.percentage >= 70)
.map(lang => lang.code);
});
}
/**
* Fetch a list of tagged strings from a language
*
* @param lang the language code
* @param tag the tag
* @param bar the progress bar
*/
function fetchTag(lang, tag, bar) {
fetch("https://api.poeditor.com/v2/projects/export", {
method: "POST",
body: makeFormData({
api_token: apiToken,
id: PROJECT_ID,
language: lang,
type: "json",
tags: tag
}),
headers: { "Content-Type": "application/x-www-form-urlencoded" }
})
.then(exportResponse => {
bar.tick();
return exportResponse.json();
})
.then(exportData => fetch(exportData.result.url))
.then(langResponse => {
bar.tick();
return langResponse.json();
})
.then(langData => {
const parsedData = langData.reduce((map, item) => {
// Check for plurals
if (typeof item.definition === "string") {
map[item.term] = item.definition;
} else if (item.definition === null) {
// Don't add missing strings. They will be loaded from the fallback language.
return map;
} else {
// Check if there's just singular and plural
if (Object.keys(item.definition).length === 2) {
map[item.term] = item.definition["one"];
map[item.term + "_plural"] = item.definition["other"];
} else {
// Map POEditor's plural keys to i18next's plural suffixes
const pluralMap = {
zero: "0",
one: "1",
two: "2",
few: "3",
many: "4",
other: "5"
};
// Add the various plural keys
for (let plural of Object.keys(item.definition))
map[item.term + "_" + pluralMap[plural]] =
item.definition[plural];
}
}
return map;
}, {});
fs.outputFileSync(
`${I18N_FOLDER}/${lang}/${tag}.json`,
JSON.stringify(parsedData, null, 4)
);
bar.tick();
});
}
/**
* Fetch all the tags of the language.
*
* @param lang the language
*/
function fetchAllTags(lang) {
const tags = [
"common",
"location",
"dashboard",
"query-log",
"lists",
"login",
"footer",
"settings",
"api-errors",
"preferences"
];
const bar = multi.newBar(`${lang}\t:percent\t[:bar]`, {
// 3 steps per tag: export, download, and parse
total: 3 * tags.length
});
// Render at 0%
bar.tick(0);
for (const tag of tags) fetchTag(lang, tag, bar);
}
// Remove old translations
console.log("Deleting old translations");
fs.emptyDirSync(I18N_FOLDER);
// Get the translated languages and download the translations
console.log("Fetching languages");
getTranslatedLanguages().then(languages => {
console.log(`Languages over 70% translated: ${languages.join(", ")}`);
for (const lang of languages) fetchAllTags(lang);
});

View File

@@ -1 +1 @@
["bg","ca","de","en","es","fr","it","pt","tr"]
["ar","bg","ca","cs","da","de","el","en","es","fr","he","hr","hu","it","nl","pl","pt","ro","sk","sl","sv","tr","zh"]