1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2026-03-02 03:39:21 +00:00

Initial support for translations

This commit is contained in:
tobspr
2020-06-10 12:13:38 +02:00
parent fad7a417f2
commit 714cd449e9
6 changed files with 860 additions and 3 deletions

23
src/js/languages.js Normal file
View File

@@ -0,0 +1,23 @@
/**
* @type {Object<string, {name: string, data: any, code: string, region: string}>}
*/
export const LANGUAGES = {
en: {
name: "English",
data: null,
code: "en",
region: "",
},
de: {
name: "Deutsch",
data: require("./built-temp/base-de.json"),
code: "de",
region: "",
},
fr: {
name: "Français",
data: require("./built-temp/base-fr.json"),
code: "fr",
region: "",
},
};

View File

@@ -9,6 +9,7 @@ import { ExplainedResult } from "../core/explained_result";
import { THEMES, THEME, applyGameTheme } from "../game/theme";
import { IS_DEMO } from "../core/config";
import { T } from "../translations";
import { LANGUAGES } from "../languages";
const logger = createLogger("application_settings");
@@ -63,6 +64,16 @@ export const scrollWheelSensitivities = [
/** @type {Array<BaseSetting>} */
export const allApplicationSettings = [
new EnumSetting("language", {
options: Object.keys(LANGUAGES),
valueGetter: key => key,
textGetter: key => LANGUAGES[key].name,
category: categoryApp,
restartRequired: true,
changeCb: (app, id) => null,
magicValue: "auto-detect",
}),
new EnumSetting("uiScale", {
options: uiScales.sort((a, b) => a.size - b.size),
valueGetter: scale => scale.id,
@@ -165,6 +176,7 @@ class SettingsStorage {
this.theme = "light";
this.refreshRate = "60";
this.scrollWheelSensitivity = "regular";
this.language = "auto-detect";
this.alwaysMultiplace = false;
this.offerHints = true;
@@ -259,8 +271,17 @@ export class ApplicationSettings extends ReadWriteProxy {
return this.getAllSettings().keybindingOverrides;
}
getLanguage() {
return this.getAllSettings().language;
}
// Setters
updateLanguage(id) {
assert(LANGUAGES[id], "Language not known: " + id);
return this.updateSetting("language", id);
}
/**
* @param {string} key
* @param {string|boolean} value
@@ -337,7 +358,7 @@ export class ApplicationSettings extends ReadWriteProxy {
}
getCurrentVersion() {
return 8;
return 9;
}
/** @param {{settings: SettingsStorage, version: number}} data */
@@ -364,6 +385,11 @@ export class ApplicationSettings extends ReadWriteProxy {
data.version = 8;
}
if (data.version < 9) {
data.settings.language = "auto-detect";
data.version = 9;
}
return ExplainedResult.good();
}
}

View File

@@ -3,7 +3,7 @@ import { createLogger } from "../core/logging";
import { findNiceValue, waitNextFrame } from "../core/utils";
import { cachebust } from "../core/cachebust";
import { PlatformWrapperImplBrowser } from "../platform/browser/wrapper";
import { T } from "../translations";
import { T, autoDetectLanguageId, updateApplicationLanguage } from "../translations";
import { HUDModalDialogs } from "../game/hud/parts/modal_dialogs";
import { CHANGELOG } from "../changelog";
import { globalConfig } from "../core/config";
@@ -143,6 +143,19 @@ export class PreloadState extends GameState {
}
})
.then(() => this.setStatus("Initializing language"))
.then(() => {
if (this.app.settings.getLanguage() === "auto-detect") {
const language = autoDetectLanguageId();
logger.log("Setting language to", language);
return this.app.settings.updateLanguage(language);
}
})
.then(() => {
const language = this.app.settings.getLanguage();
updateApplicationLanguage(language);
})
.then(() => this.setStatus("Initializing sounds"))
.then(() => {
// Notice: We don't await the sounds loading itself

View File

@@ -1,9 +1,13 @@
import { globalConfig } from "./core/config";
import { createLogger } from "./core/logging";
import { LANGUAGES } from "./languages";
const logger = createLogger("translations");
// @ts-ignore
const baseTranslations = require("./built-temp/base-en.json");
export const T = baseTranslations;
export let T = baseTranslations;
if (G_IS_DEV && globalConfig.debug.testTranslations) {
// Replaces all translations by fake translations to see whats translated and what not
@@ -19,3 +23,112 @@ if (G_IS_DEV && globalConfig.debug.testTranslations) {
};
mapTranslations(T);
}
export function applyLanguage(languageCode) {
logger.log("Applying language:", languageCode);
const data = LANGUAGES[languageCode];
if (!data) {
logger.error("Language not found:", languageCode);
return false;
}
}
// Language key is something like de-DE or en or en-US
function mapLanguageCodeToId(languageKey) {
const key = languageKey.toLowerCase();
const shortKey = key.split("-")[0];
// Try to match by key or short key
for (const id in LANGUAGES) {
const data = LANGUAGES[id];
const code = data.code.toLowerCase();
if (code === key) {
console.log("-> Match", languageKey, "->", id);
return id;
}
if (code === shortKey) {
console.log("-> Match by short key", languageKey, "->", id);
return id;
}
}
// If none found, try to find a better alternative by using the base language at least
for (const id in LANGUAGES) {
const data = LANGUAGES[id];
const code = data.code.toLowerCase();
const shortCode = code.split("-")[0];
if (shortCode === key) {
console.log("-> Desperate Match", languageKey, "->", id);
return id;
}
if (shortCode === shortKey) {
console.log("-> Desperate Match by short key", languageKey, "->", id);
return id;
}
}
return null;
}
/**
* Tries to auto-detect a language
* @returns {string}
*/
export function autoDetectLanguageId() {
let languages = [];
if (navigator.languages) {
languages = navigator.languages.slice();
} else if (navigator.language) {
languages = [navigator.language];
} else {
logger.warn("Navigator has no languages prop");
}
languages = ["de-De"];
for (let i = 0; i < languages.length; ++i) {
logger.log("Trying to find language target for", languages[i]);
const trans = mapLanguageCodeToId(languages[i]);
if (trans) {
return trans;
}
}
return null;
}
function matchDataRecursive(dest, src) {
if (typeof dest !== "object" || typeof src !== "object") {
return;
}
for (const key in dest) {
if (src[key]) {
// console.log("copy", key);
const data = dest[key];
if (typeof data === "object") {
matchDataRecursive(dest[key], src[key]);
} else if (typeof data === "string" || typeof data === "number") {
// console.log("match string", key);
dest[key] = src[key];
} else {
logger.log("Unknown type:", typeof data, "in key", key);
}
}
}
}
export function updateApplicationLanguage(id) {
logger.log("Setting application language:", id);
const data = LANGUAGES[id];
if (!data) {
logger.error("Unknown language:", id);
return;
}
if (data.data) {
logger.log("Applying translations ...");
matchDataRecursive(T, data.data);
}
}