From 818acb42900267f6c5dc2637e1bd8b7002413a98 Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Fri, 16 Aug 2024 22:19:14 +0800 Subject: [PATCH] Make editor use translation domains How editor plugins use this feature: 1. Pick a unique translation domain name. 2. `_enter_tree()`: load translations into that translation domain. 3. Call `set_translation_domain()` for its root UI node. 4. `_exit_tree()`: remove that translation domain. Plugins can also set the translation domain to `godot.editor` for nested nodes that should use editor translations. `EditorFileDialog` automatically does this. --- core/object/object.cpp | 18 ----- core/string/translation_server.cpp | 101 ++++------------------------- core/string/translation_server.h | 15 +---- doc/classes/TranslationDomain.xml | 1 + doc/classes/TranslationServer.xml | 2 +- editor/editor_node.cpp | 2 + editor/editor_settings.cpp | 2 + editor/editor_translation.cpp | 16 +++-- editor/gui/editor_file_dialog.cpp | 4 ++ editor/project_manager.cpp | 2 + 10 files changed, 38 insertions(+), 125 deletions(-) diff --git a/core/object/object.cpp b/core/object/object.cpp index faf109a13c4..2d9d468d388 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -1540,15 +1540,6 @@ String Object::tr(const StringName &p_message, const StringName &p_context) cons return p_message; } - if (Engine::get_singleton()->is_editor_hint() || Engine::get_singleton()->is_project_manager_hint()) { - String tr_msg = TranslationServer::get_singleton()->extractable_translate(p_message, p_context); - if (!tr_msg.is_empty() && tr_msg != p_message) { - return tr_msg; - } - - return TranslationServer::get_singleton()->tool_translate(p_message, p_context); - } - const Ref domain = TranslationServer::get_singleton()->get_or_add_domain(get_translation_domain()); return domain->translate(p_message, p_context); } @@ -1562,15 +1553,6 @@ String Object::tr_n(const StringName &p_message, const StringName &p_message_plu return p_message_plural; } - if (Engine::get_singleton()->is_editor_hint() || Engine::get_singleton()->is_project_manager_hint()) { - String tr_msg = TranslationServer::get_singleton()->extractable_translate_plural(p_message, p_message_plural, p_n, p_context); - if (!tr_msg.is_empty() && tr_msg != p_message && tr_msg != p_message_plural) { - return tr_msg; - } - - return TranslationServer::get_singleton()->tool_translate_plural(p_message, p_message_plural, p_n, p_context); - } - const Ref domain = TranslationServer::get_singleton()->get_or_add_domain(get_translation_domain()); return domain->translate_plural(p_message, p_message_plural, p_n, p_context); } diff --git a/core/string/translation_server.cpp b/core/string/translation_server.cpp index ae822b43fb4..c6b818a49b3 100644 --- a/core/string/translation_server.cpp +++ b/core/string/translation_server.cpp @@ -525,22 +525,14 @@ void TranslationServer::setup() { #endif } -void TranslationServer::set_tool_translation(const Ref &p_translation) { - tool_translation = p_translation; -} - -Ref TranslationServer::get_tool_translation() const { - return tool_translation; -} - String TranslationServer::get_tool_locale() { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint() || Engine::get_singleton()->is_project_manager_hint()) { - if (TranslationServer::get_singleton()->get_tool_translation().is_valid()) { - return tool_translation->get_locale(); - } else { + const PackedStringArray &locales = editor_domain->get_loaded_locales(); + if (locales.is_empty()) { return "en"; } + return locales[0]; } else { #else { @@ -555,97 +547,23 @@ String TranslationServer::get_tool_locale() { } StringName TranslationServer::tool_translate(const StringName &p_message, const StringName &p_context) const { - if (tool_translation.is_valid()) { - StringName r = tool_translation->get_message(p_message, p_context); - if (r) { - return r; - } - } - return p_message; + return editor_domain->translate(p_message, p_context); } StringName TranslationServer::tool_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { - if (tool_translation.is_valid()) { - StringName r = tool_translation->get_plural_message(p_message, p_message_plural, p_n, p_context); - if (r) { - return r; - } - } - - if (p_n == 1) { - return p_message; - } - return p_message_plural; -} - -void TranslationServer::set_property_translation(const Ref &p_translation) { - property_translation = p_translation; + return editor_domain->translate_plural(p_message, p_message_plural, p_n, p_context); } StringName TranslationServer::property_translate(const StringName &p_message, const StringName &p_context) const { - if (property_translation.is_valid()) { - StringName r = property_translation->get_message(p_message, p_context); - if (r) { - return r; - } - } - return p_message; -} - -void TranslationServer::set_doc_translation(const Ref &p_translation) { - doc_translation = p_translation; + return property_domain->translate(p_message, p_context); } StringName TranslationServer::doc_translate(const StringName &p_message, const StringName &p_context) const { - if (doc_translation.is_valid()) { - StringName r = doc_translation->get_message(p_message, p_context); - if (r) { - return r; - } - } - return p_message; + return doc_domain->translate(p_message, p_context); } StringName TranslationServer::doc_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { - if (doc_translation.is_valid()) { - StringName r = doc_translation->get_plural_message(p_message, p_message_plural, p_n, p_context); - if (r) { - return r; - } - } - - if (p_n == 1) { - return p_message; - } - return p_message_plural; -} - -void TranslationServer::set_extractable_translation(const Ref &p_translation) { - extractable_translation = p_translation; -} - -StringName TranslationServer::extractable_translate(const StringName &p_message, const StringName &p_context) const { - if (extractable_translation.is_valid()) { - StringName r = extractable_translation->get_message(p_message, p_context); - if (r) { - return r; - } - } - return p_message; -} - -StringName TranslationServer::extractable_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { - if (extractable_translation.is_valid()) { - StringName r = extractable_translation->get_plural_message(p_message, p_message_plural, p_n, p_context); - if (r) { - return r; - } - } - - if (p_n == 1) { - return p_message; - } - return p_message_plural; + return doc_domain->translate_plural(p_message, p_message_plural, p_n, p_context); } bool TranslationServer::is_pseudolocalization_enabled() const { @@ -890,5 +808,8 @@ void TranslationServer::load_translations() { TranslationServer::TranslationServer() { singleton = this; main_domain.instantiate(); + editor_domain = get_or_add_domain("godot.editor"); + property_domain = get_or_add_domain("godot.properties"); + doc_domain = get_or_add_domain("godot.documentation"); init_locale_info(); } diff --git a/core/string/translation_server.h b/core/string/translation_server.h index 1271abec99d..272fa1f11cc 100644 --- a/core/string/translation_server.h +++ b/core/string/translation_server.h @@ -41,13 +41,11 @@ class TranslationServer : public Object { String fallback; Ref main_domain; + Ref editor_domain; + Ref property_domain; + Ref doc_domain; HashMap> custom_domains; - Ref tool_translation; - Ref property_translation; - Ref doc_translation; - Ref extractable_translation; - bool enabled = true; bool pseudolocalization_enabled = false; @@ -133,18 +131,11 @@ public: int compare_locales(const String &p_locale_a, const String &p_locale_b) const; String get_tool_locale(); - void set_tool_translation(const Ref &p_translation); - Ref get_tool_translation() const; StringName tool_translate(const StringName &p_message, const StringName &p_context = "") const; StringName tool_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; - void set_property_translation(const Ref &p_translation); StringName property_translate(const StringName &p_message, const StringName &p_context = "") const; - void set_doc_translation(const Ref &p_translation); StringName doc_translate(const StringName &p_message, const StringName &p_context = "") const; StringName doc_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; - void set_extractable_translation(const Ref &p_translation); - StringName extractable_translate(const StringName &p_message, const StringName &p_context = "") const; - StringName extractable_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; bool has_domain(const StringName &p_domain) const; Ref get_or_add_domain(const StringName &p_domain); diff --git a/doc/classes/TranslationDomain.xml b/doc/classes/TranslationDomain.xml index 8079685885d..da6f2704bf3 100644 --- a/doc/classes/TranslationDomain.xml +++ b/doc/classes/TranslationDomain.xml @@ -5,6 +5,7 @@ [TranslationDomain] is a self-contained collection of [Translation] resources. Translations can be added to or removed from it. + If you're working with the main translation domain, it is more convenient to use the wrap methods on [TranslationServer]. diff --git a/doc/classes/TranslationServer.xml b/doc/classes/TranslationServer.xml index 39afa2c0d2c..0a4965c36c1 100644 --- a/doc/classes/TranslationServer.xml +++ b/doc/classes/TranslationServer.xml @@ -5,7 +5,7 @@ The translation server is the API backend that manages all language translations. - Translations are stored in [TranslationDomain]s, which can be accessed by name. The most commonly used translation domain is the main translation domain, which always exists and can be accessed using an empty [StringName]. The translation server provides wrapper methods for accessing the master translation domain directly, without having to fetch the main translation domain first. + Translations are stored in [TranslationDomain]s, which can be accessed by name. The most commonly used translation domain is the main translation domain. It always exists and can be accessed using an empty [StringName]. The translation server provides wrapper methods for accessing the main translation domain directly, without having to fetch the translation domain first. Custom translation domains are mainly for advanced usages like editor plugins. Names starting with [code]godot.[/code] are reserved for engine internals. $DOCS_URL/tutorials/i18n/internationalizing_games.html diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 66fd2cf904e..770bf5726dc 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -6557,6 +6557,8 @@ EditorNode::EditorNode() { DEV_ASSERT(!singleton); singleton = this; + set_translation_domain("godot.editor"); + Resource::_get_local_scene_func = _resource_get_edited_scene; { diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 96a7700c34a..2bc14b3410e 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -1210,6 +1210,8 @@ fail: void EditorSettings::setup_language() { String lang = get("interface/editor/editor_language"); + TranslationServer::get_singleton()->set_locale(lang); + if (lang == "en") { return; // Default, nothing to do. } diff --git a/editor/editor_translation.cpp b/editor/editor_translation.cpp index 4654d41082c..6ccde3b6967 100644 --- a/editor/editor_translation.cpp +++ b/editor/editor_translation.cpp @@ -54,6 +54,8 @@ Vector get_editor_locales() { } void load_editor_translations(const String &p_locale) { + const Ref domain = TranslationServer::get_singleton()->get_or_add_domain("godot.editor"); + EditorTranslationList *etl = _editor_translations; while (etl->data) { if (etl->lang == p_locale) { @@ -70,7 +72,7 @@ void load_editor_translations(const String &p_locale) { if (tr.is_valid()) { tr->set_locale(etl->lang); - TranslationServer::get_singleton()->set_tool_translation(tr); + domain->add_translation(tr); break; } } @@ -80,6 +82,8 @@ void load_editor_translations(const String &p_locale) { } void load_property_translations(const String &p_locale) { + const Ref domain = TranslationServer::get_singleton()->get_or_add_domain("godot.properties"); + PropertyTranslationList *etl = _property_translations; while (etl->data) { if (etl->lang == p_locale) { @@ -96,7 +100,7 @@ void load_property_translations(const String &p_locale) { if (tr.is_valid()) { tr->set_locale(etl->lang); - TranslationServer::get_singleton()->set_property_translation(tr); + domain->add_translation(tr); break; } } @@ -106,6 +110,8 @@ void load_property_translations(const String &p_locale) { } void load_doc_translations(const String &p_locale) { + const Ref domain = TranslationServer::get_singleton()->get_or_add_domain("godot.documentation"); + DocTranslationList *dtl = _doc_translations; while (dtl->data) { if (dtl->lang == p_locale) { @@ -122,7 +128,7 @@ void load_doc_translations(const String &p_locale) { if (tr.is_valid()) { tr->set_locale(dtl->lang); - TranslationServer::get_singleton()->set_doc_translation(tr); + domain->add_translation(tr); break; } } @@ -132,6 +138,8 @@ void load_doc_translations(const String &p_locale) { } void load_extractable_translations(const String &p_locale) { + const Ref domain = TranslationServer::get_singleton()->get_or_add_domain("godot.editor"); + ExtractableTranslationList *etl = _extractable_translations; while (etl->data) { if (etl->lang == p_locale) { @@ -148,7 +156,7 @@ void load_extractable_translations(const String &p_locale) { if (tr.is_valid()) { tr->set_locale(etl->lang); - TranslationServer::get_singleton()->set_extractable_translation(tr); + domain->add_translation(tr); break; } } diff --git a/editor/gui/editor_file_dialog.cpp b/editor/gui/editor_file_dialog.cpp index b6aa3c22152..18f1f6da0c5 100644 --- a/editor/gui/editor_file_dialog.cpp +++ b/editor/gui/editor_file_dialog.cpp @@ -207,6 +207,10 @@ void EditorFileDialog::_update_theme_item_cache() { void EditorFileDialog::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_POSTINITIALIZE: { + set_translation_domain(SNAME("godot.editor")); + } break; + case NOTIFICATION_THEME_CHANGED: case Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED: case NOTIFICATION_TRANSLATION_CHANGED: { diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 279590563ac..8411c0edea1 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1081,6 +1081,8 @@ void ProjectManager::_titlebar_resized() { ProjectManager::ProjectManager() { singleton = this; + set_translation_domain("godot.editor"); + // Turn off some servers we aren't going to be using in the Project Manager. NavigationServer3D::get_singleton()->set_active(false); PhysicsServer3D::get_singleton()->set_active(false);