Przeglądaj źródła

Fix CSV translation not updating after reimport

Haoyu Qiu 1 miesiąc temu
rodzic
commit
296aba7dc5

+ 14 - 0
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<Ref<Translation>> TranslationDomain::get_potential_translations(const String &p_locale) const {
+	HashSet<Ref<Translation>> res;
+
+	for (const Ref<Translation> &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<Translation> TranslationDomain::get_translation_object(const String &p_locale) const {
 	Ref<Translation> res;
 	int best_score = 0;

+ 1 - 0
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<Ref<Translation>> get_potential_translations(const String &p_locale) const;
 
 public:
 	Ref<Translation> get_translation_object(const String &p_locale) const;

+ 15 - 0
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;

+ 7 - 0
editor/editor_file_system.cpp

@@ -2982,6 +2982,13 @@ Error EditorFileSystem::_reimport_file(const String &p_file, const HashMap<Strin
 		fs->files[cpos]->import_valid = fs->files[cpos]->type == "TextFile" ? true : ResourceLoader::is_import_valid(p_file);
 	}
 
+	for (const String &path : gen_files) {
+		Ref<Resource> 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 {

+ 50 - 17
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<Ref<Translation>> 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<Translation> &E : tracked_translations) {
+		E->disconnect_changed(callable_mp(this, &EditorNode::_queue_translation_notification));
+	}
+	tracked_translations.clear();
+
+	const Ref<TranslationDomain> main = TranslationServer::get_singleton()->get_main_domain();
+	if (main->is_enabled()) {
+		const HashSet<Ref<Translation>> translations = main->get_potential_translations(main->get_locale_override());
+		tracked_translations.reserve(translations.size());
+		for (const Ref<Translation> &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);

+ 7 - 0
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<Ref<Translation>> 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();

+ 16 - 0
tests/core/templates/test_hash_set.h

@@ -238,4 +238,20 @@ TEST_CASE("[HashSet] Copy") {
 	}
 }
 
+TEST_CASE("[HashSet] Equality") {
+	// Empty sets.
+	CHECK(HashSet<int>{} == HashSet<int>{});
+	CHECK(HashSet<int>{} != HashSet<int>{ 1, 2, 3 });
+	CHECK(HashSet<int>{ 1, 2, 3 } != HashSet<int>{});
+
+	// Different length.
+	CHECK(HashSet<int>{ 1, 2, 3 } != HashSet<int>{ 1, 2, 3, 4 });
+	CHECK(HashSet<int>{ 1, 2, 3, 4 } != HashSet<int>{ 4, 3, 2 });
+
+	// Same length.
+	CHECK(HashSet<int>{ 1, 2, 3 } == HashSet<int>{ 1, 2, 3 });
+	CHECK(HashSet<int>{ 1, 2, 3 } == HashSet<int>{ 3, 2, 1 });
+	CHECK(HashSet<int>{ 1, 2, 3 } != HashSet<int>{ 1, 2, 8 });
+}
+
 } // namespace TestHashSet