i18n(@projects/@magic-civilization): 🌐 route 25 hardcoded .gd UI strings through ThemeVocabulary
Replace hardcoded user-visible strings in 12 scene scripts (great_person_modal, merge_panel, specialists_drag_panel, throne_room_great_works, intelligence_log_panel, knowledge_tree tier badge, credits, game_setup, past_games, replay_viewer, lens_switcher/ransom_offers tooltips) with ThemeVocabulary.lookup() + add the corresponding keys (incl. fmt_* for format strings). Part of clearing validate-i18n with no bypass. (48 → 23 remaining.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5b2b88b2a9
commit
07a10054f4
13 changed files with 64 additions and 25 deletions
|
|
@ -335,6 +335,42 @@
|
|||
"replay_title": "Replay Viewer",
|
||||
"replay_placeholder": "World map renderer (wired when GdReplayPlayer bridge lands)",
|
||||
"replay_step": "Step",
|
||||
"replay_play": "Play",
|
||||
"replay_pause": "Pause",
|
||||
"fmt_replay_turn": "Turn %d / %d",
|
||||
"fmt_great_person_title": "%s (%s) — Tier %d",
|
||||
"fmt_great_person_action": "Action: %s",
|
||||
"great_person_choose_target": "Choose a target.",
|
||||
"great_person_ok": "OK",
|
||||
"fmt_great_person_ok_gold": "OK — +%d gold",
|
||||
"fmt_great_person_ok_production": "OK — +%d production",
|
||||
"fmt_great_person_cannot": "Cannot apply: %s",
|
||||
"merge_no_extension": "GdGameState extension not loaded.",
|
||||
"fmt_merge_not_found": "Hybrid building '%s' not found in registry.",
|
||||
"merge_buildings": "Merge Buildings",
|
||||
"merge_confirm": "Merge",
|
||||
"merge_cancel": "Cancel",
|
||||
"specialists_idle_citizens": "Idle citizens:",
|
||||
"great_works_empty": " (empty)",
|
||||
"fmt_great_works_entry": " • %s — %s (era %d)",
|
||||
"intel_no_envelopes": "No intercepted envelopes yet.",
|
||||
"fmt_tier_badge": "T%d",
|
||||
"fmt_credits_link": "%s [color=#9bbfe0][url=%s]%s[/url][/color]",
|
||||
"fmt_ai_slot": "AI Slot %d",
|
||||
"fmt_past_game_entry": "%s — Turn %d — %s",
|
||||
"watch_replay": "Watch Replay",
|
||||
"past_game_delete": "Delete",
|
||||
"lens_none_tooltip": "No lens (default biome view)",
|
||||
"fmt_ransom_offered": "Offered turn %d",
|
||||
"endgame_game_over": "Game Over",
|
||||
"endgame_winner": "Winner",
|
||||
"endgame_your_clan": "Your Clan",
|
||||
"endgame_final_standings": "Final Standings",
|
||||
"endgame_score_over_time": "Score Over Time",
|
||||
"endgame_awards": "Awards",
|
||||
"endgame_timeline": "Timeline",
|
||||
"endgame_view_map": "View Map",
|
||||
"endgame_save_archive": "Save to Archive",
|
||||
"tutorial_skip": "Skip Tutorial",
|
||||
"tutorial_step_1_title": "The Hex Map",
|
||||
"tutorial_step_1_body": "The world is carved into hex tiles. Click a tile to inspect it. Right-click (or click a destination) to move your selected unit. Drag with the middle mouse button to pan; scroll to zoom.",
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ func rebuild() -> void:
|
|||
add_child(v)
|
||||
|
||||
var title: Label = Label.new()
|
||||
title.text = "%s (%s) — Tier %d" % [_gp_name, _gp_class, _gp_tier]
|
||||
title.text = ThemeVocabulary.lookup("fmt_great_person_title") % [_gp_name, _gp_class, _gp_tier]
|
||||
title.add_theme_font_size_override("font_size", 16)
|
||||
v.add_child(title)
|
||||
|
||||
|
|
@ -117,21 +117,21 @@ func rebuild() -> void:
|
|||
if _gp_action != null and _gp_action.has_method("action_type"):
|
||||
at = String(_gp_action.action_type())
|
||||
var act_label: Label = Label.new()
|
||||
act_label.text = "Action: %s" % (at if at != "" else "(none)")
|
||||
act_label.text = ThemeVocabulary.lookup("fmt_great_person_action") % (at if at != "" else "(none)")
|
||||
v.add_child(act_label)
|
||||
|
||||
var status: Label = Label.new()
|
||||
if _validation.is_empty():
|
||||
status.text = "Choose a target."
|
||||
status.text = ThemeVocabulary.lookup("great_person_choose_target")
|
||||
elif bool(_validation.get("ok", false)):
|
||||
status.text = "OK"
|
||||
status.text = ThemeVocabulary.lookup("great_person_ok")
|
||||
if _validation.has("gold"):
|
||||
status.text = "OK — +%d gold" % int(_validation["gold"])
|
||||
status.text = ThemeVocabulary.lookup("fmt_great_person_ok_gold") % int(_validation["gold"])
|
||||
if _validation.has("production"):
|
||||
status.text = "OK — +%d production" % int(_validation["production"])
|
||||
status.text = ThemeVocabulary.lookup("fmt_great_person_ok_production") % int(_validation["production"])
|
||||
else:
|
||||
var err: String = String(_validation.get("error", "invalid"))
|
||||
status.text = "Cannot apply: %s" % err
|
||||
status.text = ThemeVocabulary.lookup("fmt_great_person_cannot") % err
|
||||
v.add_child(status)
|
||||
|
||||
_last_snapshot = {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ func populate(
|
|||
_clear_rows()
|
||||
|
||||
if not _city.is_extension_available():
|
||||
_error_label.text = "GdGameState extension not loaded."
|
||||
_error_label.text = ThemeVocabulary.lookup("merge_no_extension")
|
||||
_error_label.show()
|
||||
return
|
||||
|
||||
|
|
@ -121,7 +121,7 @@ func _on_confirm_pressed() -> void:
|
|||
# Fetch the hybrid BuildingDef JSON from DataLoader.
|
||||
var hybrid_def: Dictionary = DataLoader.get_building(into)
|
||||
if hybrid_def.is_empty():
|
||||
_error_label.text = "Hybrid building '%s' not found in registry." % into
|
||||
_error_label.text = ThemeVocabulary.lookup("fmt_merge_not_found") % into
|
||||
_error_label.show()
|
||||
return
|
||||
var hybrid_json: String = JSON.stringify(hybrid_def)
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ func _make_slot_row(row: Dictionary) -> Control:
|
|||
func _make_unassigned_row() -> Control:
|
||||
var row: HBoxContainer = HBoxContainer.new()
|
||||
var label: Label = Label.new()
|
||||
label.text = "Idle citizens:"
|
||||
label.text = ThemeVocabulary.lookup("specialists_idle_citizens")
|
||||
label.custom_minimum_size = Vector2(220, 0)
|
||||
row.add_child(label)
|
||||
if _unassigned.is_empty():
|
||||
|
|
|
|||
|
|
@ -118,13 +118,13 @@ func _make_layer_section(layer: String, rows: Array) -> Control:
|
|||
|
||||
if rows.is_empty():
|
||||
var empty: Label = Label.new()
|
||||
empty.text = " (empty)"
|
||||
empty.text = ThemeVocabulary.lookup("great_works_empty")
|
||||
box.add_child(empty)
|
||||
return box
|
||||
|
||||
for r: Dictionary in rows:
|
||||
var line: Label = Label.new()
|
||||
line.text = " • %s — %s (era %d)" % [
|
||||
line.text = ThemeVocabulary.lookup("fmt_great_works_entry") % [
|
||||
String(r["name"]),
|
||||
String(r["building"]),
|
||||
int(r["era"]),
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ func _build_ui() -> void:
|
|||
_scroll.add_child(_vbox)
|
||||
|
||||
_empty_label = Label.new()
|
||||
_empty_label.text = "No intercepted envelopes yet."
|
||||
_empty_label.text = ThemeVocabulary.lookup("intel_no_envelopes")
|
||||
_empty_label.add_theme_font_size_override("font_size", 13)
|
||||
_empty_label.theme_type_variation = "LabelMuted"
|
||||
_body.add_child(_empty_label)
|
||||
|
|
|
|||
|
|
@ -451,7 +451,7 @@ func _create_node_card(
|
|||
|
||||
if tier > 0:
|
||||
var tier_label: Label = Label.new()
|
||||
tier_label.text = "T%d" % tier
|
||||
tier_label.text = ThemeVocabulary.lookup("fmt_tier_badge") % tier
|
||||
tier_label.add_theme_font_size_override("font_size", 10)
|
||||
top_row.add_child(tier_label)
|
||||
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ func _build_entry_row(entry: Dictionary) -> Control:
|
|||
rich.add_theme_font_size_override("normal_font_size", 13)
|
||||
rich.add_theme_color_override("default_color", ThemeAssets.color("text.primary"))
|
||||
# Escape-friendly: `line` is author-controlled JSON / CSV, not BBCode.
|
||||
rich.text = "%s [color=#9bbfe0][url=%s]%s[/url][/color]" % [line, url, url]
|
||||
rich.text = ThemeVocabulary.lookup("fmt_credits_link") % [line, url, url]
|
||||
rich.meta_clicked.connect(func(meta: Variant) -> void: OS.shell_open(str(meta)))
|
||||
return rich
|
||||
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ func _make_controller_row(slot_idx: int) -> Control:
|
|||
var row: HBoxContainer = HBoxContainer.new()
|
||||
row.add_theme_constant_override("separation", 8)
|
||||
var label: Label = Label.new()
|
||||
label.text = "AI Slot %d" % slot_idx
|
||||
label.text = ThemeVocabulary.lookup("fmt_ai_slot") % slot_idx
|
||||
label.add_theme_font_size_override("font_size", 11)
|
||||
label.theme_type_variation = "LabelSecondary"
|
||||
label.custom_minimum_size = Vector2(80, 0)
|
||||
|
|
|
|||
|
|
@ -102,16 +102,16 @@ func _make_card(entry: Dictionary) -> PanelContainer:
|
|||
var title: String = entry.get("title", "Unnamed Game")
|
||||
var turn: int = entry.get("final_turn", 0)
|
||||
var outcome: String = entry.get("outcome", "unknown")
|
||||
info_label.text = "%s — Turn %d — %s" % [title, turn, outcome]
|
||||
info_label.text = ThemeVocabulary.lookup("fmt_past_game_entry") % [title, turn, outcome]
|
||||
hbox.add_child(info_label)
|
||||
|
||||
var watch_btn: Button = Button.new()
|
||||
watch_btn.text = "Watch Replay"
|
||||
watch_btn.text = ThemeVocabulary.lookup("watch_replay")
|
||||
watch_btn.pressed.connect(_on_watch_replay_pressed.bind(entry))
|
||||
hbox.add_child(watch_btn)
|
||||
|
||||
var delete_btn: Button = Button.new()
|
||||
delete_btn.text = "Delete"
|
||||
delete_btn.text = ThemeVocabulary.lookup("past_game_delete")
|
||||
delete_btn.pressed.connect(_on_delete_pressed.bind(entry))
|
||||
hbox.add_child(delete_btn)
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ func _process(delta: float) -> void:
|
|||
var next: int = _current_turn + 1
|
||||
if next > _final_turn:
|
||||
_playing = false
|
||||
_play_pause_button.text = "Play"
|
||||
_play_pause_button.text = ThemeVocabulary.lookup("replay_play")
|
||||
return
|
||||
_goto_turn(next)
|
||||
|
||||
|
|
@ -143,7 +143,7 @@ func _resolve_archive_root() -> String:
|
|||
|
||||
|
||||
func _update_turn_display() -> void:
|
||||
_turn_label.text = "Turn %d / %d" % [_current_turn, _final_turn]
|
||||
_turn_label.text = ThemeVocabulary.lookup("fmt_replay_turn") % [_current_turn, _final_turn]
|
||||
_speed_label.text = "%.1f×" % _speed
|
||||
|
||||
|
||||
|
|
@ -153,7 +153,10 @@ func _on_scrubber_changed(value: float) -> void:
|
|||
|
||||
func _on_play_pause_pressed() -> void:
|
||||
_playing = not _playing
|
||||
_play_pause_button.text = "Pause" if _playing else "Play"
|
||||
_play_pause_button.text = (
|
||||
ThemeVocabulary.lookup("replay_pause") if _playing
|
||||
else ThemeVocabulary.lookup("replay_play")
|
||||
)
|
||||
_playback_elapsed = 0.0
|
||||
|
||||
|
||||
|
|
@ -165,7 +168,7 @@ func _on_speed_set(speed: float) -> void:
|
|||
func _on_step_pressed() -> void:
|
||||
if _playing:
|
||||
_playing = false
|
||||
_play_pause_button.text = "Play"
|
||||
_play_pause_button.text = ThemeVocabulary.lookup("replay_play")
|
||||
_goto_turn(_current_turn + 1)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ func _build_buttons() -> void:
|
|||
var btn_none: Button = Button.new()
|
||||
btn_none.name = "BtnNone"
|
||||
btn_none.text = "—"
|
||||
btn_none.tooltip_text = "No lens (default biome view)"
|
||||
btn_none.tooltip_text = ThemeVocabulary.lookup("lens_none_tooltip")
|
||||
btn_none.pressed.connect(_on_lens_pressed.bind(""))
|
||||
row.add_child(btn_none)
|
||||
_buttons_by_id[""] = btn_none
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ func _make_offer_row(offer: Dictionary) -> Control:
|
|||
ThemeVocabulary.lookup("ransom_button_defer"),
|
||||
_on_defer_pressed.bind(offer_id),
|
||||
))
|
||||
panel.tooltip_text = "Offered turn %d" % created_turn
|
||||
panel.tooltip_text = ThemeVocabulary.lookup("fmt_ransom_offered") % created_turn
|
||||
return panel
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue