Overhaul language driver and move lang data to db

This commit is contained in:
Aelita4 2024-08-07 23:28:53 +02:00
parent 4db4cc97ad
commit 99f92ddbd1
Signed by: Aelita4
GPG Key ID: E44490C2025906C1
13 changed files with 141 additions and 67 deletions

View File

@ -1,5 +1,5 @@
--- ---
import { getHighestWeightedLanguage, getLocales } from '../lib/utils/langDriver'; import { getHighestWeightedLanguage, getLocales, getName } from '../lib/utils/langDriver';
interface Props { interface Props {
id: string; id: string;
@ -8,7 +8,7 @@ interface Props {
image: string; image: string;
} }
const lang = await getLocales(await getHighestWeightedLanguage(Astro.request.headers.get('accept-language')), ['resources', 'game', 'buildings', 'research']); const lang = await getLocales(await getHighestWeightedLanguage(Astro.request.headers.get('accept-language')));
--- ---
@ -17,7 +17,7 @@ const lang = await getLocales(await getHighestWeightedLanguage(Astro.request.hea
<div> <div>
<div class="building-card-name">{Astro.props.name}</div> <div class="building-card-name">{Astro.props.name}</div>
<div class="building-card-description">{Astro.props.description}</div> <div class="building-card-description">{Astro.props.description}</div>
<a id={`build_${Astro.props.id}`} href="#" class="building-card-build">{lang["game"]['Link_build']}</a> <a id={`build_${Astro.props.id}`} href="#" class="building-card-build">{getName(lang, "general", "nav-build")}</a>
<div class="building-card-info-button">i</div> <div class="building-card-info-button">i</div>
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
--- ---
import { getHighestWeightedLanguage, getLocales } from '../lib/utils/langDriver'; import { getHighestWeightedLanguage, getLocales, getName } from '../lib/utils/langDriver';
interface Props { interface Props {
loggedIn: string; loggedIn: string;
active: string; active: string;
@ -19,88 +19,88 @@ interface NavElement {
dropdowns?: Array<NavElement>; dropdowns?: Array<NavElement>;
} }
const lang = await getLocales(await getHighestWeightedLanguage(Astro.request.headers.get('accept-language')), ['navbar']); const lang = await getLocales(await getHighestWeightedLanguage(Astro.request.headers.get('accept-language')));
const listOfElements: Array<NavElement> = [{ const listOfElements: Array<NavElement> = [{
id: "home", id: "home",
title: lang["navbar"]["Link_home"], title: getName(lang, "general", "nav-home"),
type: "simple", type: "simple",
url: "/", url: "/",
show: "always", show: "always",
position: "top" position: "top"
}, { }, {
id: "about", id: "about",
title: lang["navbar"]["Link_about"], title: getName(lang, "general", "nav-about"),
type: "simple", type: "simple",
url: "#", url: "#",
show: "always", show: "always",
position: "top" position: "top"
}, { }, {
id: "api", id: "api",
title: lang["navbar"]["Link_api"], title: getName(lang, "general", "nav-api"),
type: "simple", type: "simple",
url: "#", url: "#",
show: "always", show: "always",
position: "top" position: "top"
}, { }, {
id: "login", id: "login",
title: lang["navbar"]["Link_login"], title: getName(lang, "general", "nav-login"),
type: "simple", type: "simple",
url: "/login", url: "/login",
show: "notLoggedInOnly", show: "notLoggedInOnly",
position: "bottom" position: "bottom"
}, { }, {
id: "register", id: "register",
title: lang["navbar"]["Link_register"], title: getName(lang, "general", "nav-register"),
type: "simple", type: "simple",
url: "/register", url: "/register",
show: "notLoggedInOnly", show: "notLoggedInOnly",
position: "bottom" position: "bottom"
},{ },{
id: "overview", id: "overview",
title: lang["navbar"]["Link_overview"], title: getName(lang, "general", "nav-overview"),
type: "simple", type: "simple",
url: "/game", url: "/game",
show: "loggedInOnly", show: "loggedInOnly",
position: "bottom" position: "bottom"
}, { }, {
id: "buildings", id: "buildings",
title: lang["navbar"]["Link_buildings"], title: getName(lang, "general", "nav-buildings"),
type: "simple", type: "simple",
url: "/game/buildings", url: "/game/buildings",
show: "loggedInOnly", show: "loggedInOnly",
position: "bottom" position: "bottom"
}, { }, {
id: "research", id: "research",
title: lang["navbar"]["Link_research"], title: getName(lang, "general", "nav-research"),
type: "simple", type: "simple",
url: "/game/research", url: "/game/research",
show: "loggedInOnly", show: "loggedInOnly",
position: "bottom" position: "bottom"
}, { }, {
id: "ships", id: "ships",
title: lang["navbar"]["Link_ships"], title: getName(lang, "general", "nav-ships"),
type: "simple", type: "simple",
url: "/game/ships", url: "/game/ships",
show: "loggedInOnly", show: "loggedInOnly",
position: "bottom" position: "bottom"
}, { }, {
id: "fleet", id: "fleet",
title: lang["navbar"]["Link_fleet"], title: getName(lang, "general", "nav-fleet"),
type: "simple", type: "simple",
url: "/game/fleet", url: "/game/fleet",
show: "loggedInOnly", show: "loggedInOnly",
position: "bottom" position: "bottom"
}, { }, {
id: "galaxyView", id: "galaxyView",
title: lang["navbar"]["Link_galaxyView"], title: getName(lang, "general", "nav-galaxy-view"),
type: "simple", type: "simple",
url: "/game/galaxyView", url: "/game/galaxyView",
show: "loggedInOnly", show: "loggedInOnly",
position: "bottom" position: "bottom"
}, { }, {
id: "profile", id: "profile",
title: lang["navbar"]["Link_profile"], title: getName(lang, "general", "nav-profile"),
type: "simple", type: "simple",
url: "/game/profile", url: "/game/profile",
show: "loggedInOnly", show: "loggedInOnly",

View File

@ -1,11 +1,11 @@
--- ---
import { ObjectId } from 'mongodb'; import { ObjectId } from 'mongodb';
import { calculateCurrentAvailableResources } from '../lib/utils/resourceManager'; import { calculateCurrentAvailableResources } from '../lib/utils/resourceManager';
import { getHighestWeightedLanguage, getLocales } from '../lib/utils/langDriver'; import { getHighestWeightedLanguage, getLocales, getName } from '../lib/utils/langDriver';
import resourceTypes from '../lib/data/resources.json'; import resourceTypes from '../lib/data/resources.json';
const lang = await getLocales(await getHighestWeightedLanguage(Astro.request.headers.get('accept-language')), ['resourcebar', 'resources']); const lang = await getLocales(await getHighestWeightedLanguage(Astro.request.headers.get('accept-language')));
const resources = await calculateCurrentAvailableResources(new ObjectId(Astro.cookies.get('planetid')?.value ?? '')); const resources = await calculateCurrentAvailableResources(new ObjectId(Astro.cookies.get('planetid')?.value ?? ''));
@ -13,6 +13,7 @@ const resourceArray = [];
for(const key in resources) { for(const key in resources) {
resourceArray.push(resources[key as never]); resourceArray.push(resources[key as never]);
} }
--- ---
<div id="resourcebar"> <div id="resourcebar">
<div class="resourcebar-item-identifier"> <div class="resourcebar-item-identifier">
@ -30,13 +31,13 @@ for(const key in resources) {
<img src={resourceTypes.find(x => x.name === res.name)?.icon ?? "#"} alt={res.name} /> <img src={resourceTypes.find(x => x.name === res.name)?.icon ?? "#"} alt={res.name} />
</div> </div>
<div class="resourcebar-item-text-wrapper" data-resname={res.name}> <div class="resourcebar-item-text-wrapper" data-resname={res.name}>
<div class="resourcebar-item-text">{lang["resources"][`Label_${res.name}`]}</div> <div class="resourcebar-item-text">{getName(lang, 'resources', res.name)}</div>
<div class="resourcebar-item-amount">[fetching]</div> <div class="resourcebar-item-amount">[fetching]</div>
</div> </div>
<div class="resourcebar-item-tooltip"> <div class="resourcebar-item-tooltip">
<div class="resourcebar-item-tooltip-name">{lang["resourcebar"]['Label_avaliable']} - <span class="resourcebar-item-tooltip-avaliable">{Math.floor(res.amount).toString()}</span></div> <div class="resourcebar-item-tooltip-name">{getName(lang, 'general', 'avaliable')} - <span class="resourcebar-item-tooltip-avaliable">{Math.floor(res.amount).toString()}</span></div>
<div class="resourcebar-item-tooltip-name">{lang["resourcebar"]['Label_production']} - <span class="resourcebar-item-tooltip-production">{res.perHourMiningRate.toString()}</span></div> <div class="resourcebar-item-tooltip-name">{getName(lang, 'general', 'production')} - <span class="resourcebar-item-tooltip-production">{res.perHourMiningRate.toString()}</span></div>
<div class="resourcebar-item-tooltip-name">{lang["resourcebar"]['Label_capacity']} - <span class="resourcebar-item-tooltip-capacity">{'21372137'}</span></div> <div class="resourcebar-item-tooltip-name">{getName(lang, 'general', 'capacity')} - <span class="resourcebar-item-tooltip-capacity">{'21372137'}</span></div>
</div> </div>
</div> </div>
)} )}

View File

@ -137,6 +137,8 @@
"iron": 1000, "iron": 1000,
"gold": 500 "gold": 500
} }
} },
"time": 3000,
"multiplier": 5
} }
] ]

12
src/lib/db/lang.ts Normal file
View File

@ -0,0 +1,12 @@
import { Lang } from "./mongodb";
export const getLang = async (language = "en") => {
const lang = await Lang(language);
return {
general: await lang[0].find({}).toArray(),
buildings: await lang[1].find({}).toArray(),
ships: await lang[2].find({}).toArray(),
resources: await lang[3].find({}).toArray(),
research: await lang[4].find({}).toArray()
}
}

View File

@ -2,7 +2,6 @@ import { MongoClient } from "mongodb";
import config from '../../../config.json' import config from '../../../config.json'
const uri = config.MONGODB_URI; const uri = config.MONGODB_URI;
const dbName = config.MONGODB_DB;
const options = {}; const options = {};
const mongo = new MongoClient(uri, options); const mongo = new MongoClient(uri, options);
@ -16,7 +15,7 @@ export const disconnect = async () => {
mongo.close(); mongo.close();
} }
export const getDB = async () => { export const getDB = async (dbName = config.MONGODB_DB) => {
await connect(); await connect();
return mongo.db(dbName); return mongo.db(dbName);
} }
@ -35,3 +34,14 @@ export const Planets = async () => {
const db = await getDB(); const db = await getDB();
return db.collection('planets'); return db.collection('planets');
} }
export const Lang = async (language = "en") => {
const db = await getDB(`${config.MONGODB_DB}_${language}`);
return [
await db.collection('general'),
await db.collection('buildings'),
await db.collection('ships'),
await db.collection('resources'),
await db.collection('research')
]
}

