From 296aba7dc5a3b92ad9c1dd676230818a2b6b9b98 Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Wed, 11 Jun 2025 20:31:59 +0800 Subject: [PATCH] Fix CSV translation not updating after reimport --- core/string/translation_domain.cpp | 14 ++++++ core/string/translation_domain.h | 1 + core/templates/hash_set.h | 15 +++++++ editor/editor_file_system.cpp | 7 +++ editor/editor_node.cpp | 67 +++++++++++++++++++++------- editor/editor_node.h | 7 +++ tests/core/templates/test_hash_set.h | 16 +++++++ 7 files changed, 110 insertions(+), 17 deletions(-) diff --git a/core/string/translation_domain.cpp b/core/string/translation_domain.cpp index 507f1b995f..095eb4bdf7 100644 --- a/core/string/translation_domain.cpp +++ b/core/string/translation_domain.cpp @@ -255,6 +255,20 @@ PackedStringArray TranslationDomain::get_loaded_locales() const { return locales; } +// 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); + } + } + return res; +} + Ref TranslationDomain::get_translation_object(const String &p_locale) const { Ref res; int best_score = 0; diff --git a/core/string/translation_domain.h b/core/string/translation_domain.h index 69477128ad..c62313fdd3 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; + HashSet> get_potential_translations(const String &p_locale) const; public: Ref get_translation_object(const String &p_locale) const; diff --git a/core/templates/hash_set.h b/core/templates/hash_set.h index b33522669e..df59f617e3 100644 --- a/core/templates/hash_set.h +++ b/core/templates/hash_set.h @@ -437,6 +437,21 @@ public: _init_from(p_other); } + bool operator==(const HashSet &p_other) const { + if (num_elements != p_other.num_elements) { + return false; + } + for (uint32_t i = 0; i < num_elements; i++) { + if (!p_other.has(keys[i])) { + return false; + } + } + return true; + } + bool operator!=(const HashSet &p_other) const { + return !(*this == p_other); + } + HashSet(uint32_t p_initial_capacity) { // Capacity can't be 0. capacity_index = 0; diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 5062637177..ba0c58e1ae 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -2982,6 +2982,13 @@ Error EditorFileSystem::_reimport_file(const String &p_file, const HashMapfiles[cpos]->import_valid = fs->files[cpos]->type == "TextFile" ? true : ResourceLoader::is_import_valid(p_file); } + for (const String &path : gen_files) { + Ref cached = ResourceCache::get_ref(path); + if (cached.is_valid()) { + cached->reload_from_file(); + } + } + if (ResourceUID::get_singleton()->has_id(uid)) { ResourceUID::get_singleton()->set_id(uid, p_file); } else { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index e7b74b79e1..c2874b9f7f 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -566,17 +566,57 @@ void EditorNode::_update_translations() { main->clear(); TranslationServer::get_singleton()->load_translations(); - if (main->is_enabled() && !main->get_loaded_locales().has(main->get_locale_override())) { - // Translations for the current preview locale is removed. - main->set_enabled(false); - main->set_locale_override(String()); - scene_root->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); - emit_signal(SNAME("preview_locale_changed")); - } else { - scene_root->propagate_notification(NOTIFICATION_TRANSLATION_CHANGED); + 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())) { + // 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) { + _translation_resources_changed(); + } + } else { + // Translations for the current preview locale is removed. + main->set_enabled(false); + main->set_locale_override(String()); + _translation_resources_changed(); + } } } +void EditorNode::_translation_resources_changed() { + for (const Ref &E : tracked_translations) { + E->disconnect_changed(callable_mp(this, &EditorNode::_queue_translation_notification)); + } + tracked_translations.clear(); + + const Ref main = TranslationServer::get_singleton()->get_main_domain(); + if (main->is_enabled()) { + const HashSet> translations = main->get_potential_translations(main->get_locale_override()); + tracked_translations.reserve(translations.size()); + for (const Ref &translation : translations) { + translation->connect_changed(callable_mp(this, &EditorNode::_queue_translation_notification)); + tracked_translations.insert(translation); + } + } + + _queue_translation_notification(); + emit_signal(SNAME("preview_locale_changed")); +} + +void EditorNode::_queue_translation_notification() { + if (pending_translation_notification) { + return; + } + pending_translation_notification = true; + callable_mp(this, &EditorNode::_propagate_translation_notification).call_deferred(); +} + +void EditorNode::_propagate_translation_notification() { + pending_translation_notification = false; + scene_root->propagate_notification(NOTIFICATION_TRANSLATION_CHANGED); +} + void EditorNode::_update_theme(bool p_skip_creation) { if (!p_skip_creation) { theme = EditorThemeManager::generate_theme(theme); @@ -4056,14 +4096,7 @@ void EditorNode::set_preview_locale(const String &p_locale) { main_domain->set_enabled(!p_locale.is_empty()); main_domain->set_locale_override(p_locale); - if (prev_locale.is_empty() == p_locale.is_empty()) { - // Switching between different locales. - scene_root->propagate_notification(NOTIFICATION_TRANSLATION_CHANGED); - } else { - // Switching between on/off. - scene_root->set_auto_translate_mode(p_locale.is_empty() ? AUTO_TRANSLATE_MODE_DISABLED : AUTO_TRANSLATE_MODE_ALWAYS); - } - emit_signal(SNAME("preview_locale_changed")); + _translation_resources_changed(); } Dictionary EditorNode::_get_main_scene_state() { @@ -7850,7 +7883,7 @@ EditorNode::EditorNode() { editor_main_screen->set_v_size_flags(Control::SIZE_EXPAND_FILL); scene_root = memnew(SubViewport); - scene_root->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); + scene_root->set_auto_translate_mode(AUTO_TRANSLATE_MODE_ALWAYS); scene_root->set_translation_domain(StringName()); scene_root->set_embedding_subwindows(true); scene_root->set_disable_3d(true); diff --git a/editor/editor_node.h b/editor/editor_node.h index edb1d2f815..05bd4bc725 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -54,6 +54,7 @@ class PanelContainer; class RichTextLabel; class SubViewport; class TextureProgressBar; +class Translation; class Tree; class VBoxContainer; class VSplitContainer; @@ -455,6 +456,9 @@ private: bool waiting_for_first_scan = true; bool load_editor_layout_done = false; + HashSet> tracked_translations; + bool pending_translation_notification = false; + int current_menu_option = 0; SubViewport *scene_root = nullptr; // Root of the scene being edited. @@ -619,6 +623,9 @@ private: void _update_from_settings(); void _gdextensions_reloaded(); void _update_translations(); + void _translation_resources_changed(); + void _queue_translation_notification(); + void _propagate_translation_notification(); void _renderer_selected(int); void _update_renderer_color(); diff --git a/tests/core/templates/test_hash_set.h b/tests/core/templates/test_hash_set.h index c949e89bce..d4b5e4987a 100644 --- a/tests/core/templates/test_hash_set.h +++ b/tests/core/templates/test_hash_set.h @@ -238,4 +238,20 @@ TEST_CASE("[HashSet] Copy") { } } +TEST_CASE("[HashSet] Equality") { + // Empty sets. + CHECK(HashSet{} == HashSet{}); + CHECK(HashSet{} != HashSet{ 1, 2, 3 }); + CHECK(HashSet{ 1, 2, 3 } != HashSet{}); + + // Different length. + CHECK(HashSet{ 1, 2, 3 } != HashSet{ 1, 2, 3, 4 }); + CHECK(HashSet{ 1, 2, 3, 4 } != HashSet{ 4, 3, 2 }); + + // Same length. + CHECK(HashSet{ 1, 2, 3 } == HashSet{ 1, 2, 3 }); + CHECK(HashSet{ 1, 2, 3 } == HashSet{ 3, 2, 1 }); + CHECK(HashSet{ 1, 2, 3 } != HashSet{ 1, 2, 8 }); +} + } // namespace TestHashSet