diff --git a/locale/es.po b/locale/es.po index ea1287ff83..9b3423bbe5 100644 --- a/locale/es.po +++ b/locale/es.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: Threadbare\n" -"PO-Revision-Date: 2026-04-08 17:57-0300\n" +"PO-Revision-Date: 2026-04-08 21:25-0300\n" "Last-Translator: Manuel Quiñones \n" "Language-Team: Spanish\n" "Language: es\n" @@ -60,6 +60,10 @@ msgstr "Ajustes de video" msgid "Fullscreen" msgstr "Pantalla completa" +#: scenes/menus/options/components/language_settings.tscn +msgid "Language Settings" +msgstr "Ajustes de idioma" + #: scenes/menus/debug/debug_settings.tscn msgid "Completed Quests" msgstr "Misiones completadas" diff --git a/locale/threadbare.pot b/locale/threadbare.pot index 93a6c44f30..f871449adf 100644 --- a/locale/threadbare.pot +++ b/locale/threadbare.pot @@ -3,6 +3,7 @@ # res://scenes/menus/options/options.tscn # res://scenes/menus/options/components/sound_settings.tscn # res://scenes/menus/options/components/video_settings.tscn +# res://scenes/menus/options/components/language_settings.tscn # res://scenes/menus/debug/debug_settings.tscn # res://scenes/globals/pause/pause_overlay.tscn # res://scenes/menus/title/components/main_menu.gd @@ -72,6 +73,10 @@ msgstr "" msgid "Fullscreen" msgstr "" +#: scenes/menus/options/components/language_settings.tscn +msgid "Language Settings" +msgstr "" + #: scenes/menus/debug/debug_settings.tscn msgid "Completed Quests" msgstr "" diff --git a/project.godot b/project.godot index 9c2fd46a47..968d1fbb63 100644 --- a/project.godot +++ b/project.godot @@ -283,7 +283,7 @@ champ_walk_on_water={ [internationalization] locale/translations=PackedStringArray("res://locale/es.po") -locale/translations_pot_files=PackedStringArray("res://scenes/menus/title/components/main_menu.tscn", "res://scenes/menus/options/options.tscn", "res://scenes/menus/options/components/sound_settings.tscn", "res://scenes/menus/options/components/video_settings.tscn", "res://scenes/menus/debug/debug_settings.tscn", "res://scenes/globals/pause/pause_overlay.tscn", "res://scenes/menus/title/components/main_menu.gd", "res://scenes/ui_elements/input_hints/aim_input_hint.tscn", "res://scenes/ui_elements/input_hints/interact_input_hint.tscn", "res://scenes/ui_elements/input_hints/movement_input_hint.tscn", "res://scenes/ui_elements/input_hints/repel_input_hint.tscn", "res://scenes/ui_elements/input_hints/reset_input_hint.tscn", "res://scenes/ui_elements/input_hints/run_input_hint.tscn", "res://scenes/ui_elements/input_hints/skip_input_hint.tscn", "res://scenes/ui_elements/input_hints/throw_input_hint.tscn", "res://scenes/ui_elements/input_hints/undo_input_hint.tscn") +locale/translations_pot_files=PackedStringArray("res://scenes/menus/title/components/main_menu.tscn", "res://scenes/menus/options/options.tscn", "res://scenes/menus/options/components/sound_settings.tscn", "res://scenes/menus/options/components/video_settings.tscn", "res://scenes/menus/options/components/language_settings.tscn", "res://scenes/menus/debug/debug_settings.tscn", "res://scenes/globals/pause/pause_overlay.tscn", "res://scenes/menus/title/components/main_menu.gd", "res://scenes/ui_elements/input_hints/aim_input_hint.tscn", "res://scenes/ui_elements/input_hints/interact_input_hint.tscn", "res://scenes/ui_elements/input_hints/movement_input_hint.tscn", "res://scenes/ui_elements/input_hints/repel_input_hint.tscn", "res://scenes/ui_elements/input_hints/reset_input_hint.tscn", "res://scenes/ui_elements/input_hints/run_input_hint.tscn", "res://scenes/ui_elements/input_hints/skip_input_hint.tscn", "res://scenes/ui_elements/input_hints/throw_input_hint.tscn", "res://scenes/ui_elements/input_hints/undo_input_hint.tscn") [layer_names] diff --git a/scenes/globals/settings/settings.gd b/scenes/globals/settings/settings.gd index 5495609685..6a09448c61 100644 --- a/scenes/globals/settings/settings.gd +++ b/scenes/globals/settings/settings.gd @@ -15,6 +15,10 @@ const DEFAULT_VOLUMES: Dictionary[String, float] = { "Music": 0.5, } +const LANGUAGE_SECTION := "Language" +const LOCALE_KEY := "Locale" +const DEFAULT_LOCALE := "en" + ## 5:4 ratio of 1280×1024, 1024×768, and other pre-widescreen monitors. const MINIMUM_ASPECT_RATIO := 1.25 @@ -38,6 +42,7 @@ func _ready() -> void: _settings.set_value(META_SECTION, VERSION_KEY, VERSION) _restore_volumes() + _restore_locale() _load_project_settings_overrides() _set_minimum_window_size() @@ -101,6 +106,16 @@ func toggle_fullscreen(toggled_on: bool) -> void: set_window_mode(DisplayServer.WINDOW_MODE_WINDOWED) +func get_locale() -> String: + return TranslationServer.get_locale() + + +func set_locale(locale: String) -> void: + TranslationServer.set_locale(locale) + _settings.set_value(LANGUAGE_SECTION, LOCALE_KEY, locale) + _save() + + func set_window_mode(window_mode: int) -> void: if window_mode == DisplayServer.window_get_mode(): return @@ -113,6 +128,11 @@ func set_window_mode(window_mode: int) -> void: push_warning("Failed to save to", _overrides_path, ": ", error_string(ret)) +func _restore_locale() -> void: + var locale: String = _settings.get_value(LANGUAGE_SECTION, LOCALE_KEY, DEFAULT_LOCALE) + TranslationServer.set_locale(locale) + + func _set_volume(bus_idx: int, volume_linear: float) -> void: AudioServer.set_bus_volume_linear(bus_idx, volume_linear) diff --git a/scenes/menus/options/components/language_option.gd b/scenes/menus/options/components/language_option.gd new file mode 100644 index 0000000000..56b069729f --- /dev/null +++ b/scenes/menus/options/components/language_option.gd @@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: The Threadbare Authors +# SPDX-License-Identifier: MPL-2.0 +extends HBoxContainer + +@onready var _english_button: Button = %EnglishButton +@onready var _spanish_button: Button = %SpanishButton + + +func _ready() -> void: + # There are two instances of this option in the game: one on the title screen, and + # another in the pause overlay. At most one is displayed at a time, so we can keep them in + # synch by reading the setting each time each option is displayed. + visibility_changed.connect(_refresh) + _refresh() + + +func _refresh() -> void: + var current_locale := Settings.get_locale() + _english_button.set_pressed_no_signal(current_locale == "en") + _spanish_button.set_pressed_no_signal(current_locale == "es") + + +func _on_button_pressed(language_code: String) -> void: + Settings.set_locale(language_code) + _refresh() diff --git a/scenes/menus/options/components/language_option.gd.uid b/scenes/menus/options/components/language_option.gd.uid new file mode 100644 index 0000000000..765f84db2d --- /dev/null +++ b/scenes/menus/options/components/language_option.gd.uid @@ -0,0 +1 @@ +uid://dk2wa6nonu0jc diff --git a/scenes/menus/options/components/language_settings.tscn b/scenes/menus/options/components/language_settings.tscn new file mode 100644 index 0000000000..3861425d12 --- /dev/null +++ b/scenes/menus/options/components/language_settings.tscn @@ -0,0 +1,45 @@ +[gd_scene format=3 uid="uid://w0uscqwgsi4w"] + +[ext_resource type="Theme" uid="uid://cvitou84ni7qe" path="res://scenes/ui_elements/components/theme.tres" id="1_abc"] +[ext_resource type="Script" uid="uid://dk2wa6nonu0jc" path="res://scenes/menus/options/components/language_option.gd" id="2_abc"] + +[node name="LanguageSettings" type="VBoxContainer" unique_id=85827291] +offset_left = 96.0 +offset_top = 64.0 +offset_right = 544.0 +offset_bottom = 254.0 +theme = ExtResource("1_abc") + +[node name="PanelContainer" type="PanelContainer" parent="." unique_id=1311807474] +layout_mode = 2 +size_flags_horizontal = 0 +theme_type_variation = &"PlayerRibbon" + +[node name="Label" type="Label" parent="PanelContainer" unique_id=1487597883] +layout_mode = 2 +text = "Language Settings" + +[node name="HBoxContainer" type="HBoxContainer" parent="." unique_id=1302951996] +layout_mode = 2 +script = ExtResource("2_abc") + +[node name="EnglishButton" type="Button" parent="HBoxContainer" unique_id=993974861] +unique_name_in_owner = true +auto_translate_mode = 2 +layout_mode = 2 +size_flags_horizontal = 3 +theme_type_variation = &"FlatButton" +toggle_mode = true +text = "English" + +[node name="SpanishButton" type="Button" parent="HBoxContainer" unique_id=355814411] +unique_name_in_owner = true +auto_translate_mode = 2 +layout_mode = 2 +size_flags_horizontal = 3 +theme_type_variation = &"FlatButton" +toggle_mode = true +text = "Español" + +[connection signal="pressed" from="HBoxContainer/EnglishButton" to="HBoxContainer" method="_on_button_pressed" binds= ["en"]] +[connection signal="pressed" from="HBoxContainer/SpanishButton" to="HBoxContainer" method="_on_button_pressed" binds= ["es"]] diff --git a/scenes/menus/options/options.tscn b/scenes/menus/options/options.tscn index 42102fc8f9..ee3a14fc86 100644 --- a/scenes/menus/options/options.tscn +++ b/scenes/menus/options/options.tscn @@ -5,6 +5,7 @@ [ext_resource type="Script" uid="uid://r7cjyiw5log4" path="res://scenes/menus/options/components/options.gd" id="2_cw13b"] [ext_resource type="PackedScene" uid="uid://tahf2q1d3e74" path="res://scenes/menus/options/components/video_settings.tscn" id="4_cw13b"] [ext_resource type="Texture2D" uid="uid://xe25gqovxxpe" path="res://assets/first_party/icons/left_arrow.png" id="5_qdq3g"] +[ext_resource type="PackedScene" uid="uid://w0uscqwgsi4w" path="res://scenes/menus/options/components/language_settings.tscn" id="6_lang"] [node name="Options" type="CenterContainer" unique_id=2066163370 node_paths=PackedStringArray("back_button")] anchors_preset = 15 @@ -30,6 +31,9 @@ layout_mode = 2 [node name="VideoSettings" parent="PanelContainer/VBoxContainer" unique_id=201104966 instance=ExtResource("4_cw13b")] layout_mode = 2 +[node name="LanguageSettings" parent="PanelContainer/VBoxContainer" unique_id=1730937504 instance=ExtResource("6_lang")] +layout_mode = 2 + [node name="BackButton" type="Button" parent="PanelContainer/VBoxContainer" unique_id=200110196] unique_name_in_owner = true layout_mode = 2