View File

@ -1,5 +1,7 @@
import { GET as langs } from '../../pages/api/lang.json';
export async function getSupportedLanguages() { export async function getSupportedLanguages() {
const metadata: [] = await (await fetch('http://localhost:4321/lang/metadata.json')).json(); const metadata: { id: string, name: string }[] = await (await langs()).json();
const response: Array<string> = []; const response: Array<string> = [];
@ -32,23 +34,21 @@ export async function getHighestWeightedLanguage(header: string | null): Promise
return highestWeightedLang; return highestWeightedLang;
} }
export async function getLocales(language: string, types: string[]) { export async function getLocales(language: string) {
if(!(await getSupportedLanguages()).includes(language)) { if(!(await getSupportedLanguages()).includes(language)) {
console.log(await getSupportedLanguages(), language) console.log(await getSupportedLanguages(), language)
return null; return null;
} }
const out: any = {}; const lang = await (await fetch(`http://localhost:4321/api/lang/${language}.json`)).json();
for(const type of types) { return lang.data;
const lang = await (await fetch(`http://localhost:4321/lang/${language}/${type}.json`)).json();
out[type] = {};
for(const category in lang) {
for(const element in lang[category]) {
out[type][`${category}_${element}`] = lang[category][element];
}
}
} }
return out; export function getName(locale: { [key: string]: { id: string, name: string }[] }, type: string, name: string) {
return locale[type].find((element: { id: string }) => element.id === name)?.name ?? `NTL_${name}`;
}
export function getObj(locale: { [key: string]: { id: string, name: string, description: string | null }[] }, type: string, name: string) {
return locale[type].find((element: { id: string }) => element.id === name) ?? { id: name, name: `NTL_${name}`, description: `NTL_${name}` };
} }

