Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add context support for editor property name i18n #82852

Merged
merged 1 commit into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions core/string/translation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -776,9 +776,9 @@ void TranslationServer::set_property_translation(const Ref<Translation> &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;
}
Expand Down
2 changes: 1 addition & 1 deletion core/string/translation.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<Translation> &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<Translation> &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;
Expand Down
4 changes: 2 additions & 2 deletions editor/editor_feature_profile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 5 additions & 5 deletions editor/editor_inspector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ bool EditorInspector::_property_path_matches(const String &p_property_path, cons

const Vector<String> 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;
}
}
Expand Down Expand Up @@ -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("/");
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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));
Expand Down
43 changes: 41 additions & 2 deletions editor/editor_property_name_processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, StringName> *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;
Expand All @@ -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;
Expand Down Expand Up @@ -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() {
Expand Down
8 changes: 7 additions & 1 deletion editor/editor_property_name_processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,14 @@ class EditorPropertyNameProcessor : public Node {
HashMap<String, String> capitalize_string_remaps;
LocalVector<String> stop_words; // Exceptions that shouldn't be capitalized.

HashMap<String, HashMap<String, StringName>> 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 {
Expand All @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions editor/editor_sectioned_inspector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ static bool _property_path_matches(const String &p_property_path, const String &

const Vector<String> 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;
}
}
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions editor/editor_settings_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion editor/plugins/tiles/tile_data_editors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion editor/scene_tree_dock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3156,7 +3156,7 @@ void SceneTreeDock::_files_dropped(const Vector<String> &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);
}

Expand Down
2 changes: 0 additions & 2 deletions scene/theme/default_theme.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -936,8 +936,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("separator", "VSeparator", separator_vertical);

theme->set_icon("close", "Icons", icons["close"]);
theme->set_font("normal", "Fonts", Ref<Font>());
theme->set_font("large", "Fonts", Ref<Font>());
Comment on lines -939 to -940
Copy link
Member Author

@timothyqiu timothyqiu Oct 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: These two are removed because

  • They were used to store default theme fonts when Godot was open sourced. But fonts were changed to a dedicated theme member later, so these entries were abandoned.
  • They add unnecessary strings to translate. Not worth adding exceptions for.


theme->set_constant("separation", "HSeparator", Math::round(4 * scale));
theme->set_constant("separation", "VSeparator", Math::round(4 * scale));
Expand Down
Loading