From 479b7afa8e83607b05a39da71b370b3aee78688e Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Thu, 5 Oct 2023 21:12:10 +0800 Subject: [PATCH] Add context support for editor property name i18n --- core/string/translation.cpp | 4 +- core/string/translation.h | 2 +- editor/editor_feature_profile.cpp | 4 +- editor/editor_inspector.cpp | 10 ++--- editor/editor_property_name_processor.cpp | 43 +++++++++++++++++++++- editor/editor_property_name_processor.h | 8 +++- editor/editor_sectioned_inspector.cpp | 6 +-- editor/editor_settings_dialog.cpp | 4 +- editor/plugins/tiles/tile_data_editors.cpp | 2 +- editor/scene_tree_dock.cpp | 2 +- scene/theme/default_theme.cpp | 2 - 11 files changed, 65 insertions(+), 22 deletions(-) diff --git a/core/string/translation.cpp b/core/string/translation.cpp index 0a0052d6cbe8..613edd11cda0 100644 --- a/core/string/translation.cpp +++ b/core/string/translation.cpp @@ -776,9 +776,9 @@ void TranslationServer::set_property_translation(const Ref &p_trans property_translation = p_translation; } -StringName TranslationServer::property_translate(const StringName &p_message) const { +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); + StringName r = property_translation->get_message(p_message, p_context); if (r) { return r; } diff --git a/core/string/translation.h b/core/string/translation.h index 470ba8823291..78d6721347f6 100644 --- a/core/string/translation.h +++ b/core/string/translation.h @@ -183,7 +183,7 @@ class TranslationServer : public Object { 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 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; diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index 5236f9e254d0..541bcd5e0280 100644 --- a/editor/editor_feature_profile.cpp +++ b/editor/editor_feature_profile.cpp @@ -619,8 +619,8 @@ void EditorFeatureProfileManager::_class_list_item_selected() { if (!(E.usage & PROPERTY_USAGE_EDITOR)) { continue; } - const String text = EditorPropertyNameProcessor::get_singleton()->process_name(name, text_style); - const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(name, tooltip_style); + const String text = EditorPropertyNameProcessor::get_singleton()->process_name(name, text_style, name, class_name); + const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(name, tooltip_style, name, class_name); TreeItem *property = property_list->create_item(properties); property->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index c5ce815d6b32..7919d61f26ab 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -57,7 +57,7 @@ bool EditorInspector::_property_path_matches(const String &p_property_path, cons const Vector prop_sections = p_property_path.split("/"); for (int i = 0; i < prop_sections.size(); i++) { - if (p_filter.is_subsequence_ofn(EditorPropertyNameProcessor::get_singleton()->process_name(prop_sections[i], p_style))) { + if (p_filter.is_subsequence_ofn(EditorPropertyNameProcessor::get_singleton()->process_name(prop_sections[i], p_style, p_property_path))) { return true; } } @@ -3012,7 +3012,7 @@ void EditorInspector::update_tree() { if ((p.usage & PROPERTY_USAGE_SCRIPT_VARIABLE) && name_style == EditorPropertyNameProcessor::STYLE_LOCALIZED) { name_style = EditorPropertyNameProcessor::STYLE_CAPITALIZED; } - const String property_label_string = EditorPropertyNameProcessor::get_singleton()->process_name(name_override, name_style) + feature_tag; + const String property_label_string = EditorPropertyNameProcessor::get_singleton()->process_name(name_override, name_style, p.name, doc_name) + feature_tag; // Remove the property from the path. int idx = path.rfind("/"); @@ -3081,8 +3081,8 @@ void EditorInspector::update_tree() { tooltip = EditorPropertyNameProcessor::get_singleton()->translate_group_name(component); } } else { - label = EditorPropertyNameProcessor::get_singleton()->process_name(component, section_name_style); - tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(component, EditorPropertyNameProcessor::get_tooltip_style(section_name_style)); + label = EditorPropertyNameProcessor::get_singleton()->process_name(component, section_name_style, p.name, doc_name); + tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(component, EditorPropertyNameProcessor::get_tooltip_style(section_name_style), p.name, doc_name); } Color c = sscolor; @@ -3145,7 +3145,7 @@ void EditorInspector::update_tree() { editor_inspector_array = memnew(EditorInspectorArray(all_read_only)); String array_label = path.contains("/") ? path.substr(path.rfind("/") + 1) : path; - array_label = EditorPropertyNameProcessor::get_singleton()->process_name(property_label_string, property_name_style); + array_label = EditorPropertyNameProcessor::get_singleton()->process_name(property_label_string, property_name_style, p.name, doc_name); int page = per_array_page.has(array_element_prefix) ? per_array_page[array_element_prefix] : 0; editor_inspector_array->setup_with_move_element_function(object, array_label, array_element_prefix, page, c, use_folding); editor_inspector_array->connect("page_change_request", callable_mp(this, &EditorInspector::_page_change_request).bind(array_element_prefix)); diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp index a892ea0f85f9..1318b84d605e 100644 --- a/editor/editor_property_name_processor.cpp +++ b/editor/editor_property_name_processor.cpp @@ -91,7 +91,27 @@ String EditorPropertyNameProcessor::_capitalize_name(const String &p_name) const return capitalized; } -String EditorPropertyNameProcessor::process_name(const String &p_name, Style p_style) const { +StringName EditorPropertyNameProcessor::_get_context(const String &p_name, const String &p_property, const StringName &p_class) const { + if (p_property.is_empty() && p_class == StringName()) { + return StringName(); + } + const HashMap *context_map = translation_contexts.getptr(p_name); + if (context_map == nullptr) { + return StringName(); + } + // It's expected that full property path is enough to distinguish between usages. + // In case a class name is needed, all usages should be prefixed with the class name. + const StringName *context = context_map->getptr(p_property); + if (context == nullptr && p_class != StringName()) { + context = context_map->getptr(String(p_class) + "::" + p_property); + } + if (context == nullptr) { + return StringName(); + } + return *context; +} + +String EditorPropertyNameProcessor::process_name(const String &p_name, Style p_style, const String &p_property, const StringName &p_class) const { switch (p_style) { case STYLE_RAW: { return p_name; @@ -104,7 +124,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); + return TranslationServer::get_singleton()->property_translate(capitalized, _get_context(p_name, p_property, p_class)); } return capitalized; } break; @@ -320,6 +340,25 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() { "then", "to", }); + + // Translation context associated with a name. + // The second key is either: + // - `full/property/path` + // - `Class::full/property/path` + // In case a class name is needed to distinguish between usages, all usages should use the second format. + // + // The following initialization is parsed in `editor/translations/scripts/common.py` with a regex. + // The map name and value definition format should be kept synced with the regex. + translation_contexts["force"]["constant_force"] = "Physics"; + translation_contexts["force"]["force/8_bit"] = "Enforce"; + translation_contexts["force"]["force/mono"] = "Enforce"; + translation_contexts["force"]["force/max_rate"] = "Enforce"; + translation_contexts["force"]["force/max_rate_hz"] = "Enforce"; + translation_contexts["normal"]["theme_override_styles/normal"] = "Ordinary"; + translation_contexts["normal"]["TextureButton::texture_normal"] = "Ordinary"; + translation_contexts["normal"]["Decal::texture_normal"] = "Geometry"; + translation_contexts["normal"]["detail_normal"] = "Geometry"; + translation_contexts["normal"]["normal"] = "Geometry"; } EditorPropertyNameProcessor::~EditorPropertyNameProcessor() { diff --git a/editor/editor_property_name_processor.h b/editor/editor_property_name_processor.h index 8e3cecb45b82..2c68423c84da 100644 --- a/editor/editor_property_name_processor.h +++ b/editor/editor_property_name_processor.h @@ -42,9 +42,14 @@ class EditorPropertyNameProcessor : public Node { HashMap capitalize_string_remaps; LocalVector stop_words; // Exceptions that shouldn't be capitalized. + HashMap> translation_contexts; + // Capitalizes property path segments. String _capitalize_name(const String &p_name) const; + // Returns the translation context for the given name. + StringName _get_context(const String &p_name, const String &p_property, const StringName &p_class) const; + public: // Matches `interface/inspector/capitalize_properties` editor setting. enum Style { @@ -62,7 +67,8 @@ class EditorPropertyNameProcessor : public Node { static bool is_localization_available(); // Turns property path segment into the given style. - String process_name(const String &p_name, Style p_style) const; + // `p_class` and `p_property` are only used for `STYLE_LOCALIZED`, associating the name with a translation context. + String process_name(const String &p_name, Style p_style, const String &p_property = "", const StringName &p_class = "") const; // Translate plain text group names. String translate_group_name(const String &p_name) const; diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp index 8e8908faaf2d..f13af8e4ca6d 100644 --- a/editor/editor_sectioned_inspector.cpp +++ b/editor/editor_sectioned_inspector.cpp @@ -42,7 +42,7 @@ static bool _property_path_matches(const String &p_property_path, const String & const Vector sections = p_property_path.split("/"); for (int i = 0; i < sections.size(); i++) { - if (p_filter.is_subsequence_ofn(EditorPropertyNameProcessor::get_singleton()->process_name(sections[i], p_style))) { + if (p_filter.is_subsequence_ofn(EditorPropertyNameProcessor::get_singleton()->process_name(sections[i], p_style, p_property_path))) { return true; } } @@ -278,8 +278,8 @@ void SectionedInspector::update_category_list() { TreeItem *ms = sections->create_item(parent); section_map[metasection] = ms; - const String text = EditorPropertyNameProcessor::get_singleton()->process_name(sectionarr[i], name_style); - const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(sectionarr[i], tooltip_style); + const String text = EditorPropertyNameProcessor::get_singleton()->process_name(sectionarr[i], name_style, pi.name); + const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(sectionarr[i], tooltip_style, pi.name); ms->set_text(0, text); ms->set_tooltip_text(0, tooltip); diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index d6946afbc147..7faab03a357a 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -452,8 +452,8 @@ void EditorSettingsDialog::_update_shortcuts() { TreeItem *section = shortcuts->create_item(root); - const String item_name = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, name_style); - const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, tooltip_style); + const String item_name = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, name_style, E); + const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, tooltip_style, E); section->set_text(0, item_name); section->set_tooltip_text(0, tooltip); diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index 597fd7393f7b..f047e4ff16b8 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -1280,7 +1280,7 @@ void TileDataDefaultEditor::setup_property_editor(Variant::Type p_type, const St property_editor = EditorInspectorDefaultPlugin::get_editor_for_property(dummy_object, p_type, p_property, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT); property_editor->set_object_and_property(dummy_object, p_property); if (p_label.is_empty()) { - property_editor->set_label(EditorPropertyNameProcessor::get_singleton()->process_name(p_property, EditorPropertyNameProcessor::get_default_inspector_style())); + property_editor->set_label(EditorPropertyNameProcessor::get_singleton()->process_name(p_property, EditorPropertyNameProcessor::get_default_inspector_style(), p_property)); } else { property_editor->set_label(p_label); } diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index ded6fc2a3571..26ddec660382 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -3156,7 +3156,7 @@ void SceneTreeDock::_files_dropped(const Vector &p_files, NodePath p_to, const EditorPropertyNameProcessor::Style style = InspectorDock::get_singleton()->get_property_name_style(); menu_properties->clear(); for (const String &p : valid_properties) { - menu_properties->add_item(EditorPropertyNameProcessor::get_singleton()->process_name(p, style)); + menu_properties->add_item(EditorPropertyNameProcessor::get_singleton()->process_name(p, style, p, node->get_class_name())); menu_properties->set_item_metadata(-1, p); } diff --git a/scene/theme/default_theme.cpp b/scene/theme/default_theme.cpp index e4c469b75292..c45f52ec9e87 100644 --- a/scene/theme/default_theme.cpp +++ b/scene/theme/default_theme.cpp @@ -936,8 +936,6 @@ void fill_default_theme(Ref &theme, const Ref &default_font, const theme->set_stylebox("separator", "VSeparator", separator_vertical); theme->set_icon("close", "Icons", icons["close"]); - theme->set_font("normal", "Fonts", Ref()); - theme->set_font("large", "Fonts", Ref()); theme->set_constant("separation", "HSeparator", Math::round(4 * scale)); theme->set_constant("separation", "VSeparator", Math::round(4 * scale));