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 translation preview in editor #96921

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
15 changes: 13 additions & 2 deletions core/string/translation_domain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ void TranslationDomain::clear() {
}

StringName TranslationDomain::translate(const StringName &p_message, const StringName &p_context) const {
const String &locale = TranslationServer::get_singleton()->get_locale();
const String &locale = locale_override.is_empty() ? TranslationServer::get_singleton()->get_locale() : locale_override;
StringName res = get_message_from_translations(locale, p_message, p_context);

const String &fallback = TranslationServer::get_singleton()->get_fallback_locale();
Expand All @@ -299,7 +299,7 @@ StringName TranslationDomain::translate(const StringName &p_message, const Strin
}

StringName TranslationDomain::translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const {
const String &locale = TranslationServer::get_singleton()->get_locale();
const String &locale = locale_override.is_empty() ? TranslationServer::get_singleton()->get_locale() : locale_override;
StringName res = get_message_from_translations(locale, p_message, p_message_plural, p_n, p_context);

const String &fallback = TranslationServer::get_singleton()->get_fallback_locale();
Expand All @@ -316,6 +316,15 @@ StringName TranslationDomain::translate_plural(const StringName &p_message, cons
return res;
}

String TranslationDomain::get_locale_override() const {
return locale_override;
}

void TranslationDomain::set_locale_override(const String &p_locale) {
String new_locale = p_locale.is_empty() ? p_locale : TranslationServer::get_singleton()->standardize_locale(p_locale);
locale_override = new_locale;
}

bool TranslationDomain::is_pseudolocalization_enabled() const {
return pseudolocalization.enabled;
}
Expand Down Expand Up @@ -417,6 +426,8 @@ void TranslationDomain::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear"), &TranslationDomain::clear);
ClassDB::bind_method(D_METHOD("translate", "message", "context"), &TranslationDomain::translate, DEFVAL(StringName()));
ClassDB::bind_method(D_METHOD("translate_plural", "message", "message_plural", "n", "context"), &TranslationDomain::translate_plural, DEFVAL(StringName()));
ClassDB::bind_method(D_METHOD("get_locale_override"), &TranslationDomain::get_locale_override);
ClassDB::bind_method(D_METHOD("set_locale_override", "locale"), &TranslationDomain::set_locale_override);

ClassDB::bind_method(D_METHOD("is_pseudolocalization_enabled"), &TranslationDomain::is_pseudolocalization_enabled);
ClassDB::bind_method(D_METHOD("set_pseudolocalization_enabled", "enabled"), &TranslationDomain::set_pseudolocalization_enabled);
Expand Down
4 changes: 4 additions & 0 deletions core/string/translation_domain.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class TranslationDomain : public RefCounted {
String suffix = "]";
};

String locale_override;
HashSet<Ref<Translation>> translations;
PseudolocalizationConfig pseudolocalization;

Expand Down Expand Up @@ -80,6 +81,9 @@ class TranslationDomain : public RefCounted {
StringName translate(const StringName &p_message, const StringName &p_context) const;
StringName translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const;

String get_locale_override() const;
void set_locale_override(const String &p_locale);

bool is_pseudolocalization_enabled() const;
void set_pseudolocalization_enabled(bool p_enabled);
bool is_pseudolocalization_accents_enabled() const;
Expand Down
1 change: 1 addition & 0 deletions core/string/translation_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class TranslationServer : public Object {
public:
_FORCE_INLINE_ static TranslationServer *get_singleton() { return singleton; }

Ref<TranslationDomain> get_main_domain() const { return main_domain; }
Ref<TranslationDomain> get_editor_domain() const { return editor_domain; }

void set_enabled(bool p_enabled) { enabled = p_enabled; }
Expand Down
16 changes: 16 additions & 0 deletions doc/classes/TranslationDomain.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<description>
[TranslationDomain] is a self-contained collection of [Translation] resources. Translations can be added to or removed from it.
If you're working with the main translation domain, it is more convenient to use the wrap methods on [TranslationServer].
Because translation domain is intended to be advanced usage, modifications to it do not emit [constant MainLoop.NOTIFICATION_TRANSLATION_CHANGED] on the scene tree automatically. See the description of methods and properties below for details.
</description>
<tutorials>
</tutorials>
Expand All @@ -23,6 +24,12 @@
Removes all translations.
</description>
</method>
<method name="get_locale_override" qualifiers="const">
<return type="String" />
<description>
Returns the locale override of the domain. Returns an empty string if locale override is disabled.
</description>
</method>
<method name="get_translation_object" qualifiers="const">
<return type="Translation" />
<param index="0" name="locale" type="String" />
Expand All @@ -44,6 +51,15 @@
Removes the given translation.
</description>
</method>
<method name="set_locale_override">
<return type="void" />
<param index="0" name="locale" type="String" />
<description>
Sets the locale override of the domain.
If [param locale] is an empty string, locale override is disabled. Otherwise, [param locale] will be standardized to match known locales (e.g. [code]en-US[/code] would be matched to [code]en_US[/code]).
[b]Note: [/b] Updating this property does not automatically update texts in the scene tree. Please propagate the [constant MainLoop.NOTIFICATION_TRANSLATION_CHANGED] signal manually.
</description>
</method>
<method name="translate" qualifiers="const">
<return type="StringName" />
<param index="0" name="message" type="StringName" />
Expand Down
28 changes: 28 additions & 0 deletions editor/editor_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,8 @@ void EditorNode::_update_from_settings() {

ResourceImporterTexture::get_singleton()->update_imports();

_update_translations();

#ifdef DEBUG_ENABLED
NavigationServer3D::get_singleton()->set_debug_navigation_edge_connection_color(GLOBAL_GET("debug/shapes/navigation/edge_connection_color"));
NavigationServer3D::get_singleton()->set_debug_navigation_geometry_edge_color(GLOBAL_GET("debug/shapes/navigation/geometry_edge_color"));
Expand All @@ -492,6 +494,12 @@ void EditorNode::_gdextensions_reloaded() {
EditorHelp::generate_doc();
}

void EditorNode::_update_translations() {
TranslationServer::get_singleton()->clear();
TranslationServer::get_singleton()->load_translations();
scene_root->propagate_notification(NOTIFICATION_TRANSLATION_CHANGED);
}

void EditorNode::_update_theme(bool p_skip_creation) {
if (!p_skip_creation) {
theme = EditorThemeManager::generate_theme(theme);
Expand Down Expand Up @@ -3751,6 +3759,24 @@ void EditorNode::set_edited_scene_root(Node *p_scene, bool p_auto_add) {
}
}

String EditorNode::get_preview_locale() const {
return TranslationServer::get_singleton()->get_main_domain()->get_locale_override();
}

void EditorNode::set_preview_locale(const String &p_locale) {
Ref<TranslationDomain> main_domain = TranslationServer::get_singleton()->get_main_domain();
if (main_domain->get_locale_override() == p_locale) {
return;
}
const bool auto_translate_mode_changed = main_domain->get_locale_override().is_empty() != p_locale.is_empty();
main_domain->set_locale_override(p_locale);
if (auto_translate_mode_changed) {
scene_root->set_auto_translate_mode(p_locale.is_empty() ? AUTO_TRANSLATE_MODE_DISABLED : AUTO_TRANSLATE_MODE_ALWAYS);
} else {
scene_root->propagate_notification(NOTIFICATION_TRANSLATION_CHANGED);
}
}

Dictionary EditorNode::_get_main_scene_state() {
Dictionary state;
state["scene_tree_offset"] = SceneTreeDock::get_singleton()->get_tree_editor()->get_scene_tree()->get_vscroll_bar()->get_value();
Expand Down Expand Up @@ -7119,6 +7145,8 @@ 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_translation_domain(StringName());
scene_root->set_embedding_subwindows(true);
scene_root->set_disable_3d(true);
scene_root->set_disable_input(true);
Expand Down
4 changes: 4 additions & 0 deletions editor/editor_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,7 @@ class EditorNode : public Node {
void _update_vsync_mode();
void _update_from_settings();
void _gdextensions_reloaded();
void _update_translations();

void _renderer_selected(int);
void _update_renderer_color();
Expand Down Expand Up @@ -779,6 +780,9 @@ class EditorNode : public Node {
void set_edited_scene_root(Node *p_scene, bool p_auto_add);
Node *get_edited_scene() { return editor_data.get_edited_scene_root(); }

String get_preview_locale() const;
void set_preview_locale(const String &p_locale);

void fix_dependencies(const String &p_for_file);
int new_scene();
Error load_scene(const String &p_scene, bool p_ignore_broken_deps = false, bool p_set_inherited = false, bool p_force_open_imported = false, bool p_silent_change_tab = false);
Expand Down
36 changes: 36 additions & 0 deletions editor/plugins/canvas_item_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "core/input/input.h"
#include "core/os/keyboard.h"
#include "core/string/translation_server.h"
#include "editor/debugger/editor_debugger_node.h"
#include "editor/editor_main_screen.h"
#include "editor/editor_node.h"
Expand Down Expand Up @@ -63,6 +64,7 @@
#include "scene/main/window.h"
#include "scene/resources/packed_scene.h"
#include "scene/resources/style_box_texture.h"
#include "scene/scene_string_names.h"

#define RULER_WIDTH (15 * EDSCALE)
#define DRAG_THRESHOLD (8 * EDSCALE)
Expand Down Expand Up @@ -1062,6 +1064,34 @@ void CanvasItemEditor::_switch_theme_preview(int p_mode) {
EditorNode::get_singleton()->update_preview_themes(theme_preview);
}

void CanvasItemEditor::_prepare_translation_menu() {
const String current_preview_locale = EditorNode::get_singleton()->get_preview_locale();

translation_menu->clear();
translation_menu->add_radio_check_item(TTR("None"));
translation_menu->set_item_metadata(-1, "");
if (current_preview_locale.is_empty()) {
translation_menu->set_item_checked(-1, true);
}

const Vector<String> locales = TranslationServer::get_singleton()->get_loaded_locales();
if (!locales.is_empty()) {
translation_menu->add_separator();
}
for (const String &locale : locales) {
translation_menu->add_radio_check_item(locale);
translation_menu->set_item_metadata(-1, locale);
if (locale == current_preview_locale) {
translation_menu->set_item_checked(-1, true);
}
}
}

void CanvasItemEditor::_switch_translation_preview(int p_translation) {
view_menu->get_popup()->hide();
EditorNode::get_singleton()->set_preview_locale(translation_menu->get_item_metadata(p_translation));
}

bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_event) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Ref<InputEventMouseButton> b = p_event;
Expand Down Expand Up @@ -5582,6 +5612,12 @@ CanvasItemEditor::CanvasItemEditor() {
theme_menu->set_item_checked(i, i == theme_preview);
}

translation_menu = memnew(PopupMenu);
translation_menu->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
translation_menu->connect("about_to_popup", callable_mp(this, &CanvasItemEditor::_prepare_translation_menu));
translation_menu->connect("index_pressed", callable_mp(this, &CanvasItemEditor::_switch_translation_preview));
p->add_submenu_node_item(TTR("Preview Translation"), translation_menu);

main_menu_hbox->add_child(memnew(VSeparator));

// Contextual toolbars.
Expand Down
4 changes: 4 additions & 0 deletions editor/plugins/canvas_item_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ class CanvasItemEditor : public VBoxContainer {
MenuButton *view_menu = nullptr;
PopupMenu *grid_menu = nullptr;
PopupMenu *theme_menu = nullptr;
PopupMenu *translation_menu = nullptr;
PopupMenu *gizmos_menu = nullptr;
HBoxContainer *animation_hb = nullptr;
MenuButton *animation_menu = nullptr;
Expand Down Expand Up @@ -432,6 +433,9 @@ class CanvasItemEditor : public VBoxContainer {
ThemePreviewMode theme_preview = THEME_PREVIEW_PROJECT;
void _switch_theme_preview(int p_mode);

void _prepare_translation_menu();
void _switch_translation_preview(int p_translation);

List<CanvasItem *> _get_edited_canvas_items(bool p_retrieve_locked = false, bool p_remove_canvas_item_if_parent_in_selection = true, bool *r_has_locked_items = nullptr) const;
Rect2 _get_encompassing_rect_from_list(const List<CanvasItem *> &p_list);
void _expand_encompassing_rect_using_children(Rect2 &r_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D(), bool include_locked_nodes = true);
Expand Down
7 changes: 0 additions & 7 deletions scene/main/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,6 @@ void Node::_notification(int p_notification) {
data.is_auto_translate_dirty = true;
data.is_translation_domain_dirty = true;

#ifdef TOOLS_ENABLED
// Don't translate UI elements when they're being edited.
if (is_part_of_edited_scene()) {
set_message_translation(false);
}
#endif

if (data.auto_translate_mode != AUTO_TRANSLATE_MODE_DISABLED) {
notification(NOTIFICATION_TRANSLATION_CHANGED);
}
Expand Down
Loading