Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions tools/scripts/languages.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python3

SUPPORTED_LANGUAGES = ["ar-EG", "ca-ES", "cs-CZ", "da-DK", "de-DE", "en-GB", "en-US", "eo-ZZ",\
"es-ES", "fi-FI", "fr-FR", "gl-ES", "hu-HU", "it-IT", "ja-JP", "ko-KR",\
"nb-NO", "nl-NL", "pl-PL", "pt-BR", "ru-RU", "sv-SE", "tr-TR", "uk-UA",\
"zh-CN", "zh-TW"]
"es-ES", "fi-FI", "fr-CA", "fr-FR", "gl-ES", "hu-HU", "it-IT", "ja-JP",\
"ko-KR", "nb-NO", "nl-NL", "pl-PL", "pt-BR", "ru-RU", "sv-SE", "tr-TR",\
"uk-UA", "vi-VN", "zh-CN", "zh-TW"]
8 changes: 8 additions & 0 deletions tools/scripts/modules/lang-js-parse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const fs = require("fs");

function parse(file) {
var res = JSON.parse(fs.readFileSync(file, "utf8"));
return res;
}

module.exports = { parse }
70 changes: 70 additions & 0 deletions tools/scripts/modules/lang-tools.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
const parserJS = require("./lang-js-parse")
const parserTxt = require("./lang-txt-parse")
const utils = require("./utils");
const path = require("node:path")
const fs = require("fs");

const SupportedLanguages = [
"ar-EG", "ca-ES", "cs-CZ", "da-DK", "de-DE", "en-GB", "en-US", "eo-ZZ",
"es-ES", "fi-FI", "fr-CA", "fr-FR", "gl-ES", "hu-HU", "it-IT", "ja-JP",
"ko-KR", "nb-NO", "nl-NL", "pl-PL", "pt-BR", "ru-RU", "sv-SE", "tr-TR",
"uk-UA", "vi-VN", "zh-CN", "zh-TW"
];

const Language = {
ArEG: "ar-EG",
CaES: "ca-ES",
CsCZ: "cs-CZ",
DaDK: "da-DK",
DeDE: "de-DE",
EnGB: "en-GB",
EnUS: "en-US",
EoZZ: "eo-ZZ",
EsES: "es-ES",
FiFI: "fi-FI",
FrCA: "fr-CA",
FrFR: "fr-FR",
GlES: "gl-ES",
HuHU: "hu-HU",
ItIT: "it-IT",
JaJP: "ja-JP",
KoKR: "ko-KR",
NbNO: "nb-NO",
NlNL: "nl-NL",
PlPL: "pl-PL",
PtBR: "pt-BR",
RuRU: "ru-RU",
SvSE: "sv-SE",
TrTR: "tr-TR",
UkUA: "uk-UA",
ViVN: "vi-VN",
ZhCN: "zh-CN",
ZhTW: "zh-TW"
};

function parseLanguage(file) {
var ext = path.extname(file);
var data = null;
if(ext == ".json") {
data = parserJS.parse(file);
}
else if(ext == ".txt") {
data = parserTxt.parse(file);
}
if(data == null) {
throw "Unable to parse file";
}
return data;
}

function parseObject(file) {
var res = JSON.parse(fs.readFileSync(file, "utf8"));
return res;
}

module.exports = {
Language,
utils,
parseLanguage,
parseObject
}
7 changes: 7 additions & 0 deletions tools/scripts/modules/lang-txt-parse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const fs = require("fs");

function parse(file) {
throw "Not implemented";
}

module.exports = { parse }
90 changes: 90 additions & 0 deletions tools/scripts/modules/prettify-json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
function init(state, opts) {
var spacer = "";
if (opts.useTabs) {
spacer = "\t";
} else {
for (var i = 0; i < opts.tabSize; ++i) {
spacer += " ";
}
}
for (var i = 0; i < 20; ++i) {
var spacing = "";
for(var n = 0; n < i; ++n) {
spacing += spacer;
}
state.spacing[i] = spacing;
}
}

function getSpacing(state, opts) {
return state.spacing[state.indent];
}

function beginScope(state, opts, str, inline) {
var res = str + (inline ? "" : "\n");
state.indent++;
return res;
}

