mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-03 19:50:42 +00:00
Add localization support for game events, settings, and UI text elements (#1372)
## Description: This PR adds missing translations for various UI components, including game events and settings. No visual changes were made, so screenshots are not required. All user-facing text has been properly localized and added to the en.json file. ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: pierogi69 --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
@@ -412,16 +412,18 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
) as PlayerView;
|
||||
|
||||
this.addEvent({
|
||||
description: `${requestor.name()} requests an alliance!`,
|
||||
description: translateText("events_display.request_alliance", {
|
||||
name: requestor.name(),
|
||||
}),
|
||||
buttons: [
|
||||
{
|
||||
text: "Focus",
|
||||
text: translateText("events_display.focus"),
|
||||
className: "btn-gray",
|
||||
action: () => this.eventBus.emit(new GoToPlayerEvent(requestor)),
|
||||
preventClose: true,
|
||||
},
|
||||
{
|
||||
text: "Accept",
|
||||
text: translateText("events_display.accept_alliance"),
|
||||
className: "btn",
|
||||
action: () =>
|
||||
this.eventBus.emit(
|
||||
@@ -429,7 +431,7 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
),
|
||||
},
|
||||
{
|
||||
text: "Reject",
|
||||
text: translateText("events_display.reject_alliance"),
|
||||
className: "btn-info",
|
||||
action: () =>
|
||||
this.eventBus.emit(
|
||||
@@ -461,9 +463,12 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
) as PlayerView;
|
||||
|
||||
this.addEvent({
|
||||
description: `${recipient.name()} ${
|
||||
update.accepted ? "accepted" : "rejected"
|
||||
} your alliance request`,
|
||||
description: translateText("events_display.alliance_request_status", {
|
||||
name: recipient.name(),
|
||||
status: update.accepted
|
||||
? translateText("events_display.alliance_accepted")
|
||||
: translateText("events_display.alliance_rejected"),
|
||||
}),
|
||||
type: update.accepted
|
||||
? MessageType.ALLIANCE_ACCEPTED
|
||||
: MessageType.ALLIANCE_REJECTED,
|
||||
@@ -489,12 +494,18 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
this.game.config().traitorDuration() * 0.1,
|
||||
);
|
||||
const durationText =
|
||||
traitorDuration === 1 ? "1 second" : `${traitorDuration} seconds`;
|
||||
traitorDuration === 1
|
||||
? translateText("events_display.duration_second")
|
||||
: translateText("events_display.duration_seconds_plural", {
|
||||
seconds: traitorDuration,
|
||||
});
|
||||
|
||||
this.addEvent({
|
||||
description:
|
||||
`You broke your alliance with ${betrayed.name()}, making you a TRAITOR ` +
|
||||
`(${malusPercent}% defense debuff for ${durationText})`,
|
||||
description: translateText("events_display.betrayal_description", {
|
||||
name: betrayed.name(),
|
||||
malusPercent: malusPercent,
|
||||
durationText: durationText,
|
||||
}),
|
||||
type: MessageType.ALLIANCE_BROKEN,
|
||||
highlight: true,
|
||||
createdAt: this.game.ticks(),
|
||||
@@ -503,14 +514,16 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
} else if (betrayed === myPlayer) {
|
||||
const buttons = [
|
||||
{
|
||||
text: "Focus",
|
||||
text: translateText("events_display.focus"),
|
||||
className: "btn-gray",
|
||||
action: () => this.eventBus.emit(new GoToPlayerEvent(traitor)),
|
||||
preventClose: true,
|
||||
},
|
||||
];
|
||||
this.addEvent({
|
||||
description: `${traitor.name()} broke their alliance with you`,
|
||||
description: translateText("events_display.betrayed_you", {
|
||||
name: traitor.name(),
|
||||
}),
|
||||
type: MessageType.ALLIANCE_BROKEN,
|
||||
highlight: true,
|
||||
createdAt: this.game.ticks(),
|
||||
@@ -535,7 +548,9 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
if (!other || !myPlayer.isAlive() || !other.isAlive()) return;
|
||||
|
||||
this.addEvent({
|
||||
description: `Your alliance with ${other.name()} expired`,
|
||||
description: translateText("events_display.alliance_expired", {
|
||||
name: other.name(),
|
||||
}),
|
||||
type: MessageType.ALLIANCE_EXPIRED,
|
||||
highlight: true,
|
||||
createdAt: this.game.ticks(),
|
||||
@@ -551,7 +566,10 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
const target = this.game.playerBySmallID(event.targetID) as PlayerView;
|
||||
|
||||
this.addEvent({
|
||||
description: `${other.name()} requests you attack ${target.name()}`,
|
||||
description: translateText("events_display.attack_request", {
|
||||
name: other.name(),
|
||||
target: target.name(),
|
||||
}),
|
||||
type: MessageType.ATTACK_REQUEST,
|
||||
highlight: true,
|
||||
createdAt: this.game.ticks(),
|
||||
@@ -599,7 +617,7 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
|
||||
if (recipient === myPlayer) {
|
||||
this.addEvent({
|
||||
description: `${sender.displayName()}:${update.emoji.message}`,
|
||||
description: `${sender.displayName()}: ${update.emoji.message}`,
|
||||
unsafeDescription: true,
|
||||
type: MessageType.CHAT,
|
||||
highlight: true,
|
||||
@@ -608,9 +626,10 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
});
|
||||
} else if (sender === myPlayer && recipient !== AllPlayers) {
|
||||
this.addEvent({
|
||||
description: `Sent ${(recipient as PlayerView).displayName()}: ${
|
||||
update.emoji.message
|
||||
}`,
|
||||
description: translateText("events_display.sent_emoji", {
|
||||
name: (recipient as PlayerView).displayName(),
|
||||
emoji: update.emoji.message,
|
||||
}),
|
||||
unsafeDescription: true,
|
||||
type: MessageType.CHAT,
|
||||
highlight: true,
|
||||
@@ -746,7 +765,7 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
<div class="inline-flex items-center gap-1">
|
||||
${this.renderButton({
|
||||
content: html`${renderTroops(landAttack.troops)}
|
||||
Wilderness`,
|
||||
${translateText("help_modal.ui_wilderness")}`,
|
||||
className: "text-left text-gray-400",
|
||||
translate: false,
|
||||
})}
|
||||
@@ -953,7 +972,7 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
>`
|
||||
: ""}
|
||||
${this.renderButton({
|
||||
content: "Hide",
|
||||
content: translateText("leaderboard.hide"),
|
||||
onClick: this.toggleHidden,
|
||||
className:
|
||||
"text-white cursor-pointer pointer-events-auto",
|
||||
|
||||
@@ -11,6 +11,7 @@ import { GameType } from "../../../core/game/Game";
|
||||
import { GameUpdateType } from "../../../core/game/GameUpdates";
|
||||
import { GameView } from "../../../core/game/GameView";
|
||||
import { PauseGameEvent } from "../../Transport";
|
||||
import { translateText } from "../../Utils";
|
||||
import { Layer } from "./Layer";
|
||||
import { ShowReplayPanelEvent } from "./ReplayPanel";
|
||||
import { ShowSettingsModalEvent } from "./SettingsModal";
|
||||
@@ -86,7 +87,9 @@ export class GameRightSidebar extends LitElement implements Layer {
|
||||
private onExitButtonClick() {
|
||||
const isAlive = this.game.myPlayer()?.isAlive();
|
||||
if (isAlive) {
|
||||
const isConfirmed = confirm("Are you sure you want to exit the game?");
|
||||
const isConfirmed = confirm(
|
||||
translateText("help_modal.exit_confirmation"),
|
||||
);
|
||||
if (!isConfirmed) return;
|
||||
}
|
||||
// redirect to the home page
|
||||
|
||||
@@ -7,6 +7,7 @@ import { GameView } from "../../../core/game/GameView";
|
||||
import { UserSettings } from "../../../core/game/UserSettings";
|
||||
import { AlternateViewEvent, RefreshGraphicsEvent } from "../../InputHandler";
|
||||
import { PauseGameEvent } from "../../Transport";
|
||||
import { translateText } from "../../Utils";
|
||||
import { Layer } from "./Layer";
|
||||
|
||||
const button = ({
|
||||
@@ -74,7 +75,9 @@ export class OptionsMenu extends LitElement implements Layer {
|
||||
private onExitButtonClick() {
|
||||
const isAlive = this.game.myPlayer()?.isAlive();
|
||||
if (isAlive) {
|
||||
const isConfirmed = confirm("Are you sure you want to exit the game?");
|
||||
const isConfirmed = confirm(
|
||||
translateText("help_modal.exit_confirmation"),
|
||||
);
|
||||
if (!isConfirmed) return;
|
||||
}
|
||||
// redirect to the home page
|
||||
|
||||
@@ -74,7 +74,10 @@ export class ReplayPanel extends LitElement implements Layer {
|
||||
${this.renderSpeedButton(ReplaySpeedMultiplier.slow, "×0.5")}
|
||||
${this.renderSpeedButton(ReplaySpeedMultiplier.normal, "×1")}
|
||||
${this.renderSpeedButton(ReplaySpeedMultiplier.fast, "×2")}
|
||||
${this.renderSpeedButton(ReplaySpeedMultiplier.fastest, "max")}
|
||||
${this.renderSpeedButton(
|
||||
ReplaySpeedMultiplier.fastest,
|
||||
translateText("replay_panel.fastest_game_speed"),
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -8,10 +8,10 @@ import mouseIcon from "../../../../resources/images/MouseIconWhite.svg";
|
||||
import ninjaIcon from "../../../../resources/images/NinjaIconWhite.svg";
|
||||
import settingsIcon from "../../../../resources/images/SettingIconWhite.svg";
|
||||
import treeIcon from "../../../../resources/images/TreeIconWhite.svg";
|
||||
import { translateText } from "../../../client/Utils";
|
||||
import { EventBus } from "../../../core/EventBus";
|
||||
import { UserSettings } from "../../../core/game/UserSettings";
|
||||
import { AlternateViewEvent, RefreshGraphicsEvent } from "../../InputHandler";
|
||||
import { translateText } from "../../Utils";
|
||||
import { Layer } from "./Layer";
|
||||
|
||||
export class ShowSettingsModalEvent {
|
||||
@@ -143,7 +143,9 @@ export class SettingsModal extends LitElement implements Layer {
|
||||
height="24"
|
||||
style="vertical-align: middle;"
|
||||
/>
|
||||
<h2 class="text-xl font-semibold text-white">Settings</h2>
|
||||
<h2 class="text-xl font-semibold text-white">
|
||||
${translateText("user_setting.tab_basic")}
|
||||
</h2>
|
||||
</div>
|
||||
<button
|
||||
class="text-slate-400 hover:text-white text-2xl font-bold leading-none"
|
||||
@@ -160,15 +162,19 @@ export class SettingsModal extends LitElement implements Layer {
|
||||
>
|
||||
<img src=${treeIcon} alt="treeIcon" width="20" height="20" />
|
||||
<div class="flex-1">
|
||||
<div class="font-medium">Toggle Terrain</div>
|
||||
<div class="font-medium">
|
||||
${translateText("user_setting.toggle_terrain")}
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.alternateView
|
||||
? "Terrain view enabled"
|
||||
: "Terrain view disabled"}
|
||||
? translateText("user_setting.terrain_enabled")
|
||||
: translateText("user_setting.terrain_disabled")}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.alternateView ? "On" : "Off"}
|
||||
${this.alternateView
|
||||
? translateText("user_setting.on")
|
||||
: translateText("user_setting.off")}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -183,12 +189,14 @@ export class SettingsModal extends LitElement implements Layer {
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.emojis()
|
||||
? "Emojis are visible"
|
||||
: "Emojis are hidden"}
|
||||
? translateText("user_setting.emojis_visible")
|
||||
: translateText("user_setting.emojis_hidden")}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.emojis() ? "On" : "Off"}
|
||||
${this.userSettings.emojis()
|
||||
? translateText("user_setting.on")
|
||||
: translateText("user_setting.off")}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -208,12 +216,14 @@ export class SettingsModal extends LitElement implements Layer {
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.darkMode()
|
||||
? "Dark mode enabled"
|
||||
: "Light mode enabled"}
|
||||
? translateText("user_setting.dark_mode_enabled")
|
||||
: translateText("user_setting.light_mode_enabled")}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.darkMode() ? "On" : "Off"}
|
||||
${this.userSettings.darkMode()
|
||||
? translateText("user_setting.on")
|
||||
: translateText("user_setting.off")}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -233,12 +243,14 @@ export class SettingsModal extends LitElement implements Layer {
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.fxLayer()
|
||||
? "Special effects enabled"
|
||||
: "Special effects disabled"}
|
||||
? translateText("user_setting.special_effects_enabled")
|
||||
: translateText("user_setting.special_effects_disabled")}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.fxLayer() ? "On" : "Off"}
|
||||
${this.userSettings.fxLayer()
|
||||
? translateText("user_setting.on")
|
||||
: translateText("user_setting.off")}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -253,12 +265,14 @@ export class SettingsModal extends LitElement implements Layer {
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.anonymousNames()
|
||||
? "Anonymous names enabled"
|
||||
: "Real names shown"}
|
||||
? translateText("user_setting.anonymous_names_enabled")
|
||||
: translateText("user_setting.real_names_shown")}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.anonymousNames() ? "On" : "Off"}
|
||||
${this.userSettings.anonymousNames()
|
||||
? translateText("user_setting.on")
|
||||
: translateText("user_setting.off")}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -268,15 +282,19 @@ export class SettingsModal extends LitElement implements Layer {
|
||||
>
|
||||
<img src=${mouseIcon} alt="mouseIcon" width="20" height="20" />
|
||||
<div class="flex-1">
|
||||
<div class="font-medium">Left Click Menu</div>
|
||||
<div class="font-medium">
|
||||
${translateText("user_setting.left_click_menu")}
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.leftClickOpensMenu()
|
||||
? "Left click opens menu"
|
||||
: "Right click opens menu"}
|
||||
? translateText("user_setting.left_click_opens_menu")
|
||||
: translateText("user_setting.right_click_opens_menu")}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.leftClickOpensMenu() ? "On" : "Off"}
|
||||
${this.userSettings.leftClickOpensMenu()
|
||||
? translateText("user_setting.on")
|
||||
: translateText("user_setting.off")}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -287,8 +305,12 @@ export class SettingsModal extends LitElement implements Layer {
|
||||
>
|
||||
<img src=${exitIcon} alt="exitIcon" width="20" height="20" />
|
||||
<div class="flex-1">
|
||||
<div class="font-medium">Exit Game</div>
|
||||
<div class="text-sm text-slate-400">Return to main menu</div>
|
||||
<div class="font-medium">
|
||||
${translateText("user_setting.exit_game_label")}
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${translateText("user_setting.exit_game_info")}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user