mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-08 09:22:17 +02:00
create utils-plugins.ts and more docs
This commit is contained in:
parent
e63157717d
commit
26772fa851
@ -4,7 +4,7 @@ import LanguageDetector from "i18next-browser-languagedetector";
|
|||||||
import HttpBackend from "i18next-http-backend";
|
import HttpBackend from "i18next-http-backend";
|
||||||
import processor, { KoreanPostpositionProcessor } from "i18next-korean-postposition-processor";
|
import processor, { KoreanPostpositionProcessor } from "i18next-korean-postposition-processor";
|
||||||
import pkg from "../../package.json";
|
import pkg from "../../package.json";
|
||||||
import { namespaceMap } from "./namespacemap";
|
import { namespaceMap } from "./utils-plugins";
|
||||||
|
|
||||||
//#region Interfaces/Types
|
//#region Interfaces/Types
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ export async function initI18n(): Promise<void> {
|
|||||||
*
|
*
|
||||||
* Q: How do I add a new namespace?
|
* Q: How do I add a new namespace?
|
||||||
* A: To add a new namespace, create a new file .json in each language folder with the translations.
|
* A: To add a new namespace, create a new file .json in each language folder with the translations.
|
||||||
* The expected format for the files is kebab-case {@link https://developer.mozilla.org/en-US/docs/Glossary/Kebab_case}
|
* The expected format for the file-name is kebab-case {@link https://developer.mozilla.org/en-US/docs/Glossary/Kebab_case}
|
||||||
* If you want the namespace name to be different from the file name, configure it in namespacemap.ts.
|
* If you want the namespace name to be different from the file name, configure it in namespacemap.ts.
|
||||||
* Then update the config file for that language in its locale directory
|
* Then update the config file for that language in its locale directory
|
||||||
* and the CustomTypeOptions interface in the @types/i18next.d.ts file.
|
* and the CustomTypeOptions interface in the @types/i18next.d.ts file.
|
||||||
@ -161,7 +161,7 @@ export async function initI18n(): Promise<void> {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaultNS: "menu",
|
defaultNS: "menu",
|
||||||
ns: nsEn, // assign with namespaces-i18n-plugin.ts
|
ns: nsEn, // assigned with #app/plugins/vite/namespaces-i18n-plugin.ts
|
||||||
detection: {
|
detection: {
|
||||||
lookupLocalStorage: "prLang"
|
lookupLocalStorage: "prLang"
|
||||||
},
|
},
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
// When changing the file, the server restarts because of the namespaces-18n-plugin.ts
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ### maps namespaces that deviate from the file-name
|
|
||||||
* @description expects file-name as value and custom-namespace as key
|
|
||||||
* */
|
|
||||||
export const namespaceMap = {
|
|
||||||
titles: "trainer-titles",
|
|
||||||
moveTriggers: "move-trigger",
|
|
||||||
abilityTriggers: "ability-trigger",
|
|
||||||
battlePokemonForm: "pokemon-form-battle",
|
|
||||||
miscDialogue: "dialogue-misc",
|
|
||||||
battleSpecDialogue: "dialogue-final-boss",
|
|
||||||
doubleBattleDialogue: "dialogue-double-battle",
|
|
||||||
splashMessages: "splash-texts",
|
|
||||||
mysteryEncounterMessages: "mystery-encounter-texts",
|
|
||||||
};
|
|
49
src/plugins/utils-plugins.ts
Normal file
49
src/plugins/utils-plugins.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import path from "path"; // vite externalize in production, see https://vite.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ### maps namespaces that deviate from the file-name
|
||||||
|
* @description expects file-name as value and custom-namespace as key
|
||||||
|
* */
|
||||||
|
export const namespaceMap = {
|
||||||
|
titles: "trainer-titles",
|
||||||
|
moveTriggers: "move-trigger",
|
||||||
|
abilityTriggers: "ability-trigger",
|
||||||
|
battlePokemonForm: "pokemon-form-battle",
|
||||||
|
miscDialogue: "dialogue-misc",
|
||||||
|
battleSpecDialogue: "dialogue-final-boss",
|
||||||
|
doubleBattleDialogue: "dialogue-double-battle",
|
||||||
|
splashMessages: "splash-texts",
|
||||||
|
mysteryEncounterMessages: "mystery-encounter-texts",
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms a kebab-case string into a camelCase string
|
||||||
|
* @param str The kebabCase string
|
||||||
|
* @returns A camelCase string
|
||||||
|
*
|
||||||
|
* @source {@link https://stackoverflow.com/a/23013726}
|
||||||
|
*/
|
||||||
|
export function kebabCaseToCamelCase(str: string): string {
|
||||||
|
return str.replace(/-./g, (x)=> x[1].toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swap the value with the key and the key with the value
|
||||||
|
* @param json type {[key: string]: string}
|
||||||
|
* @returns [value]: key
|
||||||
|
*
|
||||||
|
* @source {@link https://stackoverflow.com/a/23013726}
|
||||||
|
*/
|
||||||
|
export function objectSwap(json: {[key: string]: string}): {[value: string]: string} {
|
||||||
|
const ret = {};
|
||||||
|
for (const key in json) {
|
||||||
|
ret[json[key]] = key;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isFileInsideDir(file, dir) {
|
||||||
|
const filePath = path.normalize(file);
|
||||||
|
const dirPath = path.normalize(dir);
|
||||||
|
return filePath.startsWith(dirPath);
|
||||||
|
}
|
@ -1,12 +1,16 @@
|
|||||||
import { normalizePath, type Plugin as VitePlugin } from "vite";
|
import { normalizePath, type Plugin as VitePlugin } from "vite";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { namespaceMap } from "../namespacemap";
|
import * as Utils from "../utils-plugins";
|
||||||
import { kebabCaseToCamelCase, objectSwap } from "../../utils";
|
|
||||||
|
|
||||||
const namespaceMapSwap = objectSwap(namespaceMap);
|
const namespaceMapSwap = Utils.objectSwap(Utils.namespaceMap);
|
||||||
|
/**
|
||||||
function getNameSpaces(dir: string) {
|
* Crawl a directory recursively for json files to returns her name with camelCase format...
|
||||||
|
* Also if file is in directory returns format "dir/fileName" format
|
||||||
|
* @param dir the directory to crawl
|
||||||
|
* @returns {string[]}
|
||||||
|
*/
|
||||||
|
function getNameSpaces(dir: string): string[] {
|
||||||
const namespace: string[] = [];
|
const namespace: string[] = [];
|
||||||
const files = fs.readdirSync(dir);
|
const files = fs.readdirSync(dir);
|
||||||
|
|
||||||
@ -20,13 +24,13 @@ function getNameSpaces(dir: string) {
|
|||||||
let ns = subnamespace[i];
|
let ns = subnamespace[i];
|
||||||
if (namespaceMapSwap[file.replace(".json", "")]) {
|
if (namespaceMapSwap[file.replace(".json", "")]) {
|
||||||
ns = namespaceMapSwap[file.replace(".json", "")];
|
ns = namespaceMapSwap[file.replace(".json", "")];
|
||||||
} else if (kebabCaseToCamelCase(file).replace(".json", "").startsWith("mysteryEncounters")) {
|
} else if (Utils.kebabCaseToCamelCase(file).replace(".json", "").startsWith("mysteryEncounters")) {
|
||||||
ns = subnamespace[i].replace(/Dialogue$/, "");
|
ns = subnamespace[i].replace(/Dialogue$/, "");
|
||||||
}
|
}
|
||||||
namespace.push(`${kebabCaseToCamelCase(file).replace(".json", "")}/${ns}`);
|
namespace.push(`${Utils.kebabCaseToCamelCase(file).replace(".json", "")}/${ns}`);
|
||||||
}
|
}
|
||||||
} else if (path.extname(file) === ".json") {
|
} else if (path.extname(file) === ".json") {
|
||||||
let ns = kebabCaseToCamelCase(file).replace(".json", "");
|
let ns = Utils.kebabCaseToCamelCase(file).replace(".json", "");
|
||||||
if (namespaceMapSwap[file.replace(".json", "")]) {
|
if (namespaceMapSwap[file.replace(".json", "")]) {
|
||||||
ns = namespaceMapSwap[file.replace(".json", "")];
|
ns = namespaceMapSwap[file.replace(".json", "")];
|
||||||
}
|
}
|
||||||
@ -37,41 +41,41 @@ function getNameSpaces(dir: string) {
|
|||||||
return namespace;
|
return namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isFileInsideDir(file, dir) {
|
|
||||||
const filePath = path.normalize(file);
|
|
||||||
const dirPath = path.normalize(dir);
|
|
||||||
return filePath.startsWith(dirPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function LocaleNamespace(): VitePlugin {
|
export function LocaleNamespace(): VitePlugin {
|
||||||
const nsLocation = "./public/locales";
|
const nsRelativePath = "./public/locales";
|
||||||
const nsEn = `${nsLocation}/en`; // Default namespace
|
const nsEn = `${nsRelativePath}/en`; // Default namespace
|
||||||
let namespaces = getNameSpaces(nsEn);
|
let namespaces = getNameSpaces(nsEn);
|
||||||
// const nsEnRegex = new RegExp(`^${nsEn.replace(/\//g, "\\/")}.*\\.json$`);
|
const nsAbsolutePath = path.resolve(process.cwd(), nsRelativePath);
|
||||||
const nsAbsolutePath = path.resolve(process.cwd(), nsLocation); // Convert to absolute path
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: "namespaces-i18next",
|
name: "namespaces-i18next",
|
||||||
buildStart() {
|
buildStart() {
|
||||||
if (process.env.NODE_ENV === "production") {
|
if (process.env.NODE_ENV === "production") {
|
||||||
console.log("Assign namespace to constant nsEn");
|
console.log("Collect namespaces");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
configureServer(server) {
|
configureServer(server) {
|
||||||
const restartHandler = async (file, action: string) => {
|
const restartHandler = async (file, action: string) => {
|
||||||
if (isFileInsideDir(file, nsAbsolutePath) && file.endsWith(".json")) {
|
/**
|
||||||
|
* If any JSON file in {@linkcode nsLocation} is created/modified..
|
||||||
|
* refresh the page to update the namespaces of i18next
|
||||||
|
*/
|
||||||
|
if (Utils.isFileInsideDir(file, nsAbsolutePath) && file.endsWith(".json")) {
|
||||||
console.log(`\x1b[34m${normalizePath(file.replace(nsAbsolutePath, ""))}\x1b[0m ${action}, reloading page...`);
|
console.log(`\x1b[34m${normalizePath(file.replace(nsAbsolutePath, ""))}\x1b[0m ${action}, reloading page...`);
|
||||||
|
|
||||||
namespaces = await getNameSpaces(nsEn);
|
namespaces = await getNameSpaces(nsEn);
|
||||||
await server.moduleGraph.invalidateAll();
|
await server.moduleGraph.invalidateAll();
|
||||||
await server.ws.send({
|
await server.ws.send({
|
||||||
type: "full-reload",
|
type: "full-reload"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
server.watcher.on("change", (file) => restartHandler(file, "updated"));
|
|
||||||
server.watcher.on("add", (file) => restartHandler(file, "added"));
|
server.watcher
|
||||||
server.watcher.on("unlink", (file) => restartHandler(file, "removed"));
|
.on("change", (file) => restartHandler(file, "updated"))
|
||||||
|
.on("add", (file) => restartHandler(file, "added"))
|
||||||
|
.on("unlink", (file) => restartHandler(file, "removed"));
|
||||||
},
|
},
|
||||||
transform: {
|
transform: {
|
||||||
handler(code, id) {
|
handler(code, id) {
|
||||||
|
47
src/utils.ts
47
src/utils.ts
@ -1,8 +1,7 @@
|
|||||||
// So that the utils.ts is also accessible to plugins/vite, it's important that the paths are relative and not aliases ..
|
import { MoneyFormat } from "#enums/money-format";
|
||||||
// Although, due to this, any change made to the file will cause a server restart
|
import { Moves } from "#enums/moves";
|
||||||
import { MoneyFormat } from "./enums/money-format";
|
|
||||||
import { Moves } from "./enums/moves";
|
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
import * as plugins from "./plugins/utils-plugins";
|
||||||
|
|
||||||
export type nil = null | undefined;
|
export type nil = null | undefined;
|
||||||
|
|
||||||
@ -272,23 +271,23 @@ export function executeIf<T>(condition: boolean, promiseFunc: () => Promise<T>):
|
|||||||
export const sessionIdKey = "pokerogue_sessionId";
|
export const sessionIdKey = "pokerogue_sessionId";
|
||||||
// Check if the current hostname is 'localhost' or an IP address, and ensure a port is specified
|
// Check if the current hostname is 'localhost' or an IP address, and ensure a port is specified
|
||||||
export const isLocal = (
|
export const isLocal = (
|
||||||
(globalThis.location?.hostname === "localhost" ||
|
(window.location.hostname === "localhost" ||
|
||||||
/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/.test(globalThis.location?.hostname)) &&
|
/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/.test(window.location.hostname)) &&
|
||||||
globalThis.location?.port !== "") || globalThis.location?.hostname === "";
|
window.location.port !== "") || window.location.hostname === "";
|
||||||
|
|
||||||
export const localServerUrl = import.meta.env?.VITE_SERVER_URL ?? `http://${globalThis.location?.hostname}:${globalThis.location?.port + 1}`;
|
export const localServerUrl = import.meta.env.VITE_SERVER_URL ?? `http://${window.location.hostname}:${window.location.port + 1}`;
|
||||||
|
|
||||||
// Set the server URL based on whether it's local or not
|
// Set the server URL based on whether it's local or not
|
||||||
export const apiUrl = localServerUrl ?? "https://api.pokerogue.net";
|
export const apiUrl = localServerUrl ?? "https://api.pokerogue.net";
|
||||||
// used to disable api calls when isLocal is true and a server is not found
|
// used to disable api calls when isLocal is true and a server is not found
|
||||||
export let isLocalServerConnected = true;
|
export let isLocalServerConnected = true;
|
||||||
|
|
||||||
export const isBeta = import.meta.env?.MODE === "beta"; // this checks to see if the env mode is development. Technically this gives the same value for beta AND for dev envs
|
export const isBeta = import.meta.env.MODE === "beta"; // this checks to see if the env mode is development. Technically this gives the same value for beta AND for dev envs
|
||||||
|
|
||||||
export function setCookie(cName: string, cValue: string): void {
|
export function setCookie(cName: string, cValue: string): void {
|
||||||
const expiration = new Date();
|
const expiration = new Date();
|
||||||
expiration.setTime(new Date().getTime() + 3600000 * 24 * 30 * 3/*7*/);
|
expiration.setTime(new Date().getTime() + 3600000 * 24 * 30 * 3/*7*/);
|
||||||
document.cookie = `${cName}=${cValue};Secure;SameSite=Strict;Domain=${globalThis.location.hostname};Path=/;Expires=${expiration.toUTCString()}`;
|
document.cookie = `${cName}=${cValue};Secure;SameSite=Strict;Domain=${window.location.hostname};Path=/;Expires=${expiration.toUTCString()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeCookie(cName: string): void {
|
export function removeCookie(cName: string): void {
|
||||||
@ -296,7 +295,7 @@ export function removeCookie(cName: string): void {
|
|||||||
document.cookie = `${cName}=;Secure;SameSite=Strict;Domain=pokerogue.net;Path=/;Max-Age=-1`; // we need to remove the cookie from the main domain as well
|
document.cookie = `${cName}=;Secure;SameSite=Strict;Domain=pokerogue.net;Path=/;Max-Age=-1`; // we need to remove the cookie from the main domain as well
|
||||||
}
|
}
|
||||||
|
|
||||||
document.cookie = `${cName}=;Secure;SameSite=Strict;Domain=${globalThis.location.hostname};Path=/;Max-Age=-1`;
|
document.cookie = `${cName}=;Secure;SameSite=Strict;Domain=${window.location.hostname};Path=/;Max-Age=-1`;
|
||||||
document.cookie = `${cName}=;Secure;SameSite=Strict;Path=/;Max-Age=-1`; // legacy cookie without domain, for older cookies to prevent a login loop
|
document.cookie = `${cName}=;Secure;SameSite=Strict;Path=/;Max-Age=-1`; // legacy cookie without domain, for older cookies to prevent a login loop
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -654,28 +653,4 @@ export function camelCaseToKebabCase(str: string): string {
|
|||||||
return str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, (s, o) => (o ? "-" : "") + s.toLowerCase());
|
return str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, (s, o) => (o ? "-" : "") + s.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export { plugins };
|
||||||
* Transforms a kebab-case string into a camelCase string
|
|
||||||
* @param str The kebabCase string
|
|
||||||
* @returns A camelCase string
|
|
||||||
*
|
|
||||||
* @source {@link https://stackoverflow.com/a/23013726}
|
|
||||||
*/
|
|
||||||
export function kebabCaseToCamelCase(str: string): string {
|
|
||||||
return str.replace(/-./g, (x)=> x[1].toUpperCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Swap the value with the key and the key with the value
|
|
||||||
* @param json type {[key: string]: string}
|
|
||||||
* @returns [value]: key
|
|
||||||
*
|
|
||||||
* @source {@link https://stackoverflow.com/a/23013726}
|
|
||||||
*/
|
|
||||||
export function objectSwap(json: {[key: string]: string}): {[value: string]: string} {
|
|
||||||
const ret = {};
|
|
||||||
for (const key in json) {
|
|
||||||
ret[json[key]] = key;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user