function endScope(state, opts, str, inline) {
state.indent--;
return (inline ? "" : getSpacing(state, opts)) + str;
}

function processValue(state, opts, value, inline) {
var res = "";
if (value instanceof Array) {
res += beginScope(state, opts, "[", false);
var values = [];
for (var i = 0; i < value.length; ++i) {
const innerBody = getSpacing(state, opts) + processValue(state, opts, value[i], inline);
values.push(innerBody);
}
if (values.length > 0) {
res += values.join(",\n") + "\n";
}
res += endScope(state, opts, "]", false);
}
else if (value instanceof Object) {
res += beginScope(state, opts, inline ? "{ " : "{", inline);

var values = [];
for (const key of Object.keys(value)) {
const inlineChildren = opts.forceInline.includes(key);
const innerBody = (inline ? "" : getSpacing(state, opts)) + JSON.stringify(key) + ": " + processValue(state, opts, value[key], inlineChildren);
values.push(innerBody);
}
if (values.length > 0) {
res += values.join(inline ? ", " : ",\n") + (inline ? "" : "\n");
}
res += endScope(state, opts, inline ? " }" : "}", inline);
}
else {
res += JSON.stringify(value);
}
return res;
}

function prettifyJSON(value, opts) {
var state = {
indent: 0,
spacing: [],
}
if (opts == null || opts == undefined) {
opts = {};
}
if (!('forceInline' in opts)) {
opts.forceInline = [];
}
if (!('useTabs' in opts)) {
opts.useTabs = false;
}
if (!('tabSize' in opts)) {
opts.tabSize = 4;
}
init(state, opts);
return processValue(state, opts, value, false) +
"\n" /* Some editors like adding newlines so lets just keep it that way */;
}

module.exports = { prettifyJSON };
22 changes: 22 additions & 0 deletions tools/scripts/modules/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const path = require("path")
const fs = require("fs");

function getFiles(path) {
const files = []
for (const file of fs.readdirSync(path)) {
const fullPath = path + '/' + file
if(fs.lstatSync(fullPath).isDirectory())
getFiles(fullPath).forEach(x => files.push(file + '/' + x))
else files.push(file)
}
return files
}

function getObjectFiles(filePath) {
var files = getFiles(filePath);
return files.filter(file => {
return path.extname(file) === ".json";
});
}

module.exports = { getObjectFiles };
48 changes: 48 additions & 0 deletions tools/scripts/prettify-object-json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// To use this script do:
// node ./tools/scripts/prettify-object-json.js PATH_TO_OBJECTS_REPO

const fs = require("fs");
const path = require("path");
const utils = require("./modules/utils.js");
const { prettifyJSON } = require("./modules/prettify-json");

const formatOptions = {
"forceInline": ["images", "noCsgImages"],
"useTabs": false,
"tabSize": 4,
};

const args = process.argv
if (args.length < 3) {
console.error("ERROR: Expected <path_or_file>");
process.exit(-1);
}

const objectsPathOrFile = args[2];

function formatObjectFile(fullPath) {
console.info(`Formatting: ${fullPath}`);
const fileData = fs.readFileSync(fullPath, "utf8");
const jsonData = JSON.parse(fileData);
const prettified = prettifyJSON(jsonData, formatOptions);
return prettified;
}

const fileInfo = fs.lstatSync(objectsPathOrFile);
if (fileInfo.isDirectory()) {
// Format entire directory.
const objectFiles = utils.getObjectFiles(objectsPathOrFile);
objectFiles.forEach(filePath => {
const fullPath = path.join(objectsPathOrFile, filePath);
const prettified = formatObjectFile(fullPath);
fs.writeFileSync(fullPath, prettified, "utf8");
});
} else if(fileInfo.isFile()) {
// Format single file.
const prettified = formatObjectFile(objectsPathOrFile);
//console.log(prettified);
fs.writeFileSync(objectsPathOrFile, prettified, "utf8");
} else {
console.error("ERROR: Invalid argument provided, argument is not a file or directory.");
process.exit(-1);
}
129 changes: 129 additions & 0 deletions tools/scripts/update-localisation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// To use this script do:
// node ./tools/scripts/update-localisation.js PATH_TO_LOCALISATION_REPO PATH_TO_OBJECTS_REPO

