Translate all out-of-game UI (start screen, lobbies, etc.) (#316)

This PR adds full translation support for all out-of-game UI elements,
including the start screen, public/private lobby modals, and other
pre-game interfaces.

All static text has been externalized to en.json and ja.json for future
language support.
If you find any spots that are not yet translated (missing from the
JSON), please let me know.
Thanks a lot!

This is a follow-up to PR
[#305](https://github.com/openfrontio/OpenFrontIO/pull/305).

---------

Co-authored-by: Cldprv <dubois.cnm@tutanota.com>
Co-authored-by: jacks0n <rosty.west89@gmail.com>
This commit is contained in:
Aotumuri
2025-03-24 17:12:04 -07:00
committed by GitHub
co-authored by Cldprv jacks0n
parent f188af6029
commit 9088adeb7a
14 changed files with 845 additions and 215 deletions
+38 -13
View File
@@ -11,6 +11,7 @@ import "./components/Maps";
import randomMap from "../../resources/images/RandomMap.png";
import { GameInfo } from "../core/Schemas";
import { JoinLobbyEvent } from "./Main";
import { translateText } from "../client/Utils";
@customElement("single-player-modal")
export class SinglePlayerModal extends LitElement {
@@ -30,11 +31,11 @@ export class SinglePlayerModal extends LitElement {
render() {
return html`
<o-modal title="Single Player">
<o-modal title=${translateText("single_modal.title")}>
<div class="options-layout">
<!-- Map Selection -->
<div class="options-section">
<div class="option-title">Map</div>
<div class="option-title">${translateText("single_modal.map")}</div>
<div class="option-cards">
${Object.entries(GameMapType)
.filter(([key]) => isNaN(Number(key)))
@@ -49,6 +50,9 @@ export class SinglePlayerModal extends LitElement {
.mapKey=${key}
.selected=${!this.useRandomMap &&
this.selectedMap === value}
.translation=${translateText(
`map.${key.toLowerCase()}`,
)}
></map-display>
</div>
`,
@@ -66,14 +70,18 @@ export class SinglePlayerModal extends LitElement {
style="width:100%; aspect-ratio: 4/2; object-fit:cover; border-radius:8px;"
/>
</div>
<div class="option-card-title">Random</div>
<div class="option-card-title">
${translateText("map.random")}
</div>
</div>
</div>
</div>
<!-- Difficulty Selection -->
<div class="options-section">
<div class="option-title">Difficulty</div>
<div class="option-title">
${translateText("single_modal.difficulty")}
</div>
<div class="option-cards">
${Object.entries(Difficulty)
.filter(([key]) => isNaN(Number(key)))
@@ -89,7 +97,9 @@ export class SinglePlayerModal extends LitElement {
.difficultyKey=${key}
></difficulty-display>
<p class="option-card-title">
${DifficultyDescription[key]}
${translateText(
`difficulty.${DifficultyDescription[key]}`,
)}
</p>
</div>
`,
@@ -99,7 +109,9 @@ export class SinglePlayerModal extends LitElement {
<!-- Game Options -->
<div class="options-section">
<div class="option-title">Options</div>
<div class="option-title">
${translateText("single_modal.options_title")}
</div>
<div class="option-cards">
<label for="bots-count" class="option-card">
<input
@@ -113,7 +125,10 @@ export class SinglePlayerModal extends LitElement {
.value="${this.bots}"
/>
<div class="option-card-title">
Bots: ${this.bots == 0 ? "Disabled" : this.bots}
<span>${translateText("single_modal.bots")}</span>${this
.bots == 0
? translateText("single_modal.bots_disabled")
: this.bots}
</div>
</label>
@@ -128,7 +143,9 @@ export class SinglePlayerModal extends LitElement {
@change=${this.handleDisableNPCsChange}
.checked=${this.disableNPCs}
/>
<div class="option-card-title">Disable Nations</div>
<div class="option-card-title">
${translateText("single_modal.disable_nations")}
</div>
</label>
<label
for="instant-build"
@@ -141,7 +158,9 @@ export class SinglePlayerModal extends LitElement {
@change=${this.handleInstantBuildChange}
.checked=${this.instantBuild}
/>
<div class="option-card-title">Instant build</div>
<div class="option-card-title">
${translateText("single_modal.instant_build")}
</div>
</label>
<label
@@ -155,7 +174,9 @@ export class SinglePlayerModal extends LitElement {
@change=${this.handleInfiniteGoldChange}
.checked=${this.infiniteGold}
/>
<div class="option-card-title">Infinite gold</div>
<div class="option-card-title">
${translateText("single_modal.infinite_gold")}
</div>
</label>
<label
@@ -169,7 +190,9 @@ export class SinglePlayerModal extends LitElement {
@change=${this.handleInfiniteTroopsChange}
.checked=${this.infiniteTroops}
/>
<div class="option-card-title">Infinite troops</div>
<div class="option-card-title">
${translateText("single_modal.infinite_troops")}
</div>
</label>
<label
@@ -183,14 +206,16 @@ export class SinglePlayerModal extends LitElement {
@change=${this.handleDisableNukesChange}
.checked=${this.disableNukes}
/>
<div class="option-card-title">Disable Nukes</div>
<div class="option-card-title">
${translateText("single_modal.disable_nukes")}
</div>
</label>
</div>
</div>
</div>
<o-button
title="Start Game"
title=${translateText("single_modal.start")}
@click=${this.startGame}
blockDesktop
></o-button>