diff --git a/core/string/translation_domain.cpp b/core/string/translation_domain.cpp index e4927e606df..fd5e3d6c27c 100644 --- a/core/string/translation_domain.cpp +++ b/core/string/translation_domain.cpp @@ -202,7 +202,6 @@ StringName TranslationDomain::get_message_from_translations(const String &p_loca int best_score = 0; for (const Ref &E : translations) { - ERR_CONTINUE(E.is_null()); int score = TranslationServer::get_singleton()->compare_locales(p_locale, E->get_locale()); if (score > 0 && score >= best_score) { const StringName r = E->get_message(p_message, p_context); @@ -225,7 +224,6 @@ StringName TranslationDomain::get_message_from_translations(const String &p_loca int best_score = 0; for (const Ref &E : translations) { - ERR_CONTINUE(E.is_null()); int score = TranslationServer::get_singleton()->compare_locales(p_locale, E->get_locale()); if (score > 0 && score >= best_score) { const StringName r = E->get_plural_message(p_message, p_message_plural, p_n, p_context); @@ -246,7 +244,6 @@ StringName TranslationDomain::get_message_from_translations(const String &p_loca PackedStringArray TranslationDomain::get_loaded_locales() const { PackedStringArray locales; for (const Ref &E : translations) { - ERR_CONTINUE(E.is_null()); const String &locale = E->get_locale(); if (!locales.has(locale)) { locales.push_back(locale); @@ -255,13 +252,20 @@ PackedStringArray TranslationDomain::get_loaded_locales() const { return locales; } +bool TranslationDomain::has_translation_for_locale(const String &p_locale) const { + for (const Ref &E : translations) { + if (E->get_locale() == p_locale) { + return true; + } + } + return false; +} + // Translation objects that could potentially be used for the given locale. HashSet> TranslationDomain::get_potential_translations(const String &p_locale) const { HashSet> res; for (const Ref &E : translations) { - ERR_CONTINUE(E.is_null()); - if (TranslationServer::get_singleton()->compare_locales(p_locale, E->get_locale()) > 0) { res.insert(E); } @@ -274,8 +278,6 @@ Ref TranslationDomain::get_translation_object(const String &p_local int best_score = 0; for (const Ref &E : translations) { - ERR_CONTINUE(E.is_null()); - int score = TranslationServer::get_singleton()->compare_locales(p_locale, E->get_locale()); if (score > 0 && score >= best_score) { res = E; @@ -289,6 +291,7 @@ Ref TranslationDomain::get_translation_object(const String &p_local } void TranslationDomain::add_translation(const Ref &p_translation) { + ERR_FAIL_COND_MSG(p_translation.is_null(), "Invalid translation provided."); translations.insert(p_translation); } diff --git a/core/string/translation_domain.h b/core/string/translation_domain.h index c62313fdd38..01931f05c80 100644 --- a/core/string/translation_domain.h +++ b/core/string/translation_domain.h @@ -71,6 +71,7 @@ public: StringName get_message_from_translations(const String &p_locale, const StringName &p_message, const StringName &p_context) const; StringName get_message_from_translations(const String &p_locale, const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const; PackedStringArray get_loaded_locales() const; + bool has_translation_for_locale(const String &p_locale) const; HashSet> get_potential_translations(const String &p_locale) const; public: diff --git a/core/string/translation_server.cpp b/core/string/translation_server.cpp index 40893a2d8d5..195788c430e 100644 --- a/core/string/translation_server.cpp +++ b/core/string/translation_server.cpp @@ -494,8 +494,7 @@ void TranslationServer::setup() { String TranslationServer::get_tool_locale() { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint() || Engine::get_singleton()->is_project_manager_hint()) { - const PackedStringArray &locales = editor_domain->get_loaded_locales(); - if (locales.has(locale)) { + if (editor_domain->has_translation_for_locale(locale)) { return locale; } return "en"; @@ -512,26 +511,6 @@ String TranslationServer::get_tool_locale() { } } -StringName TranslationServer::tool_translate(const StringName &p_message, const StringName &p_context) const { - 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 { - 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 { - return property_domain->translate(p_message, p_context); -} - -StringName TranslationServer::doc_translate(const StringName &p_message, const StringName &p_context) const { - 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 { - return doc_domain->translate_plural(p_message, p_message_plural, p_n, p_context); -} - bool TranslationServer::is_pseudolocalization_enabled() const { return main_domain->is_pseudolocalization_enabled(); } @@ -648,9 +627,14 @@ void TranslationServer::load_translations() { TranslationServer::TranslationServer() { singleton = this; + main_domain.instantiate(); + +#ifdef TOOLS_ENABLED editor_domain = get_or_add_domain("godot.editor"); property_domain = get_or_add_domain("godot.properties"); doc_domain = get_or_add_domain("godot.documentation"); +#endif // TOOLS_ENABLED + init_locale_info(); } diff --git a/core/string/translation_server.h b/core/string/translation_server.h index f904f074b89..7e68d8854e6 100644 --- a/core/string/translation_server.h +++ b/core/string/translation_server.h @@ -40,9 +40,11 @@ class TranslationServer : public Object { String fallback; Ref main_domain; +#ifdef TOOLS_ENABLED Ref editor_domain; Ref property_domain; Ref doc_domain; +#endif // TOOLS_ENABLED HashMap> custom_domains; mutable HashMap locale_compare_cache; @@ -95,8 +97,13 @@ class TranslationServer : public Object { public: _FORCE_INLINE_ static TranslationServer *get_singleton() { return singleton; } + // Built-in domain accessors. For engine code only, user code should use `get_or_add_domain()` instead. Ref get_main_domain() const { return main_domain; } +#ifdef TOOLS_ENABLED Ref get_editor_domain() const { return editor_domain; } + Ref get_property_domain() const { return property_domain; } + Ref get_doc_domain() const { return doc_domain; } +#endif // TOOLS_ENABLED void set_locale(const String &p_locale); String get_locale() const; @@ -135,11 +142,6 @@ public: int compare_locales(const String &p_locale_a, const String &p_locale_b) const; String get_tool_locale(); - 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; - StringName property_translate(const StringName &p_message, const StringName &p_context = "") const; - 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; bool has_domain(const StringName &p_domain) const; Ref get_or_add_domain(const StringName &p_domain); diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index 646e0e6ba06..9e6701bcf4d 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -5854,7 +5854,7 @@ Vector String::to_multibyte_char_buffer(const String &p_encoding) const */ String TTR(const String &p_text, const String &p_context) { if (TranslationServer::get_singleton()) { - return TranslationServer::get_singleton()->tool_translate(p_text, p_context); + return TranslationServer::get_singleton()->get_editor_domain()->translate(p_text, p_context); } return p_text; @@ -5874,7 +5874,7 @@ String TTR(const String &p_text, const String &p_context) { */ String TTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context) { if (TranslationServer::get_singleton()) { - return TranslationServer::get_singleton()->tool_translate_plural(p_text, p_text_plural, p_n, p_context); + return TranslationServer::get_singleton()->get_editor_domain()->translate_plural(p_text, p_text_plural, p_n, p_context); } // Return message based on English plural rule if translation is not possible. @@ -5895,7 +5895,7 @@ String DTR(const String &p_text, const String &p_context) { const String text = p_text.dedent().strip_edges(); if (TranslationServer::get_singleton()) { - return String(TranslationServer::get_singleton()->doc_translate(text, p_context)).replace("$DOCS_URL", GODOT_VERSION_DOCS_URL); + return String(TranslationServer::get_singleton()->get_doc_domain()->translate(text, p_context)).replace("$DOCS_URL", GODOT_VERSION_DOCS_URL); } return text.replace("$DOCS_URL", GODOT_VERSION_DOCS_URL); @@ -5912,7 +5912,7 @@ String DTRN(const String &p_text, const String &p_text_plural, int p_n, const St const String text_plural = p_text_plural.dedent().strip_edges(); if (TranslationServer::get_singleton()) { - return String(TranslationServer::get_singleton()->doc_translate_plural(text, text_plural, p_n, p_context)).replace("$DOCS_URL", GODOT_VERSION_DOCS_URL); + return String(TranslationServer::get_singleton()->get_doc_domain()->translate_plural(text, text_plural, p_n, p_context)).replace("$DOCS_URL", GODOT_VERSION_DOCS_URL); } // Return message based on English plural rule if translation is not possible. @@ -5936,11 +5936,13 @@ String DTRN(const String &p_text, const String &p_text_plural, int p_n, const St */ String RTR(const String &p_text, const String &p_context) { if (TranslationServer::get_singleton()) { - String rtr = TranslationServer::get_singleton()->tool_translate(p_text, p_context); - if (rtr.is_empty() || rtr == p_text) { - return TranslationServer::get_singleton()->translate(p_text, p_context); +#ifdef TOOLS_ENABLED + String rtr = TranslationServer::get_singleton()->get_editor_domain()->translate(p_text, p_context); + if (!rtr.is_empty() && rtr != p_text) { + return rtr; } - return rtr; +#endif // TOOLS_ENABLED + return TranslationServer::get_singleton()->translate(p_text, p_context); } return p_text; @@ -5959,11 +5961,13 @@ String RTR(const String &p_text, const String &p_context) { */ String RTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context) { if (TranslationServer::get_singleton()) { - String rtr = TranslationServer::get_singleton()->tool_translate_plural(p_text, p_text_plural, p_n, p_context); - if (rtr.is_empty() || rtr == p_text || rtr == p_text_plural) { - return TranslationServer::get_singleton()->translate_plural(p_text, p_text_plural, p_n, p_context); +#ifdef TOOLS_ENABLED + String rtr = TranslationServer::get_singleton()->get_editor_domain()->translate_plural(p_text, p_text_plural, p_n, p_context); + if (!rtr.is_empty() && rtr != p_text && rtr != p_text_plural) { + return rtr; } - return rtr; +#endif // TOOLS_ENABLED + return TranslationServer::get_singleton()->translate_plural(p_text, p_text_plural, p_n, p_context); } // Return message based on English plural rule if translation is not possible. diff --git a/editor/doc/doc_tools.cpp b/editor/doc/doc_tools.cpp index d73b6e27427..0166efec039 100644 --- a/editor/doc/doc_tools.cpp +++ b/editor/doc/doc_tools.cpp @@ -71,7 +71,7 @@ static String _get_indent(const String &p_text) { static String _translate_doc_string(const String &p_text) { const String indent = _get_indent(p_text); const String message = p_text.dedent().strip_edges(); - const String translated = TranslationServer::get_singleton()->doc_translate(message, ""); + const String translated = TranslationServer::get_singleton()->get_doc_domain()->translate(message, StringName()); // No need to restore stripped edges because they'll be stripped again later. return translated.indent(indent); } diff --git a/editor/editor_builders.py b/editor/editor_builders.py index 1eaab101829..c7d04d0602c 100644 --- a/editor/editor_builders.py +++ b/editor/editor_builders.py @@ -124,7 +124,7 @@ inline constexpr const unsigned char _{category}_translation_{name}_compressed[] file.write(f"""\ #include "{target_h}" -const {category.capitalize()}TranslationList _{category}_translations[] = {{ +const EditorTranslationList _{category}_translations[] = {{ """) for x in xl_names: @@ -137,12 +137,18 @@ const {category.capitalize()}TranslationList _{category}_translations[] = {{ with methods.generated_wrapper(target_h) as file: file.write(f"""\ -struct {category.capitalize()}TranslationList {{ + +#ifndef EDITOR_TRANSLATION_LIST +#define EDITOR_TRANSLATION_LIST + +struct EditorTranslationList {{ const char* lang; int comp_size; int uncomp_size; const unsigned char* data; }}; -extern const {category.capitalize()}TranslationList _{category}_translations[]; +#endif // EDITOR_TRANSLATION_LIST + +extern const EditorTranslationList _{category}_translations[]; """) diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index f7b7dc340d3..edb378bec82 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -581,7 +581,7 @@ void EditorNode::_update_translations() { if (main->is_enabled()) { // Check for the exact locale. // `get_potential_translations("zh_CN")` could return translations for "zh". - if (main->get_loaded_locales().has(main->get_locale_override())) { + if (main->has_translation_for_locale(main->get_locale_override())) { // The set of translation resources for the current locale changed. const HashSet> translations = main->get_potential_translations(main->get_locale_override()); if (translations != tracked_translations) { diff --git a/editor/inspector/editor_property_name_processor.cpp b/editor/inspector/editor_property_name_processor.cpp index 25ab6b5edee..4250bd50daf 100644 --- a/editor/inspector/editor_property_name_processor.cpp +++ b/editor/inspector/editor_property_name_processor.cpp @@ -120,7 +120,7 @@ String EditorPropertyNameProcessor::process_name(const String &p_name, Style p_s case STYLE_LOCALIZED: { const String capitalized = _capitalize_name(p_name); if (TranslationServer::get_singleton()) { - return TranslationServer::get_singleton()->property_translate(capitalized, _get_context(p_name, p_property, p_class)); + return TranslationServer::get_singleton()->get_property_domain()->translate(capitalized, _get_context(p_name, p_property, p_class)); } return capitalized; } break; @@ -130,7 +130,7 @@ String EditorPropertyNameProcessor::process_name(const String &p_name, Style p_s String EditorPropertyNameProcessor::translate_group_name(const String &p_name) const { if (TranslationServer::get_singleton()) { - return TranslationServer::get_singleton()->property_translate(p_name); + return TranslationServer::get_singleton()->get_property_domain()->translate(p_name, StringName()); } return p_name; } diff --git a/editor/settings/editor_settings.cpp b/editor/settings/editor_settings.cpp index 22db86c60eb..d11758856e4 100644 --- a/editor/settings/editor_settings.cpp +++ b/editor/settings/editor_settings.cpp @@ -1337,16 +1337,10 @@ void EditorSettings::setup_language(bool p_initial_setup) { TranslationServer::get_singleton()->set_locale(lang); return; // Default, nothing to do. } - // Load editor translation for configured/detected locale. + load_editor_translations(lang); - load_property_translations(lang); - - // Load class reference translation. load_doc_translations(lang); - // Load extractable translation for projects. - load_extractable_translations(lang); - TranslationServer::get_singleton()->set_locale(lang); } diff --git a/editor/translations/editor_translation.cpp b/editor/translations/editor_translation.cpp index 8f0ded8c945..e9b85cf79cd 100644 --- a/editor/translations/editor_translation.cpp +++ b/editor/translations/editor_translation.cpp @@ -42,26 +42,20 @@ Vector get_editor_locales() { Vector locales; - const EditorTranslationList *etl = _editor_translations; - while (etl->data) { + for (const EditorTranslationList *etl = _editor_translations; etl->data; etl++) { const String &locale = etl->lang; locales.push_back(locale); - - etl++; } return locales; } -void load_editor_translations(const String &p_locale) { - const Ref domain = TranslationServer::get_singleton()->get_or_add_domain("godot.editor"); - - const EditorTranslationList *etl = _editor_translations; - while (etl->data) { +static void _load(const Ref p_domain, const String &p_locale, const EditorTranslationList *p_etl) { + for (const EditorTranslationList *etl = p_etl; etl->data; etl++) { if (etl->lang == p_locale) { - Vector data; - data.resize(etl->uncomp_size); - const int64_t ret = Compression::decompress(data.ptrw(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE); + LocalVector data; + data.resize_uninitialized(etl->uncomp_size); + const int64_t ret = Compression::decompress(data.ptr(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE); ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt."); Ref fa; @@ -69,115 +63,45 @@ void load_editor_translations(const String &p_locale) { fa->open_custom(data.ptr(), data.size()); Ref tr = TranslationLoaderPO::load_translation(fa); - if (tr.is_valid()) { tr->set_locale(etl->lang); - domain->add_translation(tr); + p_domain->add_translation(tr); break; } } - - etl++; } } -void load_property_translations(const String &p_locale) { - const Ref domain = TranslationServer::get_singleton()->get_or_add_domain("godot.properties"); +void load_editor_translations(const String &p_locale) { + Ref domain; - const PropertyTranslationList *etl = _property_translations; - while (etl->data) { - if (etl->lang == p_locale) { - Vector data; - data.resize(etl->uncomp_size); - const int64_t ret = Compression::decompress(data.ptrw(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE); - ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt."); + domain = TranslationServer::get_singleton()->get_editor_domain(); + domain->clear(); + _load(domain, p_locale, _editor_translations); + _load(domain, p_locale, _extractable_translations); - Ref fa; - fa.instantiate(); - fa->open_custom(data.ptr(), data.size()); - - Ref tr = TranslationLoaderPO::load_translation(fa); - - if (tr.is_valid()) { - tr->set_locale(etl->lang); - domain->add_translation(tr); - break; - } - } - - etl++; - } + domain = TranslationServer::get_singleton()->get_property_domain(); + domain->clear(); + _load(domain, p_locale, _property_translations); } void load_doc_translations(const String &p_locale) { - const Ref domain = TranslationServer::get_singleton()->get_or_add_domain("godot.documentation"); - - const DocTranslationList *dtl = _doc_translations; - while (dtl->data) { - if (dtl->lang == p_locale) { - Vector data; - data.resize(dtl->uncomp_size); - const int64_t ret = Compression::decompress(data.ptrw(), dtl->uncomp_size, dtl->data, dtl->comp_size, Compression::MODE_DEFLATE); - ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt."); - - Ref fa; - fa.instantiate(); - fa->open_custom(data.ptr(), data.size()); - - Ref tr = TranslationLoaderPO::load_translation(fa); - - if (tr.is_valid()) { - tr->set_locale(dtl->lang); - domain->add_translation(tr); - break; - } - } - - dtl++; - } -} - -void load_extractable_translations(const String &p_locale) { - const Ref domain = TranslationServer::get_singleton()->get_or_add_domain("godot.editor"); - - const ExtractableTranslationList *etl = _extractable_translations; - while (etl->data) { - if (etl->lang == p_locale) { - Vector data; - data.resize(etl->uncomp_size); - const int64_t ret = Compression::decompress(data.ptrw(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE); - ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt."); - - Ref fa; - fa.instantiate(); - fa->open_custom(data.ptr(), data.size()); - - Ref tr = TranslationLoaderPO::load_translation(fa); - - if (tr.is_valid()) { - tr->set_locale(etl->lang); - domain->add_translation(tr); - break; - } - } - - etl++; - } + const Ref domain = TranslationServer::get_singleton()->get_doc_domain(); + domain->clear(); + _load(domain, p_locale, _doc_translations); } Vector> get_extractable_message_list() { - const ExtractableTranslationList *etl = _extractable_translations; Vector> list; - while (etl->data) { + for (const EditorTranslationList *etl = _extractable_translations; etl->data; etl++) { if (strcmp(etl->lang, "source")) { - etl++; continue; } - Vector data; - data.resize(etl->uncomp_size); - const int64_t ret = Compression::decompress(data.ptrw(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE); + LocalVector data; + data.resize_uninitialized(etl->uncomp_size); + const int64_t ret = Compression::decompress(data.ptr(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE); ERR_FAIL_COND_V_MSG(ret == -1, list, "Compressed file is corrupt."); Ref fa; @@ -322,8 +246,6 @@ Vector> get_extractable_message_list() { line++; } } - - etl++; } return list; diff --git a/editor/translations/editor_translation.h b/editor/translations/editor_translation.h index f20e8ff6ed3..862c32e16a0 100644 --- a/editor/translations/editor_translation.h +++ b/editor/translations/editor_translation.h @@ -35,7 +35,5 @@ Vector get_editor_locales(); void load_editor_translations(const String &p_locale); -void load_property_translations(const String &p_locale); void load_doc_translations(const String &p_locale); -void load_extractable_translations(const String &p_locale); Vector> get_extractable_message_list();