aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Hop311 <Hop3114@gmail.com>2023-03-30 15:04:58 +0200
committer GitHub <noreply@github.com>2023-03-30 15:04:58 +0200
commit3384b21177a160f7192a2e4877eea3b29880bf4e (patch)
treedb9c9a37a187e15ef494a700f8afe5d65c3a8b78
parent8f213935bdea2400b6809f9d5db45dde3416dedc (diff)
Added Localisation (#77)
* Added Localisation * Removed `.gdignore`s. * Localisation dir path and Locale name cleanup * Incomplete entry warnings + README
-rw-r--r--extension/src/LoadLocalisation.cpp111
-rw-r--r--extension/src/LoadLocalisation.hpp29
-rw-r--r--extension/src/register_types.cpp9
-rw-r--r--game/default_bus_layout.tres4
-rw-r--r--game/localisation/README.md16
-rw-r--r--game/localisation/en_GB/menus.csv52
-rw-r--r--game/localisation/en_GB/menus.csv.import3
-rw-r--r--game/localisation/en_US/menus.csv52
-rw-r--r--game/localisation/en_US/menus.csv.import3
-rw-r--r--game/localisation/fr_FR/menus.csv52
-rw-r--r--game/localisation/fr_FR/menus.csv.import3
-rw-r--r--game/project.godot2
-rw-r--r--game/src/Autoload/Events.gd1
-rw-r--r--game/src/Autoload/Events/Localisation.gd30
-rw-r--r--game/src/CreditsMenu/CreditsMenu.tscn2
-rw-r--r--game/src/GameSession/GameSessionMenu.tscn4
-rw-r--r--game/src/LobbyMenu/LobbyMenu.tscn4
-rw-r--r--game/src/LocaleButton.gd60
-rw-r--r--game/src/MainMenu/MainMenu.tscn14
-rw-r--r--game/src/MainMenu/ReleaseInfoBox.gd16
-rw-r--r--game/src/MainMenu/ReleaseInfoBox.tscn10
-rw-r--r--game/src/OptionMenu/GeneralTab.tscn28
-rw-r--r--game/src/OptionMenu/OptionsMenu.gd4
-rw-r--r--game/src/OptionMenu/SettingNodes/SettingHSlider.gd4
-rw-r--r--game/src/OptionMenu/SettingNodes/SettingOptionButton.gd4
-rw-r--r--game/src/OptionMenu/VideoTab.tscn39
-rw-r--r--game/src/OptionMenu/VolumeGrid.gd9
27 files changed, 475 insertions, 90 deletions
diff --git a/extension/src/LoadLocalisation.cpp b/extension/src/LoadLocalisation.cpp
new file mode 100644
index 0000000..c95c08b
--- /dev/null
+++ b/extension/src/LoadLocalisation.cpp
@@ -0,0 +1,111 @@
+#include "LoadLocalisation.hpp"
+
+#include <godot_cpp/variant/utility_functions.hpp>
+#include <godot_cpp/classes/file_access.hpp>
+#include <godot_cpp/classes/dir_access.hpp>
+#include <godot_cpp/classes/translation_server.hpp>
+
+using namespace godot;
+using namespace OpenVic2;
+
+LoadLocalisation *LoadLocalisation::singleton = nullptr;
+
+void LoadLocalisation::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("load_file", "file_path", "locale"), &LoadLocalisation::load_file);
+ ClassDB::bind_method(D_METHOD("load_locale_dir", "dir_path", "locale"), &LoadLocalisation::load_locale_dir);
+ ClassDB::bind_method(D_METHOD("load_localisation_dir", "dir_path"), &LoadLocalisation::load_localisation_dir);
+}
+
+LoadLocalisation *LoadLocalisation::get_singleton() {
+ return singleton;
+}
+
+LoadLocalisation::LoadLocalisation() {
+ ERR_FAIL_COND(singleton != nullptr);
+ singleton = this;
+}
+
+LoadLocalisation::~LoadLocalisation() {
+ ERR_FAIL_COND(singleton != this);
+ singleton = nullptr;
+}
+
+Error LoadLocalisation::_load_file_into_translation(String const& file_path, Ref<Translation> translation) {
+ Ref<FileAccess> file = FileAccess::open(file_path, FileAccess::ModeFlags::READ);
+ Error err = FileAccess::get_open_error();
+ if (err != OK || file.is_null()) {
+ UtilityFunctions::push_error("Failed to load localisation file: ", file_path);
+ return err == OK ? FAILED : err;
+ }
+ int line_number = 0;
+ while (!file->eof_reached()) {
+ PackedStringArray line = file->get_csv_line();
+ line_number++;
+ if (line.size() < 2 || line[0].is_empty() || line[1].is_empty()) {
+ if (!line[0].is_empty())
+ UtilityFunctions::push_warning("Key \"", line[0], "\" missing value on line ", line_number, " in file: ", file_path);
+ else if (line.size() >= 2 && !line[1].is_empty())
+ UtilityFunctions::push_warning("Value \"", line[1], "\" missing key on line ", line_number, " in file: ", file_path);
+ continue;
+ }
+ translation->add_message(line[0], line[1].c_unescape());
+ }
+ return OK;
+}
+
+Ref<Translation> LoadLocalisation::_get_translation(String const& locale) {
+ TranslationServer *server = TranslationServer::get_singleton();
+ Ref<Translation> translation = server->get_translation_object(locale);
+ if (translation.is_null() || translation->get_locale() != locale) {
+ translation.instantiate();
+ translation->set_locale(locale);
+ server->add_translation(translation);
+ }
+ return translation;
+}
+
+Error LoadLocalisation::load_file(String const& file_path, String const& locale) {
+ return _load_file_into_translation(file_path, _get_translation(locale));
+}
+
+/* REQUIREMENTS
+ * FS-18, FS-24, FS-25
+ */
+Error LoadLocalisation::load_locale_dir(String const& dir_path, String const& locale) {
+ Ref<Translation> translation = _get_translation(locale);
+ if (DirAccess::dir_exists_absolute(dir_path)) {
+ Error err = OK;
+ for (String const& file_name : DirAccess::get_files_at(dir_path)) {
+ if (file_name.get_extension().to_lower() == "csv") {
+ String file_path = dir_path.path_join(file_name);
+ if (_load_file_into_translation(file_path, translation) != OK)
+ err = FAILED;
+ }
+ }
+ return err;
+ }
+ UtilityFunctions::push_error("Locale directory does not exist: ", dir_path);
+ return FAILED;
+}
+
+/* REQUIREMENTS
+ * FS-23
+ */
+Error LoadLocalisation::load_localisation_dir(String const& dir_path) {
+ if (DirAccess::dir_exists_absolute(dir_path)) {
+ TranslationServer *server = TranslationServer::get_singleton();
+ Error err = OK;
+ for (String const& locale_name : DirAccess::get_directories_at(dir_path)) {
+ if (locale_name == server->standardize_locale(locale_name)) {
+ if (load_locale_dir(dir_path.path_join(locale_name), locale_name) != OK)
+ err = FAILED;
+ } else {
+ err = FAILED;
+ UtilityFunctions::push_error("Invalid locale directory name: ", locale_name);
+ }
+ }
+ return err;
+ }
+ UtilityFunctions::push_error("Localisation directory does not exist: ", dir_path);
+ return FAILED;
+}
diff --git a/extension/src/LoadLocalisation.hpp b/extension/src/LoadLocalisation.hpp
new file mode 100644
index 0000000..90f3158
--- /dev/null
+++ b/extension/src/LoadLocalisation.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <godot_cpp/core/class_db.hpp>
+#include <godot_cpp/classes/translation.hpp>
+
+namespace OpenVic2 {
+ class LoadLocalisation : public godot::Object
+ {
+ GDCLASS(LoadLocalisation, godot::Object)
+
+ static LoadLocalisation *singleton;
+
+ godot::Error _load_file_into_translation(godot::String const& file_path, godot::Ref<godot::Translation> translation);
+ godot::Ref<godot::Translation> _get_translation(godot::String const& locale);
+
+ protected:
+ static void _bind_methods();
+
+ public:
+ static LoadLocalisation *get_singleton();
+
+ LoadLocalisation();
+ ~LoadLocalisation();
+
+ godot::Error load_file(godot::String const& file_path, godot::String const& locale);
+ godot::Error load_locale_dir(godot::String const& dir_path, godot::String const& locale);
+ godot::Error load_localisation_dir(godot::String const& dir_path);
+ };
+}
diff --git a/extension/src/register_types.cpp b/extension/src/register_types.cpp
index aac38b9..d1613a5 100644
--- a/extension/src/register_types.cpp
+++ b/extension/src/register_types.cpp
@@ -8,6 +8,7 @@
#include "TestSingleton.hpp"
#include "Simulation.hpp"
#include "Checksum.hpp"
+#include "LoadLocalisation.hpp"
using namespace godot;
using namespace OpenVic2;
@@ -15,6 +16,7 @@ using namespace OpenVic2;
static TestSingleton* _test_singleton;
static Simulation* _simulation;
static Checksum* _checksum;
+static LoadLocalisation* _load_localisation;
void initialize_openvic2_types(ModuleInitializationLevel p_level)
{
@@ -34,6 +36,10 @@ void initialize_openvic2_types(ModuleInitializationLevel p_level)
_checksum = memnew(Checksum);
Engine::get_singleton()->register_singleton("Checksum", Checksum::get_singleton());
+ ClassDB::register_class<LoadLocalisation>();
+ _load_localisation = memnew(LoadLocalisation);
+ Engine::get_singleton()->register_singleton("LoadLocalisation", LoadLocalisation::get_singleton());
+
}
void uninitialize_openvic2_types(ModuleInitializationLevel p_level) {
@@ -49,6 +55,9 @@ void uninitialize_openvic2_types(ModuleInitializationLevel p_level) {
Engine::get_singleton()->unregister_singleton("Checksum");
memdelete(_checksum);
+
+ Engine::get_singleton()->unregister_singleton("LoadLocalisation");
+ memdelete(_load_localisation);
}
extern "C"
diff --git a/game/default_bus_layout.tres b/game/default_bus_layout.tres
index 87413af..d6f0c67 100644
--- a/game/default_bus_layout.tres
+++ b/game/default_bus_layout.tres
@@ -1,13 +1,13 @@
[gd_resource type="AudioBusLayout" format=3 uid="uid://cquqx51trot64"]
[resource]
-bus/1/name = &"Music"
+bus/1/name = &"MUSIC_BUS"
bus/1/solo = false
bus/1/mute = false
bus/1/bypass_fx = false
bus/1/volume_db = 0.0
bus/1/send = &"Master"
-bus/2/name = &"SFX"
+bus/2/name = &"SFX_BUS"
bus/2/solo = false
bus/2/mute = false
bus/2/bypass_fx = false
diff --git a/game/localisation/README.md b/game/localisation/README.md
new file mode 100644
index 0000000..401517f
--- /dev/null
+++ b/game/localisation/README.md
@@ -0,0 +1,16 @@
+# Localisation
+
+This folder contains localisations for in-game text. Each sub-folder must be named with a standard locale code, e.g. `en_GB`, to which the localisations contained within it shall apply (Godot's supported locale codes are listed [here](https://docs.godotengine.org/en/latest/tutorials/i18n/locales.html)). These folders contain `.csv` files where each line is interpreted as a key-value pair. Empty lines allow for spacing out/separating sections, and any further entries beyond the first two on a line are ignored, which can be used to add comments at the end of lines. Lines with their key and value empty are skipped, allowing free-standing comments with no preceeding localisation, but lines with only one of their key or value empty, while not loaded as a localisation, will still result in warnings about incomplete entries.
+
+```
+,, Example Localisation Comment
+EXAMPLE_KEY,Example Value
+ANOTHER_EXAMPLE,Another Example, This is a comment
+
+,, Entries with empty keys/values are skipped but can still produce warnings
+THIS,, produces a warning!
+,As, does this!
+,, This doesn't!
+BUT_THIS_DOES
+AND_THIS,
+```
diff --git a/game/localisation/en_GB/menus.csv b/game/localisation/en_GB/menus.csv
new file mode 100644
index 0000000..27a0858
--- /dev/null
+++ b/game/localisation/en_GB/menus.csv
@@ -0,0 +1,52 @@
+,, Main Menu
+MAINMENU_TITLE,OpenVic2
+MAINMENU_NEW_GAME,New Game
+MAINMENU_CONTINUE,Continue
+MAINMENU_MULTIPLAYER,Multiplayer
+MAINMENU_OPTIONS,Options
+MAINMENU_CREDITS,Credits
+MAINMENU_EXIT,Exit
+MAINMENU_CHECKSUM,Checksum %s
+
+,, Options
+OPTIONS_RESET,R
+OPTIONS_BACK,X
+
+,, General Tab
+OPTIONS_GENERAL_SAVEFORMAT,Savegame Format
+OPTIONS_GENERAL_BINARY,Binary
+OPTIONS_GENERAL_TEXT,Text
+OPTIONS_GENERAL_AUTOSAVE,Autosave Interval
+OPTIONS_GENERAL_AUTOSAVE_MONTHLY,Monthly
+OPTIONS_GENERAL_AUTOSAVE_BIMONTHLY,Bi-Monthly
+OPTIONS_GENERAL_AUTOSAVE_YEARLY,Yearly
+OPTIONS_GENERAL_AUTOSAVE_BIYEARLY,Bi-Yearly
+OPTIONS_GENERAL_AUTOSAVE_NEVER,Never
+OPTIONS_GENERAL_LANGUAGE,Language
+
+,, Video Tab
+OPTIONS_VIDEO_RESOLUTION,Resolution
+OPTIONS_VIDEO_SCREEN_MODE,Screen Mode
+OPTIONS_VIDEO_FULLSCREEN,Fullscreen
+OPTIONS_VIDEO_BORDERLESS,Borderless
+OPTIONS_VIDEO_WINDOWED,Windowed
+OPTIONS_VIDEO_MONITOR_SELECTION,Monitor Selection
+OPTIONS_VIDEO_REFRESH_RATE,Refresh Rate
+OPTIONS_VIDEO_REFRESH_RATE_TOOLTIP,Only change from VSYNC if you are having issues with screen tearing.
+OPTIONS_VIDEO_QUALITY,Quality Preset
+
+,, Sound Tab
+MASTER_BUS,Master Volume
+MUSIC_BUS,Music Volume
+SFX_BUS,SFX Volume
+
+,, Credits Menu
+CREDITS_BACK,Back to Main Menu
+
+,, Game Lobby
+GAMELOBBY_START,Start Game
+GAMELOBBY_BACK,Back
+
+,, Game Session Menu
+GAMESESSIONMENU_RESIGN,Resign
+GAMESESSIONMENU_CLOSE,Close
diff --git a/game/localisation/en_GB/menus.csv.import b/game/localisation/en_GB/menus.csv.import
new file mode 100644
index 0000000..8dd0c09
--- /dev/null
+++ b/game/localisation/en_GB/menus.csv.import
@@ -0,0 +1,3 @@
+[remap]
+
+importer="keep"
diff --git a/game/localisation/en_US/menus.csv b/game/localisation/en_US/menus.csv
new file mode 100644
index 0000000..27a0858
--- /dev/null
+++ b/game/localisation/en_US/menus.csv
@@ -0,0 +1,52 @@
+,, Main Menu
+MAINMENU_TITLE,OpenVic2
+MAINMENU_NEW_GAME,New Game
+MAINMENU_CONTINUE,Continue
+MAINMENU_MULTIPLAYER,Multiplayer
+MAINMENU_OPTIONS,Options
+MAINMENU_CREDITS,Credits
+MAINMENU_EXIT,Exit
+MAINMENU_CHECKSUM,Checksum %s
+
+,, Options
+OPTIONS_RESET,R
+OPTIONS_BACK,X
+
+,, General Tab
+OPTIONS_GENERAL_SAVEFORMAT,Savegame Format
+OPTIONS_GENERAL_BINARY,Binary
+OPTIONS_GENERAL_TEXT,Text
+OPTIONS_GENERAL_AUTOSAVE,Autosave Interval
+OPTIONS_GENERAL_AUTOSAVE_MONTHLY,Monthly
+OPTIONS_GENERAL_AUTOSAVE_BIMONTHLY,Bi-Monthly
+OPTIONS_GENERAL_AUTOSAVE_YEARLY,Yearly
+OPTIONS_GENERAL_AUTOSAVE_BIYEARLY,Bi-Yearly
+OPTIONS_GENERAL_AUTOSAVE_NEVER,Never
+OPTIONS_GENERAL_LANGUAGE,Language
+
+,, Video Tab
+OPTIONS_VIDEO_RESOLUTION,Resolution
+OPTIONS_VIDEO_SCREEN_MODE,Screen Mode
+OPTIONS_VIDEO_FULLSCREEN,Fullscreen
+OPTIONS_VIDEO_BORDERLESS,Borderless
+OPTIONS_VIDEO_WINDOWED,Windowed
+OPTIONS_VIDEO_MONITOR_SELECTION,Monitor Selection
+OPTIONS_VIDEO_REFRESH_RATE,Refresh Rate
+OPTIONS_VIDEO_REFRESH_RATE_TOOLTIP,Only change from VSYNC if you are having issues with screen tearing.
+OPTIONS_VIDEO_QUALITY,Quality Preset
+
+,, Sound Tab
+MASTER_BUS,Master Volume
+MUSIC_BUS,Music Volume
+SFX_BUS,SFX Volume
+
+,, Credits Menu
+CREDITS_BACK,Back to Main Menu
+
+,, Game Lobby
+GAMELOBBY_START,Start Game
+GAMELOBBY_BACK,Back
+
+,, Game Session Menu
+GAMESESSIONMENU_RESIGN,Resign
+GAMESESSIONMENU_CLOSE,Close
diff --git a/game/localisation/en_US/menus.csv.import b/game/localisation/en_US/menus.csv.import
new file mode 100644
index 0000000..8dd0c09
--- /dev/null
+++ b/game/localisation/en_US/menus.csv.import
@@ -0,0 +1,3 @@
+[remap]
+
+importer="keep"
diff --git a/game/localisation/fr_FR/menus.csv b/game/localisation/fr_FR/menus.csv
new file mode 100644
index 0000000..8e8a7ad
--- /dev/null
+++ b/game/localisation/fr_FR/menus.csv
@@ -0,0 +1,52 @@
+,, Main Menu
+MAINMENU_TITLE,OpenVic2
+MAINMENU_NEW_GAME,Nouveau Jeu
+MAINMENU_CONTINUE,Continuer
+MAINMENU_MULTIPLAYER,Multijouer
+MAINMENU_OPTIONS,Options
+MAINMENU_CREDITS,Credits
+MAINMENU_EXIT,Quitter
+MAINMENU_CHECKSUM,Somme de contrôle %s
+
+,, Options
+OPTIONS_RESET,R
+OPTIONS_BACK,X
+
+,, General Tab
+OPTIONS_GENERAL_SAVEFORMAT,Format de Sauvegarde
+OPTIONS_GENERAL_BINARY,Binaire
+OPTIONS_GENERAL_TEXT,Texte
+OPTIONS_GENERAL_AUTOSAVE,Intervalle d'Enregistrement Automatique
+OPTIONS_GENERAL_AUTOSAVE_MONTHLY,Mensuel
+OPTIONS_GENERAL_AUTOSAVE_BIMONTHLY,Bimensuel
+OPTIONS_GENERAL_AUTOSAVE_YEARLY,Annuel
+OPTIONS_GENERAL_AUTOSAVE_BIYEARLY,Bisannuel
+OPTIONS_GENERAL_AUTOSAVE_NEVER,Jamais
+OPTIONS_GENERAL_LANGUAGE,Langue
+
+,, Video Tab
+OPTIONS_VIDEO_RESOLUTION,Résolution
+OPTIONS_VIDEO_SCREEN_MODE,Mode Écran
+OPTIONS_VIDEO_FULLSCREEN,Plein Écran
+OPTIONS_VIDEO_BORDERLESS,Sans Bordure
+OPTIONS_VIDEO_WINDOWED,Fenêtré
+OPTIONS_VIDEO_MONITOR_SELECTION,Sélection du Moniteur
+OPTIONS_VIDEO_REFRESH_RATE,Taux de Rafraîchissement
+OPTIONS_VIDEO_REFRESH_RATE_TOOLTIP,Ne changez de VSYNC que si vous rencontrez des problèmes de déchirement d'écran.
+OPTIONS_VIDEO_QUALITY,Préréglage de la Qualité
+
+,, Sound Tab
+MASTER_BUS,Volume Principal
+MUSIC_BUS,Volume de la Musique
+SFX_BUS,Volume d'Effets Spéciaux
+
+,, Credits Menu
+CREDITS_BACK,Retour au Menu Principal
+
+,, Game Lobby
+GAMELOBBY_START,Démarrer Jeu
+GAMELOBBY_BACK,Retourner
+
+,, Game Session Menu
+GAMESESSIONMENU_RESIGN,Démissionner
+GAMESESSIONMENU_CLOSE,Fermer
diff --git a/game/localisation/fr_FR/menus.csv.import b/game/localisation/fr_FR/menus.csv.import
new file mode 100644
index 0000000..8dd0c09
--- /dev/null
+++ b/game/localisation/fr_FR/menus.csv.import
@@ -0,0 +1,3 @@
+[remap]
+
+importer="keep"
diff --git a/game/project.godot b/game/project.godot
index b2a3098..363bbc1 100644
--- a/game/project.godot
+++ b/game/project.godot
@@ -50,8 +50,10 @@ locale/translation_remaps={}
locale/fallback="en_GB"
locale/locale_filter_mode=0
locale/country_short_name={
+"United Kingdom": "UK",
"United States of America": "USA"
}
+locale/localisation_path="res://localisation"
[memory]
diff --git a/game/src/Autoload/Events.gd b/game/src/Autoload/Events.gd
index f0f60b7..25a185f 100644
--- a/game/src/Autoload/Events.gd
+++ b/game/src/Autoload/Events.gd
@@ -1,3 +1,4 @@
extends Node
var Options = preload("Events/Options.gd").new()
+var Localisation = preload("Events/Localisation.gd").new()
diff --git a/game/src/Autoload/Events/Localisation.gd b/game/src/Autoload/Events/Localisation.gd
new file mode 100644
index 0000000..eda7e51
--- /dev/null
+++ b/game/src/Autoload/Events/Localisation.gd
@@ -0,0 +1,30 @@
+extends RefCounted
+
+# REQUIREMENTS
+# * SS-59, SS-60, SS-61
+func get_default_locale() -> String:
+ var locales := TranslationServer.get_loaded_locales()
+ var default_locale := OS.get_locale()
+ if default_locale in locales:
+ return default_locale
+ var default_language := OS.get_locale_language()
+ for locale in locales:
+ if locale.begins_with(default_language):
+ return default_language
+ return ProjectSettings.get_setting("internationalization/locale/fallback", "en_GB")
+
+func load_localisation(dir_path : String) -> void:
+ if LoadLocalisation.load_localisation_dir(dir_path) == OK:
+ print("loaded locales: ", TranslationServer.get_loaded_locales())
+ else:
+ push_error("Failed to load localisation directory: ", dir_path)
+
+# REQUIREMENTS
+# * SS-57
+# * FS-17
+func _init():
+ var localisation_dir_path : String = ProjectSettings.get_setting("internationalization/locale/localisation_path", "")
+ if localisation_dir_path.is_empty():
+ push_error("Missing localisation_path setting!")
+ else:
+ load_localisation(localisation_dir_path)
diff --git a/game/src/CreditsMenu/CreditsMenu.tscn b/game/src/CreditsMenu/CreditsMenu.tscn
index d2819d7..6c5f36b 100644
--- a/game/src/CreditsMenu/CreditsMenu.tscn
+++ b/game/src/CreditsMenu/CreditsMenu.tscn
@@ -29,7 +29,7 @@ theme_type_variation = &"BackButtonsMargin"
[node name="BackButton" type="Button" parent="ControlMargin"]
editor_description = "UI-38"
layout_mode = 2
-text = "Back to Main Menu"
+text = "CREDITS_BACK"
[node name="Scroll" type="ScrollContainer" parent="."]
editor_description = "UI-35"
diff --git a/game/src/GameSession/GameSessionMenu.tscn b/game/src/GameSession/GameSessionMenu.tscn
index d6a7ca9..45fff4b 100644
--- a/game/src/GameSession/GameSessionMenu.tscn
+++ b/game/src/GameSession/GameSessionMenu.tscn
@@ -14,7 +14,7 @@ layout_mode = 2
[node name="MainMenuButton" type="Button" parent="VBoxContainer"]
editor_description = "UI-71"
layout_mode = 2
-text = "Resign"
+text = "GAMESESSIONMENU_RESIGN"
[node name="HSeparator" type="HSeparator" parent="VBoxContainer"]
layout_mode = 2
@@ -22,7 +22,7 @@ layout_mode = 2
[node name="CloseButton" type="Button" parent="VBoxContainer"]
editor_description = "UI-80"
layout_mode = 2
-text = "Close"
+text = "GAMESESSIONMENU_CLOSE"
[connection signal="pressed" from="VBoxContainer/MainMenuButton" to="." method="_on_to_main_menu_pressed"]
[connection signal="pressed" from="VBoxContainer/CloseButton" to="." method="_on_close_button_pressed"]
diff --git a/game/src/LobbyMenu/LobbyMenu.tscn b/game/src/LobbyMenu/LobbyMenu.tscn
index fcf2263..528e7ae 100644
--- a/game/src/LobbyMenu/LobbyMenu.tscn
+++ b/game/src/LobbyMenu/LobbyMenu.tscn
@@ -34,7 +34,7 @@ size_flags_vertical = 3
[node name="BackButton" type="Button" parent="GameSelectPanel/VBoxContainer"]
editor_description = "UI-37"
layout_mode = 2
-text = "Back"
+text = "GAMELOBBY_BACK"
[node name="Spacer2" type="Control" parent="GameSelectPanel/VBoxContainer"]
custom_minimum_size = Vector2(0, 33)
@@ -71,7 +71,7 @@ size_flags_vertical = 3
editor_description = "UI-43"
layout_mode = 2
disabled = true
-text = "Start Game"
+text = "GAMELOBBY_START"
[node name="Spacer3" type="Control" parent="GameStartPanel/VBoxContainer"]
custom_minimum_size = Vector2(0, 33)
diff --git a/game/src/LocaleButton.gd b/game/src/LocaleButton.gd
index c3c6925..2b717a4 100644
--- a/game/src/LocaleButton.gd
+++ b/game/src/LocaleButton.gd
@@ -1,40 +1,49 @@
extends OptionButton
-const section_name : String = "Localization"
-const setting_name : String = "Locale"
+const section_name : String = "localisation"
+const setting_name : String = "locale"
-var _locales_country_rename : Dictionary
-var _locales_list : Array[String]
+var _default_locale_index : int
func _ready():
- _locales_country_rename = ProjectSettings.get_setting("internationalization/locale/country_short_name", {})
+ var locales_country_rename : Dictionary = ProjectSettings.get_setting("internationalization/locale/country_short_name", {})
- _locales_list = [TranslationServer.get_locale()]
- _locales_list.append_array(TranslationServer.get_loaded_locales())
+ var locales_list = TranslationServer.get_loaded_locales()
+ var default_locale := Events.Localisation.get_default_locale()
+ if default_locale not in locales_list:
+ locales_list.push_back(default_locale)
- for locale in _locales_list:
+ for locale in locales_list:
+ # locale_name consists of a compulsory language name and optional script
+ # and country names, in the format: "<language>[ (script)][, country]"
var locale_name := TranslationServer.get_locale_name(locale)
- var locale_first_part := locale_name.get_slice(", ", 0)
- var locale_second_part := locale_name.substr(locale_first_part.length() + 2)
- if locale_second_part in _locales_country_rename:
- locale_second_part = _locales_country_rename[locale_second_part]
+ var comma_idx := locale_name.find(", ")
+ if comma_idx != -1:
+ var locale_country_name := locale_name.substr(comma_idx + 2)
+ locale_country_name = locales_country_rename.get(locale_country_name, "")
+ if not locale_country_name.is_empty():
+ locale_name = locale_name.left(comma_idx + 2) + locale_country_name
- add_item("%s, %s" % [locale_first_part, locale_second_part])
+ add_item(locale_name)
+ set_item_metadata(item_count - 1, locale)
+
+ if locale == default_locale:
+ _default_locale_index = item_count - 1
Events.Options.load_settings.connect(load_setting)
Events.Options.save_settings.connect(save_setting)
-
-func _notification(what):
+
+func _notification(what : int):
match what:
NOTIFICATION_TRANSLATION_CHANGED:
_select_locale_by_string(TranslationServer.get_locale())
func _valid_index(index : int) -> bool:
- return 0 <= index and index < _locales_list.size()
+ return 0 <= index and index < item_count
func load_setting(file : ConfigFile) -> void:
if file == null: return
- var load_value = file.get_value(section_name, setting_name, TranslationServer.get_locale())
+ var load_value = file.get_value(section_name, setting_name, Events.Localisation.get_default_locale())
match typeof(load_value):
TYPE_STRING, TYPE_STRING_NAME:
if _select_locale_by_string(load_value as String):
@@ -42,28 +51,29 @@ func load_setting(file : ConfigFile) -> void:
return
push_error("Setting value '%s' invalid for setting [%s] %s" % [load_value, section_name, setting_name])
reset_setting()
-
+
func _select_locale_by_string(locale : String) -> bool:
- var locale_index := _locales_list.find(locale)
- if locale_index != -1:
- selected = locale_index
- return true
+ for idx in item_count:
+ if get_item_metadata(idx) == locale:
+ selected = idx
+ return true
+ selected = _default_locale_index
return false
# REQUIREMENTS:
# * UIFUN-74
func save_setting(file : ConfigFile) -> void:
if file == null: return
- file.set_value(section_name, setting_name, _locales_list[selected])
+ file.set_value(section_name, setting_name, get_item_metadata(selected))
func reset_setting() -> void:
- selected = _locales_list.find(TranslationServer.get_locale())
+ _select_locale_by_string(TranslationServer.get_locale())
# REQUIREMENTS:
# * SS-58
func _on_item_selected(index : int) -> void:
if _valid_index(index):
- TranslationServer.set_locale(_locales_list[index])
+ TranslationServer.set_locale(get_item_metadata(index))
Events.Options.save_settings_to_file.call_deferred()
else:
push_error("Invalid LocaleButton index: %d" % index)
diff --git a/game/src/MainMenu/MainMenu.tscn b/game/src/MainMenu/MainMenu.tscn
index 10bf526..5fb6ca9 100644
--- a/game/src/MainMenu/MainMenu.tscn
+++ b/game/src/MainMenu/MainMenu.tscn
@@ -34,7 +34,7 @@ layout_mode = 2
size_flags_vertical = 6
size_flags_stretch_ratio = 1.5
theme_type_variation = &"TitleLabel"
-text = "OpenVic2"
+text = "MAINMENU_TITLE"
horizontal_alignment = 1
vertical_alignment = 1
@@ -60,7 +60,7 @@ focus_neighbor_right = NodePath("../ContinueButton")
focus_next = NodePath("../ContinueButton")
focus_previous = NodePath("../ExitButton")
theme_type_variation = &"TitleButton"
-text = "New Game"
+text = "MAINMENU_NEW_GAME"
clip_text = true
[node name="ContinueButton" type="Button" parent="Panel/VBox/Margin/ButtonList"]
@@ -72,7 +72,7 @@ focus_next = NodePath("../MultiplayerButton")
focus_previous = NodePath("../NewGameButton")
theme_type_variation = &"TitleButton"
disabled = true
-text = "Continue"
+text = "MAINMENU_CONTINUE"
clip_text = true
[node name="MultiplayerButton" type="Button" parent="Panel/VBox/Margin/ButtonList"]
@@ -84,7 +84,7 @@ focus_neighbor_right = NodePath("../OptionsButton")
focus_next = NodePath("../OptionsButton")
focus_previous = NodePath("../ContinueButton")
theme_type_variation = &"TitleButton"
-text = "Multiplayer"
+text = "MAINMENU_MULTIPLAYER"
clip_text = true
[node name="OptionsButton" type="Button" parent="Panel/VBox/Margin/ButtonList"]
@@ -96,7 +96,7 @@ focus_neighbor_right = NodePath("../CreditsButton")
focus_next = NodePath("../CreditsButton")
focus_previous = NodePath("../MultiplayerButton")
theme_type_variation = &"TitleButton"
-text = "Options"
+text = "MAINMENU_OPTIONS"
clip_text = true
[node name="CreditsButton" type="Button" parent="Panel/VBox/Margin/ButtonList"]
@@ -108,7 +108,7 @@ focus_neighbor_right = NodePath("../ExitButton")
focus_next = NodePath("../ExitButton")
focus_previous = NodePath("../OptionsButton")
theme_type_variation = &"TitleButton"
-text = "Credits"
+text = "MAINMENU_CREDITS"
clip_text = true
[node name="ExitButton" type="Button" parent="Panel/VBox/Margin/ButtonList"]
@@ -120,7 +120,7 @@ focus_neighbor_right = NodePath("../NewGameButton")
focus_next = NodePath("../NewGameButton")
focus_previous = NodePath("../OptionsButton")
theme_type_variation = &"TitleButton"
-text = "Exit"
+text = "MAINMENU_EXIT"
clip_text = true
[node name="BottomSpace" type="Control" parent="Panel/VBox"]
diff --git a/game/src/MainMenu/ReleaseInfoBox.gd b/game/src/MainMenu/ReleaseInfoBox.gd
index 48686f3..ca03af3 100644
--- a/game/src/MainMenu/ReleaseInfoBox.gd
+++ b/game/src/MainMenu/ReleaseInfoBox.gd
@@ -9,6 +9,8 @@ var _commit_label : Button
@export
var _checksum_label : Button
+var _checksum : String = "????"
+
# REQUIREMENTS:
# * UIFUN-97
func _ready():
@@ -17,9 +19,17 @@ func _ready():
_commit_label.text = _GIT_INFO_.short_hash
_commit_label.tooltip_text = _GIT_INFO_.commit_hash
# UI-111
- _checksum_label.tooltip_text = "Checksum " + Checksum.get_checksum_text()
- _checksum_label.text = "(" + Checksum.get_checksum_text().substr(0, 4) + ")"
+ _checksum = Checksum.get_checksum_text()
+ _update_checksum_label_text()
+
+func _notification(what : int):
+ match what:
+ NOTIFICATION_TRANSLATION_CHANGED:
+ _update_checksum_label_text()
+func _update_checksum_label_text() -> void:
+ _checksum_label.tooltip_text = tr("MAINMENU_CHECKSUM") % _checksum
+ _checksum_label.text = "(%s)" % _checksum.substr(0, 4)
func _on_version_label_pressed():
DisplayServer.clipboard_set(_GIT_INFO_.tag)
@@ -28,4 +38,4 @@ func _on_commit_label_pressed():
DisplayServer.clipboard_set(_GIT_INFO_.commit_hash)
func _on_checksum_label_pressed():
- DisplayServer.clipboard_set(Checksum.get_checksum_text())
+ DisplayServer.clipboard_set(_checksum)
diff --git a/game/src/MainMenu/ReleaseInfoBox.tscn b/game/src/MainMenu/ReleaseInfoBox.tscn
index d15ae31..821982b 100644
--- a/game/src/MainMenu/ReleaseInfoBox.tscn
+++ b/game/src/MainMenu/ReleaseInfoBox.tscn
@@ -11,25 +11,25 @@ _checksum_label = NodePath("ChecksumLabel")
[node name="VersionLabel" type="Button" parent="."]
layout_mode = 2
-tooltip_text = "OpenVic2 v0.01 \"Primum Mobile\""
+tooltip_text = "VERSION_MISSING"
theme_type_variation = &"VersionLabel"
-text = "v0.01"
+text = "VERSION_MISSING"
flat = true
alignment = 0
[node name="CommitLabel" type="Button" parent="."]
layout_mode = 2
theme_type_variation = &"CommitLabel"
-text = "ffffffff"
+text = "????????"
flat = true
alignment = 0
[node name="ChecksumLabel" type="Button" parent="."]
editor_description = "UI-111"
layout_mode = 2
-tooltip_text = "Checksum 00000000"
+tooltip_text = "CHECKSUM_MISSING"
theme_type_variation = &"ChecksumLabel"
-text = "(0000)"
+text = "(????)"
flat = true
alignment = 0
diff --git a/game/src/OptionMenu/GeneralTab.tscn b/game/src/OptionMenu/GeneralTab.tscn
index b38f548..a9223af 100644
--- a/game/src/OptionMenu/GeneralTab.tscn
+++ b/game/src/OptionMenu/GeneralTab.tscn
@@ -26,7 +26,7 @@ columns = 2
[node name="SavegameFormatLabel" type="Label" parent="VBoxContainer/GridContainer"]
layout_mode = 2
-text = "Savegame Format"
+text = "OPTIONS_GENERAL_SAVEFORMAT"
[node name="SavegameFormatSelector" type="OptionButton" parent="VBoxContainer/GridContainer"]
editor_description = "UI-50"
@@ -34,18 +34,18 @@ layout_mode = 2
focus_neighbor_bottom = NodePath("../AutosaveIntervalSelector")
item_count = 2
selected = 0
-popup/item_0/text = "Binary"
+popup/item_0/text = "OPTIONS_GENERAL_BINARY"
popup/item_0/id = 0
-popup/item_1/text = "Text"
+popup/item_1/text = "OPTIONS_GENERAL_TEXT"
popup/item_1/id = 1
script = ExtResource("2_msx2u")
-section_name = "General"
-setting_name = "Savegame Format"
+section_name = "general"
+setting_name = "savegame_format"
default_selected = 0
[node name="AutosaveIntervalLabel" type="Label" parent="VBoxContainer/GridContainer"]
layout_mode = 2
-text = "Autosave Interval"
+text = "OPTIONS_GENERAL_AUTOSAVE"
horizontal_alignment = 1
[node name="AutosaveIntervalSelector" type="OptionButton" parent="VBoxContainer/GridContainer"]
@@ -55,24 +55,24 @@ focus_neighbor_top = NodePath("../SavegameFormatSelector")
focus_neighbor_bottom = NodePath("../LocaleButton")
item_count = 5
selected = 0
-popup/item_0/text = "Monthly"
+popup/item_0/text = "OPTIONS_GENERAL_AUTOSAVE_MONTHLY"
popup/item_0/id = 0
-popup/item_1/text = "Bi-Monthly"
+popup/item_1/text = "OPTIONS_GENERAL_AUTOSAVE_BIMONTHLY"
popup/item_1/id = 1
-popup/item_2/text = "Bi-Yearly"
+popup/item_2/text = "OPTIONS_GENERAL_AUTOSAVE_YEARLY"
popup/item_2/id = 2
-popup/item_3/text = "Yearly"
+popup/item_3/text = "OPTIONS_GENERAL_AUTOSAVE_BIYEARLY"
popup/item_3/id = 3
-popup/item_4/text = "Never"
+popup/item_4/text = "OPTIONS_GENERAL_AUTOSAVE_NEVER"
popup/item_4/id = 4
script = ExtResource("2_t06tb")
-section_name = "General"
-setting_name = "Autosave Interval"
+section_name = "general"
+setting_name = "autosave_interval"
default_selected = 0
[node name="LocaleLabel" type="Label" parent="VBoxContainer/GridContainer"]
layout_mode = 2
-text = "Language"
+text = "OPTIONS_GENERAL_LANGUAGE"
[node name="LocaleButton" parent="VBoxContainer/GridContainer" instance=ExtResource("2_5cfd7")]
editor_description = "UI-79"
diff --git a/game/src/OptionMenu/OptionsMenu.gd b/game/src/OptionMenu/OptionsMenu.gd
index d5f128c..5f6a088 100644
--- a/game/src/OptionMenu/OptionsMenu.gd
+++ b/game/src/OptionMenu/OptionsMenu.gd
@@ -20,7 +20,7 @@ func _ready():
# * UI-12
# * UIFUN-14
var reset_button := Button.new()
- reset_button.text = "R"
+ reset_button.text = "OPTIONS_RESET"
reset_button.pressed.connect(Events.Options.try_reset_settings)
button_list.add_child(reset_button)
@@ -28,7 +28,7 @@ func _ready():
# * UI-11
# * UIFUN-17
var back_button := Button.new()
- back_button.text = "X"
+ back_button.text = "OPTIONS_BACK"
back_button.pressed.connect(_on_back_button_pressed)
button_list.add_child(back_button)
get_viewport().get_window().close_requested.connect(_on_window_close_requested)
diff --git a/game/src/OptionMenu/SettingNodes/SettingHSlider.gd b/game/src/OptionMenu/SettingNodes/SettingHSlider.gd
index 6a0e5ed..4e7c9c9 100644
--- a/game/src/OptionMenu/SettingNodes/SettingHSlider.gd
+++ b/game/src/OptionMenu/SettingNodes/SettingHSlider.gd
@@ -2,10 +2,10 @@ extends HSlider
class_name SettingHSlider
@export
-var section_name : String = "Setting"
+var section_name : String = "setting"
@export
-var setting_name : String = "SettingHSlider"
+var setting_name : String = "setting_hslider"
@export
var default_value : float = 0
diff --git a/game/src/OptionMenu/SettingNodes/SettingOptionButton.gd b/game/src/OptionMenu/SettingNodes/SettingOptionButton.gd
index c7b760d..e0b8e4c 100644
--- a/game/src/OptionMenu/SettingNodes/SettingOptionButton.gd
+++ b/game/src/OptionMenu/SettingNodes/SettingOptionButton.gd
@@ -2,10 +2,10 @@ extends OptionButton
class_name SettingOptionButton
@export
-var section_name : String = "Setting"
+var section_name : String = "setting"
@export
-var setting_name : String = "SettingOptionMenu"
+var setting_name : String = "setting_optionbutton"
@export
var default_selected : int = -1:
diff --git a/game/src/OptionMenu/VideoTab.tscn b/game/src/OptionMenu/VideoTab.tscn
index c060b19..c92f7f7 100644
--- a/game/src/OptionMenu/VideoTab.tscn
+++ b/game/src/OptionMenu/VideoTab.tscn
@@ -9,7 +9,6 @@
[node name="Video" type="HBoxContainer" node_paths=PackedStringArray("initial_focus")]
editor_description = "UI-46"
-tooltip_text = "This is my cool and very nice tooltip"
alignment = 1
script = ExtResource("1_jvv62")
initial_focus = NodePath("VBoxContainer/GridContainer/ResolutionSelector")
@@ -29,7 +28,7 @@ columns = 2
[node name="ResolutionLabel" type="Label" parent="VBoxContainer/GridContainer"]
layout_mode = 2
-text = "Resolution"
+text = "OPTIONS_VIDEO_RESOLUTION"
[node name="ResolutionSelector" type="OptionButton" parent="VBoxContainer/GridContainer"]
editor_description = "UI-19"
@@ -40,13 +39,13 @@ selected = 0
popup/item_0/text = "MISSING"
popup/item_0/id = 0
script = ExtResource("1_i8nro")
-section_name = "Video"
-setting_name = "Resolution"
+section_name = "video"
+setting_name = "resolution"
[node name="ScreenModeLabel" type="Label" parent="VBoxContainer/GridContainer"]
editor_description = "UI-44"
layout_mode = 2
-text = "Screen Mode"
+text = "OPTIONS_VIDEO_SCREEN_MODE"
[node name="ScreenModeSelector" type="OptionButton" parent="VBoxContainer/GridContainer"]
layout_mode = 2
@@ -54,19 +53,19 @@ focus_neighbor_top = NodePath("../ResolutionSelector")
focus_neighbor_bottom = NodePath("../MonitorDisplaySelector")
item_count = 3
selected = 0
-popup/item_0/text = "Fullscreen"
+popup/item_0/text = "OPTIONS_VIDEO_FULLSCREEN"
popup/item_0/id = 0
-popup/item_1/text = "Borderless"
+popup/item_1/text = "OPTIONS_VIDEO_BORDERLESS"
popup/item_1/id = 1
-popup/item_2/text = "Windowed"
+popup/item_2/text = "OPTIONS_VIDEO_WINDOWED"
popup/item_2/id = 2
script = ExtResource("2_wa7vw")
-section_name = "Video"
-setting_name = "Mode Selected"
+section_name = "video"
+setting_name = "mode_selected"
[node name="MonitorSelectionLabel" type="Label" parent="VBoxContainer/GridContainer"]
layout_mode = 2
-text = "Monitor Selection"
+text = "OPTIONS_VIDEO_MONITOR_SELECTION"
[node name="MonitorDisplaySelector" type="OptionButton" parent="VBoxContainer/GridContainer"]
layout_mode = 2
@@ -77,17 +76,17 @@ selected = 0
popup/item_0/text = "MISSING"
popup/item_0/id = 0
script = ExtResource("3_y6lyb")
-section_name = "Video"
-setting_name = "Current Screen"
+section_name = "video"
+setting_name = "current_screen"
[node name="RefreshRateLabel" type="Label" parent="VBoxContainer/GridContainer"]
layout_mode = 2
-text = "Refresh Rate"
+text = "OPTIONS_VIDEO_REFRESH_RATE"
[node name="RefreshRateSelector" type="OptionButton" parent="VBoxContainer/GridContainer"]
editor_description = "UI-18"
layout_mode = 2
-tooltip_text = "Only change from VSYNC if you are having issues with screen tearing."
+tooltip_text = "OPTIONS_VIDEO_REFRESH_RATE_TOOLTIP"
focus_neighbor_top = NodePath("../MonitorDisplaySelector")
focus_neighbor_bottom = NodePath("../QualityPresetSelector")
item_count = 8
@@ -109,13 +108,13 @@ popup/item_6/id = 6
popup/item_7/text = "Unlimited"
popup/item_7/id = 7
script = ExtResource("4_381mg")
-section_name = "Video"
-setting_name = "Refresh Rate"
+section_name = "video"
+setting_name = "refresh_rate"
default_selected = 0
[node name="QualityPresetLabel" type="Label" parent="VBoxContainer/GridContainer"]
layout_mode = 2
-text = "Quality Preset"
+text = "OPTIONS_VIDEO_QUALITY"
[node name="QualityPresetSelector" type="OptionButton" parent="VBoxContainer/GridContainer"]
editor_description = "UI-21"
@@ -134,8 +133,8 @@ popup/item_3/id = 3
popup/item_4/text = "Custom"
popup/item_4/id = 4
script = ExtResource("5_srg4v")
-section_name = "Video"
-setting_name = "Quality Preset"
+section_name = "video"
+setting_name = "quality_preset"
default_selected = 1
[connection signal="item_selected" from="VBoxContainer/GridContainer/ResolutionSelector" to="VBoxContainer/GridContainer/ResolutionSelector" method="_on_item_selected"]
diff --git a/game/src/OptionMenu/VolumeGrid.gd b/game/src/OptionMenu/VolumeGrid.gd
index 5b1d13f..46613b4 100644
--- a/game/src/OptionMenu/VolumeGrid.gd
+++ b/game/src/OptionMenu/VolumeGrid.gd
@@ -14,13 +14,16 @@ func get_volume_value_as_db(value : float) -> float:
# linear_to_db consumes a float between 0 and 1 to produce the db value
return linear_to_db(value / RATIO_FOR_LINEAR)
-func add_volume_row(bus_name : StringName, bus_index : int) -> HSlider:
+func add_volume_row(bus_name : String, bus_index : int) -> HSlider:
var volume_label := Label.new()
- volume_label.text = bus_name + " Volume"
+ if bus_name == "Master":
+ volume_label.text = "MASTER_BUS"
+ else:
+ volume_label.text = bus_name
add_child(volume_label)
var volume_slider := SettingHSlider.new()
- volume_slider.section_name = "Audio"
+ volume_slider.section_name = "audio"
volume_slider.setting_name = volume_label.text
volume_slider.custom_minimum_size = Vector2(290, 0)
volume_slider.size_flags_vertical = Control.SIZE_FILL