1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-06-13 13:04:03 +00:00

Cleanup base dir

This commit is contained in:
Bagel03 2022-11-17 21:39:40 -05:00
parent d3fe689b31
commit e768561dc6
4 changed files with 176 additions and 110 deletions

View File

@ -38,11 +38,13 @@ import { WegameSplashState } from "./states/wegame_splash";
import { MODS } from "./mods/modloader"; import { MODS } from "./mods/modloader";
import { MOD_SIGNALS } from "./mods/mod_signals"; import { MOD_SIGNALS } from "./mods/mod_signals";
import { ModsState } from "./states/mods"; import { ModsState } from "./states/mods";
export type AchievementProviderInterface = import("./platform/achievement_provider").AchievementProviderInterface;
export type SoundInterface = import("./platform/sound").SoundInterface; import type { AchievementProviderInterface } from "./platform/achievement_provider";
export type StorageInterface = import("./platform/storage").StorageInterface; import type { SoundInterface } from "./platform/sound";
import type { StorageInterface } from "./platform/storage";
const logger: any = createLogger("application"); const logger: any = createLogger("application");
// Set the name of the hidden property and the change event for visibility // Set the name of the hidden property and the change event for visibility
let pageHiddenPropName: any, pageVisibilityEventName: any; let pageHiddenPropName: any, pageVisibilityEventName: any;
if (typeof document.hidden !== "undefined") { if (typeof document.hidden !== "undefined") {
@ -50,71 +52,87 @@ if (typeof document.hidden !== "undefined") {
pageHiddenPropName = "hidden"; pageHiddenPropName = "hidden";
pageVisibilityEventName = "visibilitychange"; pageVisibilityEventName = "visibilitychange";
// @ts-ignore // @ts-ignore
} } else if (typeof document.msHidden !== "undefined") {
else if (typeof document.msHidden !== "undefined") {
pageHiddenPropName = "msHidden"; pageHiddenPropName = "msHidden";
pageVisibilityEventName = "msvisibilitychange"; pageVisibilityEventName = "msvisibilitychange";
// @ts-ignore // @ts-ignore
} } else if (typeof document.webkitHidden !== "undefined") {
else if (typeof document.webkitHidden !== "undefined") {
pageHiddenPropName = "webkitHidden"; pageHiddenPropName = "webkitHidden";
pageVisibilityEventName = "webkitvisibilitychange"; pageVisibilityEventName = "webkitvisibilitychange";
} }
export class Application { export class Application {
public unloaded = true;
// Global stuff
public settings = new ApplicationSettings(this);
public ticker = new AnimationFrame();
public stateMgr = new StateManager(this);
public savegameMgr = new SavegameManager(this);
public inputMgr = new InputDistributor(this);
public backgroundResourceLoader = new BackgroundResourcesLoader(this);
public clientApi = new ClientAPI(this);
// Restrictions (Like demo etc)
public restrictionMgr = new RestrictionManager(this);
// Platform dependent stuff
public storage: StorageInterface = null;
public sound: SoundInterface = new SoundImplBrowser(this);
public platformWrapper: PlatformWrapperInterface = G_IS_STANDALONE ? new PlatformWrapperImplElectron(this) : new PlatformWrapperImplBrowser(this);
public achievementProvider: AchievementProviderInterface = new NoAchievementProvider(this);
public adProvider: AdProviderInterface = new NoAdProvider(this);
public analytics: AnalyticsInterface = new GoogleAnalyticsImpl(this);
public gameAnalytics = new ShapezGameAnalytics(this);
// Track if the window is focused (only relevant for browser)
public focused = true;
// Track if the window is visible
public pageVisible = true;
// Track if the app is paused (cordova)
public applicationPaused = false;
public trackedIsRenderable = new TrackedState(this.onAppRenderableStateChanged, this);
public trackedIsPlaying = new TrackedState(this.onAppPlayingStateChanged, this);
// Dimensions
public screenWidth = 0;
public screenHeight = 0;
// Store the timestamp where we last checked for a screen resize, since orientationchange is unreliable with cordova
public lastResizeCheck: number = null;
// Store the mouse position, or null if not available
public mousePosition: Vector = null;
/** /**
* Boots the application * Boots the application
*/ */
async boot(): any { async boot(): Promise<void> {
console.log("Booting ..."); console.log("Booting ...");
assert(!GLOBAL_APP, "Tried to construct application twice"); assert(!GLOBAL_APP, "Tried to construct application twice");
logger.log("Creating application, platform =", getPlatformName()); logger.log("Creating application, platform =", getPlatformName());
setGlobalApp(this); setGlobalApp(this);
MODS.app = this; MODS.app = this;
// MODS // MODS
try { try {
await MODS.initMods(); await MODS.initMods();
} }
catch (ex: any) { catch (ex: any) {
alert("Failed to load mods (launch with --dev for more info): \n\n" + ex); alert("Failed to load mods (launch with --dev for more info): \n\n" + ex);
} }
this.unloaded = false; this.unloaded = false;
// Global stuff
this.settings = new ApplicationSettings(this);
this.ticker = new AnimationFrame();
this.stateMgr = new StateManager(this);
this.savegameMgr = new SavegameManager(this);
this.inputMgr = new InputDistributor(this);
this.backgroundResourceLoader = new BackgroundResourcesLoader(this);
this.clientApi = new ClientAPI(this);
// Restrictions (Like demo etc)
this.restrictionMgr = new RestrictionManager(this);
// Platform dependent stuff
this.storage = null;
this.sound = null;
this.platformWrapper = null;
this.achievementProvider = null;
this.adProvider = null;
this.analytics = null;
this.gameAnalytics = null;
this.initPlatformDependentInstances();
// Track if the window is focused (only relevant for browser)
this.focused = true;
// Track if the window is visible
this.pageVisible = true;
// Track if the app is paused (cordova)
this.applicationPaused = false;
this.trackedIsRenderable = new TrackedState(this.onAppRenderableStateChanged, this);
this.trackedIsPlaying = new TrackedState(this.onAppPlayingStateChanged, this);
// Dimensions
this.screenWidth = 0;
this.screenHeight = 0;
// Store the timestamp where we last checked for a screen resize, since orientationchange is unreliable with cordova
this.lastResizeCheck = null;
// Store the mouse position, or null if not available
this.mousePosition = null;
this.registerStates(); this.registerStates();
this.registerEventListeners(); this.registerEventListeners();
Loader.linkAppAfterBoot(this); Loader.linkAppAfterBoot(this);
// Check for mobile // Check for mobile
if (IS_MOBILE) { if (IS_MOBILE) {
this.stateMgr.moveToState("MobileWarningState"); this.stateMgr.moveToState("MobileWarningState");
@ -122,35 +140,21 @@ export class Application {
else { else {
this.stateMgr.moveToState("PreloadState"); this.stateMgr.moveToState("PreloadState");
} }
// Starting rendering // Starting rendering
this.ticker.frameEmitted.add(this.onFrameEmitted, this); this.ticker.frameEmitted.add(this.onFrameEmitted, this);
this.ticker.bgFrameEmitted.add(this.onBackgroundFrame, this); this.ticker.bgFrameEmitted.add(this.onBackgroundFrame, this);
this.ticker.start(); this.ticker.start();
window.focus(); window.focus();
MOD_SIGNALS.appBooted.dispatch(); MOD_SIGNALS.appBooted.dispatch();
} }
/**
* Initializes all platform instances
*/
initPlatformDependentInstances(): any {
logger.log("Creating platform dependent instances (standalone=", G_IS_STANDALONE, ")");
if (G_IS_STANDALONE) {
this.platformWrapper = new PlatformWrapperImplElectron(this);
}
else {
this.platformWrapper = new PlatformWrapperImplBrowser(this);
}
// Start with empty ad provider
this.adProvider = new NoAdProvider(this);
this.sound = new SoundImplBrowser(this);
this.analytics = new GoogleAnalyticsImpl(this);
this.gameAnalytics = new ShapezGameAnalytics(this);
this.achievementProvider = new NoAchievementProvider(this);
}
/** /**
* Registers all game states * Registers all game states
*/ */
registerStates(): any { registerStates(): void {
const states: Array<typeof GameState> = [ const states: Array<typeof GameState> = [
WegameSplashState, WegameSplashState,
PreloadState, PreloadState,
@ -165,39 +169,47 @@ export class Application {
LoginState, LoginState,
ModsState, ModsState,
]; ];
for (let i: any = 0; i < states.length; ++i) { for (let i = 0; i < states.length; ++i) {
this.stateMgr.register(states[i]); this.stateMgr.register(states[i]);
} }
} }
/** /**
* Registers all event listeners * Registers all event listeners
*/ */
registerEventListeners(): any { registerEventListeners(): void {
window.addEventListener("focus", this.onFocus.bind(this)); window.addEventListener("focus", this.onFocus.bind(this));
window.addEventListener("blur", this.onBlur.bind(this)); window.addEventListener("blur", this.onBlur.bind(this));
window.addEventListener("resize", (): any => this.checkResize(), true);
window.addEventListener("orientationchange", (): any => this.checkResize(), true); window.addEventListener("resize", () => this.checkResize(), true);
window.addEventListener("orientationchange", () => this.checkResize(), true);
window.addEventListener("mousemove", this.handleMousemove.bind(this)); window.addEventListener("mousemove", this.handleMousemove.bind(this));
window.addEventListener("mouseout", this.handleMousemove.bind(this)); window.addEventListener("mouseout", this.handleMousemove.bind(this));
window.addEventListener("mouseover", this.handleMousemove.bind(this)); window.addEventListener("mouseover", this.handleMousemove.bind(this));
window.addEventListener("mouseleave", this.handleMousemove.bind(this)); window.addEventListener("mouseleave", this.handleMousemove.bind(this));
// Unload events // Unload events
window.addEventListener("beforeunload", this.onBeforeUnload.bind(this), true); window.addEventListener("beforeunload", this.onBeforeUnload.bind(this), true);
document.addEventListener(pageVisibilityEventName, this.handleVisibilityChange.bind(this), false); document.addEventListener(pageVisibilityEventName, this.handleVisibilityChange.bind(this), false);
// Track touches so we can update the focus appropriately // Track touches so we can update the focus appropriately
document.addEventListener("touchstart", this.updateFocusAfterUserInteraction.bind(this), true); document.addEventListener("touchstart", this.updateFocusAfterUserInteraction.bind(this), true);
document.addEventListener("touchend", this.updateFocusAfterUserInteraction.bind(this), true); document.addEventListener("touchend", this.updateFocusAfterUserInteraction.bind(this), true);
} }
/** /**
* Checks the focus after a touch * Checks the focus after a touch
*/ */
updateFocusAfterUserInteraction(event: TouchEvent): any { updateFocusAfterUserInteraction(event: TouchEvent): void {
const target: any = (event.target as HTMLElement); const target = (event.target as HTMLElement);
if (!target || !target.tagName) { if (!target || !target.tagName) {
// Safety check // Safety check
logger.warn("Invalid touchstart/touchend event:", event); logger.warn("Invalid touchstart/touchend event:", event);
return; return;
} }
// When clicking an element which is not the currently focused one, defocus it // When clicking an element which is not the currently focused one, defocus it
if (target !== document.activeElement) { if (target !== document.activeElement) {
// @ts-ignore // @ts-ignore
@ -206,16 +218,18 @@ export class Application {
document.activeElement.blur(); document.activeElement.blur();
} }
} }
// If we click an input field, focus it now // If we click an input field, focus it now
if (target.tagName.toLowerCase() === "input") { if (target.tagName.toLowerCase() === "input") {
// We *really* need the focus // We *really* need the focus
waitNextFrame().then((): any => target.focus()); waitNextFrame().then((): any => target.focus());
} }
} }
/** /**
* Handles a page visibility change event * Handles a page visibility change event
*/ */
handleVisibilityChange(event: Event): any { handleVisibilityChange(event: Event): void {
window.focus(); window.focus();
const pageVisible: any = !document[pageHiddenPropName]; const pageVisible: any = !document[pageHiddenPropName];
if (pageVisible !== this.pageVisible) { if (pageVisible !== this.pageVisible) {
@ -224,31 +238,36 @@ export class Application {
this.trackedIsRenderable.set(this.isRenderable()); this.trackedIsRenderable.set(this.isRenderable());
} }
} }
/** /**
* Handles a mouse move event * Handles a mouse move event
*/ */
handleMousemove(event: MouseEvent): any { handleMousemove(event: MouseEvent): void {
this.mousePosition = new Vector(event.clientX, event.clientY); this.mousePosition = new Vector(event.clientX, event.clientY);
} }
/** /**
* Internal on focus handler * Internal on focus handler
*/ */
onFocus(): any { onFocus(): void {
this.focused = true; this.focused = true;
} }
/** /**
* Internal blur handler * Internal blur handler
*/ */
onBlur(): any { onBlur(): void {
this.focused = false; this.focused = false;
} }
/** /**
* Returns if the app is currently visible * Returns if the app is currently visible
*/ */
isRenderable(): any { isRenderable(): boolean {
return !this.applicationPaused && this.pageVisible; return !this.applicationPaused && this.pageVisible;
} }
onAppRenderableStateChanged(renderable: any): any {
onAppRenderableStateChanged(renderable: boolean): void {
logger.log("Application renderable:", renderable); logger.log("Application renderable:", renderable);
window.focus(); window.focus();
const currentState: any = this.stateMgr.getCurrentState(); const currentState: any = this.stateMgr.getCurrentState();
@ -263,9 +282,11 @@ export class Application {
} }
this.checkResize(); this.checkResize();
} }
this.sound.onPageRenderableStateChanged(renderable); this.sound.onPageRenderableStateChanged(renderable);
} }
onAppPlayingStateChanged(playing: any): any {
onAppPlayingStateChanged(playing: boolean): void {
try { try {
this.adProvider.setPlayStatus(playing); this.adProvider.setPlayStatus(playing);
} }
@ -273,12 +294,14 @@ export class Application {
console.warn("Play status changed"); console.warn("Play status changed");
} }
} }
/** /**
* Internal before-unload handler * Internal before-unload handler
*/ */
onBeforeUnload(event: any): any { onBeforeUnload(event: BeforeUnloadEvent): void {
logSection("BEFORE UNLOAD HANDLER", "#f77"); logSection("BEFORE UNLOAD HANDLER", "#f77");
const currentState: any = this.stateMgr.getCurrentState(); const currentState: GameState = this.stateMgr.getCurrentState();
if (!G_IS_DEV && currentState && currentState.getHasUnloadConfirmation()) { if (!G_IS_DEV && currentState && currentState.getHasUnloadConfirmation()) {
if (!G_IS_STANDALONE) { if (!G_IS_STANDALONE) {
// Need to show a "Are you sure you want to exit" // Need to show a "Are you sure you want to exit"
@ -287,71 +310,82 @@ export class Application {
} }
} }
} }
/** /**
* Deinitializes the application * Deinitializes the application
*/ */
deinitialize(): any { deinitialize(): Promise<void> {
return this.sound.deinitialize(); return this.sound.deinitialize();
} }
/** /**
* Background frame update callback * Background frame update callback
*/ */
onBackgroundFrame(dt: number): any { onBackgroundFrame(dt: number): void {
if (this.isRenderable()) { if (this.isRenderable()) {
return; return;
} }
const currentState: any = this.stateMgr.getCurrentState(); const currentState: any = this.stateMgr.getCurrentState();
if (currentState) { if (currentState) {
currentState.onBackgroundTick(dt); currentState.onBackgroundTick(dt);
} }
} }
/** /**
* Frame update callback * Frame update callback
*/ */
onFrameEmitted(dt: number): any { onFrameEmitted(dt: number): void {
if (!this.isRenderable()) { if (!this.isRenderable()) {
return; return;
} }
const time: any = performance.now(); const time: any = performance.now();
// Periodically check for resizes, this is expensive (takes 2-3ms so only do it once in a while!) // Periodically check for resizes, this is expensive (takes 2-3ms so only do it once in a while!)
if (!this.lastResizeCheck || time - this.lastResizeCheck > 1000) { if (!this.lastResizeCheck || time - this.lastResizeCheck > 1000) {
this.checkResize(); this.checkResize();
this.lastResizeCheck = time; this.lastResizeCheck = time;
} }
const currentState: any = this.stateMgr.getCurrentState(); const currentState: any = this.stateMgr.getCurrentState();
this.trackedIsPlaying.set(currentState && currentState.getIsIngame()); this.trackedIsPlaying.set(currentState && currentState.getIsIngame());
if (currentState) { if (currentState) {
currentState.onRender(dt); currentState.onRender(dt);
} }
} }
/** /**
* Checks if the app resized. Only does this once in a while * Checks if the app resized. Only does this once in a while
*/ */
checkResize(forceUpdate: boolean = false): any { checkResize(forceUpdate: boolean = false): void {
const w: any = window.innerWidth; const w = window.innerWidth;
const h: any = window.innerHeight; const h = window.innerHeight;
if (this.screenWidth !== w || this.screenHeight !== h || forceUpdate) { if (this.screenWidth !== w || this.screenHeight !== h || forceUpdate) {
this.screenWidth = w; this.screenWidth = w;
this.screenHeight = h; this.screenHeight = h;
const currentState: any = this.stateMgr.getCurrentState(); const currentState: GameState = this.stateMgr.getCurrentState();
if (currentState) { if (currentState) {
currentState.onResized(this.screenWidth, this.screenHeight); currentState.onResized(this.screenWidth, this.screenHeight);
} }
const scale: any = this.getEffectiveUiScale();
const scale: number = this.getEffectiveUiScale();
waitNextFrame().then((): any => document.documentElement.style.setProperty("--ui-scale", `${scale}`)); waitNextFrame().then((): any => document.documentElement.style.setProperty("--ui-scale", `${scale}`));
window.focus(); window.focus();
} }
} }
/** /**
* Returns the effective ui sclae * Returns the effective ui sclae
*/ */
getEffectiveUiScale(): any { getEffectiveUiScale(): number {
return this.platformWrapper.getUiScale() * this.settings.getInterfaceScaleValue(); return this.platformWrapper.getUiScale() * this.settings.getInterfaceScaleValue();
} }
/** /**
* Callback after ui scale has changed * Callback after ui scale has changed
*/ */
updateAfterUiScaleChanged(): any { updateAfterUiScaleChanged(): void {
this.checkResize(true); this.checkResize(true);
} }
} }

View File

@ -1,4 +1,9 @@
export const CHANGELOG: any = [ export const CHANGELOG: {
version: string,
date: string,
entries: string[],
skin?: string
}[] = [
{ {
version: "1.5.6", version: "1.5.6",
date: "09.12.2022", date: "09.12.2022",

View File

@ -1,6 +1,8 @@
import "./core/polyfills"; import "./core/polyfills";
import "./core/assert"; import "./core/assert";
import "./mods/modloader"; import "./mods/modloader";
import { createLogger, logSection } from "./core/logging"; import { createLogger, logSection } from "./core/logging";
import { Application } from "./application"; import { Application } from "./application";
import { IS_DEBUG } from "./core/config"; import { IS_DEBUG } from "./core/config";
@ -10,36 +12,48 @@ import { initItemRegistry } from "./game/item_registry";
import { initMetaBuildingRegistry } from "./game/meta_building_registry"; import { initMetaBuildingRegistry } from "./game/meta_building_registry";
import { initGameModeRegistry } from "./game/game_mode_registry"; import { initGameModeRegistry } from "./game/game_mode_registry";
import { initGameSpeedRegistry } from "./game/game_speed_registry"; import { initGameSpeedRegistry } from "./game/game_speed_registry";
const logger: any = createLogger("main"); const logger: any = createLogger("main");
if (window.coreThreadLoadedCb) { if (window.coreThreadLoadedCb) {
logger.log("Javascript parsed, calling html thread"); logger.log("Javascript parsed, calling html thread");
window.coreThreadLoadedCb(); window.coreThreadLoadedCb();
} }
console.log(`%cshapez.io %c\n© 2022 tobspr Games\nCommit %c${G_BUILD_COMMIT_HASH}%c on %c${new Date(G_BUILD_TIME).toLocaleString()}\n`, "font-size: 35px; font-family: Arial;font-weight: bold; padding: 10px 0;", "color: #aaa", "color: #7f7", "color: #aaa", "color: #7f7"); console.log(`%cshapez.io %c\n© 2022 tobspr Games\nCommit %c${G_BUILD_COMMIT_HASH}%c on %c${new Date(G_BUILD_TIME).toLocaleString()}\n`, "font-size: 35px; font-family: Arial;font-weight: bold; padding: 10px 0;", "color: #aaa", "color: #7f7", "color: #aaa", "color: #7f7");
console.log("Environment: %c" + G_APP_ENVIRONMENT, "color: #fff"); console.log("Environment: %c" + G_APP_ENVIRONMENT, "color: #fff");
if (G_IS_DEV && IS_DEBUG) { if (G_IS_DEV && IS_DEBUG) {
console.log("\n%c🛑 DEBUG ENVIRONMENT 🛑\n", "color: #f77"); console.log("\n%c🛑 DEBUG ENVIRONMENT 🛑\n", "color: #f77");
} }
/* typehints:start */ /* typehints:start */
// @ts-ignore // @ts-ignore
throw new Error("typehints built in, this should never be the case!"); throw new Error("typehints built in, this should never be the case!");
/* typehints:end */ /* typehints:end */
/* dev:start */ /* dev:start */
console.log("%cDEVCODE BUILT IN", "color: #f77"); console.log("%cDEVCODE BUILT IN", "color: #f77");
/* dev:end */ /* dev:end */
logSection("Boot Process", "#f9a825"); logSection("Boot Process", "#f9a825");
initDrawUtils(); initDrawUtils();
initComponentRegistry(); initComponentRegistry();
initItemRegistry(); initItemRegistry();
initMetaBuildingRegistry(); initMetaBuildingRegistry();
initGameModeRegistry(); initGameModeRegistry();
initGameSpeedRegistry(); initGameSpeedRegistry();
let app: any = null;
let app: Application = null;
function bootApp(): any { function bootApp(): any {
logger.log("Page Loaded"); logger.log("Page Loaded");
app = new Application(); app = new Application();
app.boot(); app.boot();
} }
if (G_IS_STANDALONE) { if (G_IS_STANDALONE) {
window.addEventListener("load", bootApp); window.addEventListener("load", bootApp);
} }

View File

@ -1,15 +1,18 @@
import { globalConfig } from "./core/config"; import { globalConfig } from "./core/config";
import { createLogger } from "./core/logging"; import { createLogger } from "./core/logging";
import { LANGUAGES } from "./languages"; import { LANGUAGES } from "./languages";
const logger: any = createLogger("translations"); const logger: any = createLogger("translations");
// @ts-ignore // @ts-ignore
const baseTranslations: any = require("./built-temp/base-en.json"); const baseTranslations: any = require("./built-temp/base-en.json");
export let T: any = baseTranslations; export let T: any = baseTranslations;
if (G_IS_DEV && globalConfig.debug.testTranslations) { if (G_IS_DEV && globalConfig.debug.testTranslations) {
// Replaces all translations by fake translations to see whats translated and what not // Replaces all translations by fake translations to see whats translated and what not
const mapTranslations: any = (obj: any): any => { const mapTranslations: any = (obj: any): any => {
for (const key: any in obj) { for (const key in obj) {
const value: any = obj[key]; const value: any = obj[key];
if (typeof value === "string") { if (typeof value === "string") {
obj[key] = value.replace(/[a-z]/gi, "x"); obj[key] = value.replace(/[a-z]/gi, "x");
} }
@ -20,14 +23,16 @@ if (G_IS_DEV && globalConfig.debug.testTranslations) {
}; };
mapTranslations(T); mapTranslations(T);
} }
// Language key is something like de-DE or en or en-US // Language key is something like de-DE or en or en-US
function mapLanguageCodeToId(languageKey: any): any { function mapLanguageCodeToId(languageKey: string): string {
const key: any = languageKey.toLowerCase(); const key = languageKey.toLowerCase();
const shortKey: any = key.split("-")[0]; const shortKey = key.split("-")[0];
// Try to match by key or short key // Try to match by key or short key
for (const id: any in LANGUAGES) { for (const id in LANGUAGES) {
const data: any = LANGUAGES[id]; const data = LANGUAGES[id];
const code: any = data.code.toLowerCase(); const code = data.code.toLowerCase();
if (code === key) { if (code === key) {
console.log("-> Match", languageKey, "->", id); console.log("-> Match", languageKey, "->", id);
return id; return id;
@ -37,11 +42,13 @@ function mapLanguageCodeToId(languageKey: any): any {
return id; return id;
} }
} }
// If none found, try to find a better alternative by using the base language at least // If none found, try to find a better alternative by using the base language at least
for (const id: any in LANGUAGES) { for (const id in LANGUAGES) {
const data: any = LANGUAGES[id]; const data = LANGUAGES[id];
const code: any = data.code.toLowerCase(); const code = data.code.toLowerCase();
const shortCode: any = code.split("-")[0]; const shortCode = code.split("-")[0];
if (shortCode === key) { if (shortCode === key) {
console.log("-> Desperate Match", languageKey, "->", id); console.log("-> Desperate Match", languageKey, "->", id);
return id; return id;
@ -53,12 +60,9 @@ function mapLanguageCodeToId(languageKey: any): any {
} }
return null; return null;
} }
/** /** Tries to auto-detect a language */
* Tries to auto-detect a language
* {}
*/
export function autoDetectLanguageId(): string { export function autoDetectLanguageId(): string {
let languages: any = []; let languages: string[] = [];
if (navigator.languages) { if (navigator.languages) {
languages = navigator.languages.slice(); languages = navigator.languages.slice();
} }
@ -68,24 +72,28 @@ export function autoDetectLanguageId(): string {
else { else {
logger.warn("Navigator has no languages prop"); logger.warn("Navigator has no languages prop");
} }
for (let i: any = 0; i < languages.length; ++i) {
for (let i = 0; i < languages.length; ++i) {
logger.log("Trying to find language target for", languages[i]); logger.log("Trying to find language target for", languages[i]);
const trans: any = mapLanguageCodeToId(languages[i]); const trans = mapLanguageCodeToId(languages[i]);
if (trans) { if (trans) {
return trans; return trans;
} }
} }
// Fallback // Fallback
return "en"; return "en";
} }
export function matchDataRecursive(dest: any, src: any, addNewKeys: any = false): any {
export function matchDataRecursive(dest: any, src: any, addNewKeys: boolean = false): void {
if (typeof dest !== "object" || typeof src !== "object") { if (typeof dest !== "object" || typeof src !== "object") {
return; return;
} }
if (dest === null || src === null) { if (dest === null || src === null) {
return; return;
} }
for (const key: any in dest) {
for (const key in dest) {
if (src[key]) { if (src[key]) {
// console.log("copy", key); // console.log("copy", key);
const data: any = dest[key]; const data: any = dest[key];
@ -101,21 +109,26 @@ export function matchDataRecursive(dest: any, src: any, addNewKeys: any = false)
} }
} }
} }
if (addNewKeys) { if (addNewKeys) {
for (const key: any in src) { for (const key in src) {
if (!dest[key]) { if (!dest[key]) {
dest[key] = JSON.parse(JSON.stringify(src[key])); dest[key] = JSON.parse(JSON.stringify(src[key]));
} }
} }
} }
} }
export function updateApplicationLanguage(id: any): any {
export function updateApplicationLanguage(id: string): void {
logger.log("Setting application language:", id); logger.log("Setting application language:", id);
const data: any = LANGUAGES[id]; const data: any = LANGUAGES[id];
if (!data) { if (!data) {
logger.error("Unknown language:", id); logger.error("Unknown language:", id);
return; return;
} }
if (data.data) { if (data.data) {
logger.log("Applying translations ..."); logger.log("Applying translations ...");
matchDataRecursive(T, data.data); matchDataRecursive(T, data.data);