mirror of
https://github.com/godotengine/godot.git
synced 2024-11-21 19:42:43 +00:00
Add context support for editor property name i18n
This commit is contained in:
parent
29b3d9e9e5
commit
479b7afa8e
@ -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;
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ public:
|
||||
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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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));
|
||||
|
@ -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;
|
||||
@ -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() {
|
||||
|
@ -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 {
|
||||
@ -62,7 +67,8 @@ public:
|
||||
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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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>());
|
||||
|
||||
theme->set_constant("separation", "HSeparator", Math::round(4 * scale));
|
||||
theme->set_constant("separation", "VSeparator", Math::round(4 * scale));
|
||||
|
Loading…
Reference in New Issue
Block a user