View File

@ -0,0 +1,14 @@
export async function GET() {
return new Response(
JSON.stringify([
{
"id": "en",
"name": "English"
},
{
"id": "pl",
"name": "Polish"
}
]),
)
}

View File

@ -0,0 +1,35 @@
import type { APIRoute } from 'astro';
import { GET as langs } from '../lang.json';
import { getLang } from '../../../lib/db/lang';
const supportedLanguages: { id: string, name: string }[] = await (await langs()).json();
export const GET: APIRoute = async ({ params, request }) => {
const id = params.id;
if (!supportedLanguages.find(lang => lang.id === id)) {
return new Response(
JSON.stringify({
code: 404,
message: "Language not found"
}), { status: 404 }
)
}
const lang = await getLang(id);
if (!lang) {
return new Response(
JSON.stringify({
code: 500,
message: "Internal Server Error"
}), { status: 500 }
)
}
return new Response(
JSON.stringify({
code: 200,
message: "OK",
data: lang
})
)
}

View File

@ -3,7 +3,7 @@ import Layout from '../../layouts/Layout.astro';
import NavBar from '../../components/NavBar.astro'; import NavBar from '../../components/NavBar.astro';
import BuildingCard from '../../components/BuildingCard.astro'; import BuildingCard from '../../components/BuildingCard.astro';
import { getUserByAccessToken } from '../../lib/db/users'; import { getUserByAccessToken } from '../../lib/db/users';
import { getHighestWeightedLanguage, getLocales } from '../../lib/utils/langDriver'; import { getHighestWeightedLanguage, getLocales, getObj } from '../../lib/utils/langDriver';
import ResourceBar from '../../components/ResourceBar.astro'; import ResourceBar from '../../components/ResourceBar.astro';
const buildingsList = (await import('../../lib/data/buildings.json')).default; const buildingsList = (await import('../../lib/data/buildings.json')).default;
@ -17,7 +17,7 @@ if(checkUser === null || checkUser.username !== username) return Astro.redirect(
const locale = await getHighestWeightedLanguage(Astro.request.headers.get('accept-language')); const locale = await getHighestWeightedLanguage(Astro.request.headers.get('accept-language'));
const lang = await getLocales(locale, ['resources', 'game', 'buildings', 'research']); const lang = await getLocales(locale);
const modalSet: { [key: string]: { resources: Array<any>, research: Array<any>, buildings: Array<any>, energy: number } } = {}; const modalSet: { [key: string]: { resources: Array<any>, research: Array<any>, buildings: Array<any>, energy: number } } = {};
@ -55,8 +55,8 @@ buildingsList.forEach(cat => {
<div class="building-cat"> <div class="building-cat">
{cat.buildings.map(building => <BuildingCard {cat.buildings.map(building => <BuildingCard
id={building.id} id={building.id}
name={lang["buildings"][`Label_${building.id}`].name} name={getObj(lang, "buildings", building.id).name}
description={lang["buildings"][`Label_${building.id}`].description} description={getObj(lang, "buildings", building.id).description ?? ""}
image="/favicon.svg" />)} image="/favicon.svg" />)}
</div> </div>
</div> </div>

View File

@ -2,7 +2,7 @@
import Layout from '../../layouts/Layout.astro'; import Layout from '../../layouts/Layout.astro';
import NavBar from '../../components/NavBar.astro'; import NavBar from '../../components/NavBar.astro';
import { getUserByAccessToken, getUserByNickOrEmail } from '../../lib/db/users'; import { getUserByAccessToken, getUserByNickOrEmail } from '../../lib/db/users';
import { getHighestWeightedLanguage, getLocales } from '../../lib/utils/langDriver'; import { getHighestWeightedLanguage, getLocales, getName } from '../../lib/utils/langDriver';
import ResourceBar from '../../components/ResourceBar.astro'; import ResourceBar from '../../components/ResourceBar.astro';
import format from '../../lib/utils/format'; import format from '../../lib/utils/format';
@ -17,7 +17,7 @@ const locale = await getHighestWeightedLanguage(Astro.request.headers.get('accep
const user = await getUserByNickOrEmail(username); const user = await getUserByNickOrEmail(username);
const lang = await getLocales(locale, ['game']); const lang = await getLocales(locale);
--- ---
<Layout title="Profile"> <Layout title="Profile">
@ -25,24 +25,24 @@ const lang = await getLocales(locale, ['game']);
<ResourceBar loggedIn="true" /> <ResourceBar loggedIn="true" />
<div class="wrapper"> <div class="wrapper">
<h3>{format(lang["game"]['Label_userCreationDate'], user?.createdAt.toISOString().slice(0, 19).replace(/-/g, "/").replace("T", " ").toString() ?? "")}</h3> <h3>{format(getName(lang, 'general', 'user-creation-date'), user?.createdAt.toISOString().slice(0, 19).replace(/-/g, "/").replace("T", " ").toString() ?? "")}</h3>
<a href="/logout" class="a-button">{lang["game"]['Link_logout']}</a> <a href="/logout" class="a-button">{getName(lang, 'general', 'nav-logout')}</a>
</div> </div>
<form id="changeUsernameForm" class="data-form"> <form id="changeUsernameForm" class="data-form">
<input class="data-form-input" type="text" name="username" placeholder={lang["game"]['Label_newUsernamePlaceholder']} /> <input class="data-form-input" type="text" name="username" placeholder={getName(lang, 'general', 'input-placeholder-new-username')} />
<input class="data-form-input" type="password" name="password" placeholder={lang["game"]['Label_passwordPlaceholder']} /> <input class="data-form-input" type="password" name="password" placeholder={getName(lang, 'general', 'input-placeholder-password')} />
<input class="data-form-button" type="button" value={lang["game"]['Link_changeUsername']} /> <input class="data-form-button" type="button" value={getName(lang, 'general', 'change-username')} />
</form> </form>
<form id="changeEmailForm" class="data-form"> <form id="changeEmailForm" class="data-form">
<input class="data-form-input" type="email" name="email" placeholder={lang["game"]['Label_newEmailPlaceholder']} /> <input class="data-form-input" type="email" name="email" placeholder={getName(lang, 'general', 'input-placeholder-new-email')} />
<input class="data-form-input" type="password" name="password" placeholder={lang["game"]['Label_passwordPlaceholder']} /> <input class="data-form-input" type="password" name="password" placeholder={getName(lang, 'general', 'input-placeholder-password')} />
<input class="data-form-button" type="button" value={lang["game"]['Link_changeEmail']} /> <input class="data-form-button" type="button" value={getName(lang, 'general', 'change-email')} />
</form> </form>
<form id="changePasswordForm" class="data-form"> <form id="changePasswordForm" class="data-form">
<input class="data-form-input" type="password" name="oldPassword" placeholder={lang["game"]['Label_oldPasswordPlaceholder']} /> <input class="data-form-input" type="password" name="oldPassword" placeholder={getName(lang, 'general', 'input-placeholder-old-password')} />
<input class="data-form-input" type="password" name="password1" placeholder={lang["game"]['Label_newPasswordPlaceholder']} /> <input class="data-form-input" type="password" name="password1" placeholder={getName(lang, 'general', 'input-placeholder-new-password')} />
<input class="data-form-input" type="password" name="password2" placeholder={lang["game"]['Label_newPasswordVerifyPlaceholder']} /> <input class="data-form-input" type="password" name="password2" placeholder={getName(lang, 'general', 'input-placeholder-new-password-verify')} />
<input class="data-form-button" type="button" value={lang["game"]['Link_changePassword']} /> <input class="data-form-button" type="button" value={getName(lang, 'general', 'change-password')} />
</form> </form>
</Layout> </Layout>

View File

@ -4,7 +4,7 @@ import { Icon } from 'astro-icon/components'
import Layout from '../../layouts/Layout.astro'; import Layout from '../../layouts/Layout.astro';
import NavBar from '../../components/NavBar.astro'; import NavBar from '../../components/NavBar.astro';
import { getUserByAccessToken } from '../../lib/db/users'; import { getUserByAccessToken } from '../../lib/db/users';
import { getHighestWeightedLanguage, getLocales } from '../../lib/utils/langDriver'; import { getHighestWeightedLanguage, getLocales, getName, getObj } from '../../lib/utils/langDriver';
import ResourceBar from '../../components/ResourceBar.astro'; import ResourceBar from '../../components/ResourceBar.astro';
type ResearchDetail = { id: string, level: number, requiredResearch: { id: string, level: number}[], cost: { [key: string]: number } }; type ResearchDetail = { id: string, level: number, requiredResearch: { id: string, level: number}[], cost: { [key: string]: number } };
@ -20,7 +20,7 @@ if(checkUser === null || checkUser.username !== username) return Astro.redirect(
const locale = await getHighestWeightedLanguage(Astro.request.headers.get('accept-language')); const locale = await getHighestWeightedLanguage(Astro.request.headers.get('accept-language'));
const lang = await getLocales(locale, ['game', 'resources', 'buildings', 'research']); const lang = await getLocales(locale);
const researchDetails: ResearchDetail[] = []; //TODO: Add union type for cost keys const researchDetails: ResearchDetail[] = []; //TODO: Add union type for cost keys
researchList.forEach(element => { researchList.forEach(element => {
@ -45,21 +45,21 @@ researchList.forEach(element => {
{researchDetails.map(research => ( {researchDetails.map(research => (
<div class="research-card"> <div class="research-card">
<h2>{lang["research"][`Label_${research.id}`].name}</h2> <h2>{getObj(lang, "research", research.id).name}</h2>
<div class="research-card-wrapper"> <div class="research-card-wrapper">
<div class="research-image"></div> <div class="research-image"></div>
{lang["research"][`Label_${research.id}`].description}<br /> {getObj(lang, "research", research.id).description}<br />
<a id={`research_${research.id}`} href="#" class="a-button">{lang["game"]['Link_research']}</a> <a id={`research_${research.id}`} href="#" class="a-button">{getName(lang, "general", "nav-research")}</a>
<div class="research-req-icon"> <div class="research-req-icon">
<Icon class="research-req-icon-proper" name="mdi:help" /> <Icon class="research-req-icon-proper" name="mdi:help" />
<div class="research-req-tooltip"> <div class="research-req-tooltip">
<div>{lang["research"]['Label_required']}:</div> <div>{getName(lang, "general", "required")}:</div>
{research.requiredResearch.length !== 0 ? research.requiredResearch.map(req => ( {research.requiredResearch.length !== 0 ? research.requiredResearch.map(req => (
<div> <div>
{lang["research"][`Label_${req.id}`].name} - {req.level} {getObj(lang, "research", req.id).name} - {req.level}
</div> </div>
)) : lang["research"]['Label_none']} )) : getName(lang, "general", "none")}
</div> </div>
</div> </div>
</div> </div>
@ -68,7 +68,7 @@ researchList.forEach(element => {
</div> </div>
<div class="research-cost-wrapper"> <div class="research-cost-wrapper">
{Object.entries(research.cost).map(([key, value]) => <div> {Object.entries(research.cost).map(([key, value]) => <div>
{lang["resources"][`Label_${key}`]}: {value} || {getName(lang, "resources", key)}: {value} ||
</div>)} </div>)}
</div> </div>
</div> </div>

View File

@ -20,7 +20,7 @@ const planet = await getPlanetById(new ObjectId(Astro.cookies.get('planetid')?.v
if(!planet) return; if(!planet) return;
const lang = await getLocales(await getHighestWeightedLanguage(Astro.request.headers.get('accept-language')), ['ships']); const lang = await getLocales(await getHighestWeightedLanguage(Astro.request.headers.get('accept-language')));
--- ---
<Layout title="Ships"> <Layout title="Ships">