mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 11: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:
+37
-3
@@ -60,6 +60,7 @@
|
||||
"ui_options_desc": "The following elements can be found inside:",
|
||||
"ui_playeroverlay": "Player info overlay",
|
||||
"ui_playeroverlay_desc": "When you hover over a country, the Player info overlay is displayed under Options. It shows the type of player: Human, Nation (smart bot), or Bot. A Nation's attitude towards you, ranging from Hostile to Friendly. And defending troops, gold, plus the number of Warships and various buildings the player has.",
|
||||
"ui_wilderness": "Wilderness",
|
||||
"option_pause": "Pause/Unpause the game - Only available in single player mode.",
|
||||
"option_timer": "Timer - Time passed since the start of the game.",
|
||||
"option_exit": "Exit button.",
|
||||
@@ -112,7 +113,8 @@
|
||||
"icon_ally": "Handshake - Ally. This player is your ally.",
|
||||
"icon_embargo": "Dollar stop sign - Embargo. This player has stopped trading with you automatically or manually.",
|
||||
"icon_request": "Envelope - Alliance request. This player has sent you an alliance request.",
|
||||
"info_enemy_panel": "Enemy info panel"
|
||||
"info_enemy_panel": "Enemy info panel",
|
||||
"exit_confirmation": "Are you sure you want to exit the game?"
|
||||
},
|
||||
"single_modal": {
|
||||
"title": "Single Player",
|
||||
@@ -255,16 +257,27 @@
|
||||
"tab_keybinds": "Keybinds",
|
||||
"dark_mode_label": "Dark Mode",
|
||||
"dark_mode_desc": "Toggle the site’s appearance between light and dark themes",
|
||||
"dark_mode_enabled": "Dark mode enabled",
|
||||
"light_mode_enabled": "Light mode enabled",
|
||||
"emojis_label": "Emojis",
|
||||
"emojis_visible": "Emojis are visible",
|
||||
"emojis_hidden": "Emojis are hidden",
|
||||
"emojis_desc": "Toggle whether emojis are shown in game",
|
||||
"alert_frame_label": "Alert Frame",
|
||||
"alert_frame_desc": "Toggle the alert frame. When enabled, the frame will be displayed when you are betrayed.",
|
||||
"special_effects_label": "Special effects",
|
||||
"special_effects_desc": "Toggle special effects. Deactivate to improve performances",
|
||||
"special_effects_enabled": "Special effects enabled",
|
||||
"special_effects_disabled": "Special effects disabled",
|
||||
"anonymous_names_label": "Hidden Names",
|
||||
"anonymous_names_desc": "Hide real player names with random ones on your screen.",
|
||||
"anonymous_names_enabled": "Anonymous names enabled",
|
||||
"real_names_shown": "Real names shown",
|
||||
"left_click_label": "Left Click to Open Menu",
|
||||
"left_click_desc": "When ON, left-click opens menu and sword button attacks. When OFF, left-click attacks directly.",
|
||||
"left_click_menu": "Left Click Menu",
|
||||
"left_click_opens_menu": "Left click opens menu",
|
||||
"right_click_opens_menu": "Right click opens menu",
|
||||
"attack_ratio_label": "⚔️ Attack Ratio",
|
||||
"attack_ratio_desc": "What percentage of your troops to send in an attack (1–100%)",
|
||||
"troop_ratio_label": "🪖🛠️ Troops and Workers Ratio",
|
||||
@@ -305,7 +318,14 @@
|
||||
"move_right": "Move Camera Right",
|
||||
"move_right_desc": "Move the camera to the right",
|
||||
"reset": "Reset",
|
||||
"unbind": "Unbind"
|
||||
"unbind": "Unbind",
|
||||
"on": "On",
|
||||
"off": "Off",
|
||||
"toggle_terrain": "Toggle Terrain",
|
||||
"terrain_enabled": "Terrain view enabled",
|
||||
"terrain_disabled": "Terrain view disabled",
|
||||
"exit_game_label": "Exit Game",
|
||||
"exit_game_info": "Return to main menu"
|
||||
},
|
||||
"chat": {
|
||||
"title": "Quick Chat",
|
||||
@@ -437,9 +457,22 @@
|
||||
"events_display": {
|
||||
"retreating": "retreating",
|
||||
"boat": "Boat",
|
||||
"alliance_request_status": "{name} {status} your alliance request",
|
||||
"alliance_accepted": "accepted",
|
||||
"alliance_rejected": "rejected",
|
||||
"duration_second": "1 second",
|
||||
"betrayal_description": "You broke your alliance with {name}, making you a TRAITOR ({malusPercent}% defense debuff for {durationText})",
|
||||
"duration_seconds_plural": "{seconds} seconds",
|
||||
"betrayed_you": "{name} broke their alliance with you",
|
||||
"about_to_expire": "Your alliance with {name} is about to expire!",
|
||||
"alliance_expired": "Your alliance with {name} expired",
|
||||
"attack_request": "{name} requests you attack {target}",
|
||||
"sent_emoji": "Sent {name}: {emoji}",
|
||||
"renew_alliance": "Request to renew",
|
||||
"request_alliance": "{name} requests an alliance!",
|
||||
"focus": "Focus",
|
||||
"accept_alliance": "Accept",
|
||||
"reject_alliance": "Reject",
|
||||
"alliance_renewed": "Your alliance with {name} has been renewed",
|
||||
"ignore": "Ignore"
|
||||
},
|
||||
@@ -483,7 +516,8 @@
|
||||
},
|
||||
"replay_panel": {
|
||||
"replay_speed": "Replay speed",
|
||||
"game_speed": "Game speed"
|
||||
"game_speed": "Game speed",
|
||||
"fastest_game_speed": "max"
|
||||
},
|
||||
"error_modal": {
|
||||
"crashed": "Game crashed!",
|
||||
|
||||
@@ -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