const fs = require("node:fs");
const path = require("node:path");
const langTools = require("./modules/lang-tools.js");
const utils = require("./modules/utils.js")
const { prettifyJSON } = require("./modules/prettify-json");

const formatOptions = {
"forceInline": ["images", "noCsgImages"],
"useTabs": false,
"tabSize": 4,
};

function parseObjectLanguages(localisationRootPath) {
var res = [];
for (let key in langTools.Language) {
const langId = langTools.Language[key];
const langPath = path.join(localisationRootPath, "objects", langId + ".json");
const langData = langTools.parseLanguage(langPath, langId);
res[langId] = langData;
}
return res;
}

function mergeLanguageData(objectData, langData, lang) {
// Create a copy.
objectData = Object.assign({}, objectData);
const objectId = objectData["id"];

var objectLangData = langData[objectId];
if(objectLangData === undefined)
{
console.warn(`Missing object group '${objectId}' in language '${lang}'`);
return objectData;
}

var langStrings = objectData["strings"];
for(var key in langStrings) {
const translation = objectLangData[key];
if(translation === undefined) {
console.warn(`Missing key ${key} in ${lang} data`);
continue;
}
const referenceTranslation = objectLangData[`reference-${key}`];
if(lang != langTools.Language.EnGB && lang != langTools.Language.EnUS && referenceTranslation == translation)
{
//console.warn(`Warning: Translation ${key} is same as reference for non-english language: ${lang}, skipping.`);
continue;
}
else {
const oldEntry = langStrings[key][lang];
if(oldEntry === undefined) {
//console.log(`Created key ${lang}:${key} -> '${translation}'`);
langStrings[key][lang] = translation;
}
else if(oldEntry != translation) {
console.log(`Updated key ${lang}:${key} from '${oldEntry}' -> '${translation}'`);
langStrings[key][lang] = translation;
}
else if(oldEntry == translation) {
//console.log(`Translation identical for key ${lang}:${key} -> ${translation}`);
}
}
}

return objectData;
}

function processObjectFile(objectsLangData, objectFilePath) {
console.info(`Processing Object ${objectFilePath}`);

var objectData = langTools.parseObject(objectFilePath);
if (objectData == null) {
throw `Failed to read object data: ${objectFilePath}`;
}

// Update all keys.
for (let key in langTools.Language) {
const langId = langTools.Language[key];
const langData = objectsLangData[langId];
objectData = mergeLanguageData(objectData, langData, langId);
}

// Remove en-US when its same as en-GB
for(let nameKey in objectData["strings"]) {
var stringEntries = objectData["strings"][nameKey];
if(stringEntries[langTools.Language.EnUS] !== undefined && stringEntries[langTools.Language.EnUS] == stringEntries[langTools.Language.EnGB]) {
delete stringEntries[langTools.Language.EnUS];
}
}

// Save to file.
var jsonStr = prettifyJSON(objectData, formatOptions);
fs.writeFileSync(objectFilePath, jsonStr, "utf8");
}

function mergeLocalisationToObjects(localisationRootPath, objectsRootPath) {
const objectsPath = path.join(objectsRootPath, "objects");

const objectFiles = utils.getObjectFiles(objectsPath);
if (objectFiles.length == 0) {
throw "No object files found";
}

const objectsLangData = parseObjectLanguages(localisationRootPath);
objectFiles.forEach(objectFile => processObjectFile(objectsLangData, path.join(objectsPath, objectFile)));
}

const args = process.argv
if (args.length < 4) {
console.error("ERROR: Expected arguments: <path_to_localisation> <path_to_objects>");
process.exit(-1);
}

const localisationPath = args[2];
if (!fs.lstatSync(localisationPath).isDirectory()) {
console.error("ERROR: Argument provided for localisation is not a directory.");
process.exit(-1);
}

const objectsPath = args[3];
if (!fs.lstatSync(objectsPath).isDirectory()) {
console.error("ERROR: Argument provided for objects is not a directory.");
process.exit(-1);
}

mergeLocalisationToObjects(localisationPath, objectsPath);
Loading