Add translation preview in editor
This commit is contained in:
@ -287,7 +287,11 @@ void TranslationDomain::clear() {
|
||||
}
|
||||
|
||||
StringName TranslationDomain::translate(const StringName &p_message, const StringName &p_context) const {
|
||||
const String &locale = TranslationServer::get_singleton()->get_locale();
|
||||
if (!enabled) {
|
||||
return p_message;
|
||||
}
|
||||
|
||||
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();
|
||||
@ -302,7 +306,11 @@ 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();
|
||||
if (!enabled) {
|
||||
return p_n == 1 ? p_message : p_message_plural;
|
||||
}
|
||||
|
||||
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();
|
||||
@ -319,6 +327,22 @@ 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) {
|
||||
locale_override = p_locale.is_empty() ? p_locale : TranslationServer::get_singleton()->standardize_locale(p_locale);
|
||||
}
|
||||
|
||||
bool TranslationDomain::is_enabled() const {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
void TranslationDomain::set_enabled(bool p_enabled) {
|
||||
enabled = p_enabled;
|
||||
}
|
||||
|
||||
bool TranslationDomain::is_pseudolocalization_enabled() const {
|
||||
return pseudolocalization.enabled;
|
||||
}
|
||||
@ -424,6 +448,10 @@ 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_enabled"), &TranslationDomain::is_enabled);
|
||||
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &TranslationDomain::set_enabled);
|
||||
|
||||
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);
|
||||
@ -445,6 +473,7 @@ void TranslationDomain::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_pseudolocalization_suffix", "suffix"), &TranslationDomain::set_pseudolocalization_suffix);
|
||||
ClassDB::bind_method(D_METHOD("pseudolocalize", "message"), &TranslationDomain::pseudolocalize);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::Type::BOOL, "enabled"), "set_enabled", "is_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::Type::BOOL, "pseudolocalization_enabled"), "set_pseudolocalization_enabled", "is_pseudolocalization_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::Type::BOOL, "pseudolocalization_accents_enabled"), "set_pseudolocalization_accents_enabled", "is_pseudolocalization_accents_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::Type::BOOL, "pseudolocalization_double_vowels_enabled"), "set_pseudolocalization_double_vowels_enabled", "is_pseudolocalization_double_vowels_enabled");
|
||||
|
||||
@ -49,6 +49,9 @@ class TranslationDomain : public RefCounted {
|
||||
String suffix = "]";
|
||||
};
|
||||
|
||||
bool enabled = true;
|
||||
|
||||
String locale_override;
|
||||
HashSet<Ref<Translation>> translations;
|
||||
PseudolocalizationConfig pseudolocalization;
|
||||
|
||||
@ -79,6 +82,12 @@ public:
|
||||
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_enabled() const;
|
||||
void set_enabled(bool p_enabled);
|
||||
|
||||
bool is_pseudolocalization_enabled() const;
|
||||
void set_pseudolocalization_enabled(bool p_enabled);
|
||||
bool is_pseudolocalization_accents_enabled() const;
|
||||
|
||||
@ -406,21 +406,10 @@ void TranslationServer::clear() {
|
||||
}
|
||||
|
||||
StringName TranslationServer::translate(const StringName &p_message, const StringName &p_context) const {
|
||||
if (!enabled) {
|
||||
return p_message;
|
||||
}
|
||||
|
||||
return main_domain->translate(p_message, p_context);
|
||||
}
|
||||
|
||||
StringName TranslationServer::translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const {
|
||||
if (!enabled) {
|
||||
if (p_n == 1) {
|
||||
return p_message;
|
||||
}
|
||||
return p_message_plural;
|
||||
}
|
||||
|
||||
return main_domain->translate_plural(p_message, p_message_plural, p_n, p_context);
|
||||
}
|
||||
|
||||
|
||||
@ -47,8 +47,6 @@ class TranslationServer : public Object {
|
||||
|
||||
mutable HashMap<String, int> locale_compare_cache;
|
||||
|
||||
bool enabled = true;
|
||||
|
||||
static inline TranslationServer *singleton = nullptr;
|
||||
|
||||
static void _bind_methods();
|
||||
@ -96,11 +94,9 @@ 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; }
|
||||
_FORCE_INLINE_ bool is_enabled() const { return enabled; }
|
||||
|
||||
void set_locale(const String &p_locale);
|
||||
String get_locale() const;
|
||||
String get_fallback_locale() const;
|
||||
|
||||
@ -23,6 +23,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" />
|
||||
@ -44,6 +50,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] Calling this method 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" />
|
||||
@ -65,6 +80,9 @@
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">
|
||||
If [code]true[/code], translation is enabled. Otherwise, [method translate] and [method translate_plural] will return the input message unchanged regardless of the current locale.
|
||||
</member>
|
||||
<member name="pseudolocalization_accents_enabled" type="bool" setter="set_pseudolocalization_accents_enabled" getter="is_pseudolocalization_accents_enabled" default="true">
|
||||
Replace all characters with their accented variants during pseudolocalization.
|
||||
[b]Note:[/b] Updating this property does not automatically update texts in the scene tree. Please propagate the [constant MainLoop.NOTIFICATION_TRANSLATION_CHANGED] notification manually after you have finished modifying pseudolocalization related options.
|
||||
|
||||
@ -509,6 +509,8 @@ void EditorNode::_update_from_settings() {
|
||||
|
||||
ResourceImporterTexture::get_singleton()->update_imports();
|
||||
|
||||
_update_translations();
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
NavigationServer2D::get_singleton()->set_debug_navigation_edge_connection_color(GLOBAL_GET("debug/shapes/navigation/2d/edge_connection_color"));
|
||||
NavigationServer2D::get_singleton()->set_debug_navigation_geometry_edge_color(GLOBAL_GET("debug/shapes/navigation/2d/geometry_edge_color"));
|
||||
@ -544,6 +546,23 @@ void EditorNode::_gdextensions_reloaded() {
|
||||
EditorHelp::generate_doc(true, false);
|
||||
}
|
||||
|
||||
void EditorNode::_update_translations() {
|
||||
Ref<TranslationDomain> main = TranslationServer::get_singleton()->get_main_domain();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorNode::_update_theme(bool p_skip_creation) {
|
||||
if (!p_skip_creation) {
|
||||
theme = EditorThemeManager::generate_theme(theme);
|
||||
@ -4025,6 +4044,33 @@ void EditorNode::set_edited_scene_root(Node *p_scene, bool p_auto_add) {
|
||||
}
|
||||
}
|
||||
|
||||
String EditorNode::get_preview_locale() const {
|
||||
const Ref<TranslationDomain> &main_domain = TranslationServer::get_singleton()->get_main_domain();
|
||||
return main_domain->is_enabled() ? main_domain->get_locale_override() : String();
|
||||
}
|
||||
|
||||
void EditorNode::set_preview_locale(const String &p_locale) {
|
||||
const String &prev_locale = get_preview_locale();
|
||||
if (prev_locale == p_locale) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Texts set in the editor could be identifiers that should never be translated.
|
||||
// So we need to disable translation entirely.
|
||||
Ref<TranslationDomain> main_domain = TranslationServer::get_singleton()->get_main_domain();
|
||||
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"));
|
||||
}
|
||||
|
||||
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();
|
||||
@ -7060,6 +7106,7 @@ void EditorNode::_bind_methods() {
|
||||
ADD_SIGNAL(MethodInfo("scene_saved", PropertyInfo(Variant::STRING, "path")));
|
||||
ADD_SIGNAL(MethodInfo("scene_changed"));
|
||||
ADD_SIGNAL(MethodInfo("scene_closed", PropertyInfo(Variant::STRING, "path")));
|
||||
ADD_SIGNAL(MethodInfo("preview_locale_changed"));
|
||||
}
|
||||
|
||||
static Node *_resource_get_edited_scene() {
|
||||
@ -7354,7 +7401,7 @@ EditorNode::EditorNode() {
|
||||
ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &EditorNode::_update_from_settings));
|
||||
GDExtensionManager::get_singleton()->connect("extensions_reloaded", callable_mp(this, &EditorNode::_gdextensions_reloaded));
|
||||
|
||||
TranslationServer::get_singleton()->set_enabled(false);
|
||||
TranslationServer::get_singleton()->get_main_domain()->set_enabled(false);
|
||||
// Load settings.
|
||||
if (!EditorSettings::get_singleton()) {
|
||||
EditorSettings::create();
|
||||
@ -7767,6 +7814,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);
|
||||
|
||||
@ -615,6 +615,7 @@ private:
|
||||
void _update_vsync_mode();
|
||||
void _update_from_settings();
|
||||
void _gdextensions_reloaded();
|
||||
void _update_translations();
|
||||
|
||||
void _renderer_selected(int);
|
||||
void _update_renderer_color();
|
||||
@ -819,6 +820,9 @@ public:
|
||||
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);
|
||||
|
||||
76
editor/gui/editor_translation_preview_button.cpp
Normal file
76
editor/gui/editor_translation_preview_button.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
/**************************************************************************/
|
||||
/* editor_translation_preview_button.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "editor_translation_preview_button.h"
|
||||
|
||||
#include "core/string/translation_server.h"
|
||||
#include "editor/editor_node.h"
|
||||
|
||||
void EditorTranslationPreviewButton::_update() {
|
||||
const String &locale = EditorNode::get_singleton()->get_preview_locale();
|
||||
|
||||
if (locale.is_empty()) {
|
||||
hide();
|
||||
return;
|
||||
}
|
||||
|
||||
const String name = TranslationServer::get_singleton()->get_locale_name(locale);
|
||||
set_text(vformat(TTR("Previewing: %s"), name == locale ? locale : name + " [" + locale + "]"));
|
||||
show();
|
||||
}
|
||||
|
||||
void EditorTranslationPreviewButton::pressed() {
|
||||
EditorNode::get_singleton()->set_preview_locale(String());
|
||||
}
|
||||
|
||||
void EditorTranslationPreviewButton::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
set_button_icon(get_editor_theme_icon(SNAME("Translation")));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_TRANSLATION_CHANGED: {
|
||||
_update();
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_READY: {
|
||||
EditorNode::get_singleton()->connect("preview_locale_changed", callable_mp(this, &EditorTranslationPreviewButton::_update));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
EditorTranslationPreviewButton::EditorTranslationPreviewButton() {
|
||||
set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
set_tooltip_auto_translate_mode(AUTO_TRANSLATE_MODE_ALWAYS);
|
||||
set_accessibility_name(TTRC("Disable Translation Preview"));
|
||||
set_tooltip_text(TTRC("Previewing translation. Click to disable."));
|
||||
set_focus_mode(FOCUS_NONE);
|
||||
set_visible(false);
|
||||
}
|
||||
47
editor/gui/editor_translation_preview_button.h
Normal file
47
editor/gui/editor_translation_preview_button.h
Normal file
@ -0,0 +1,47 @@
|
||||
/**************************************************************************/
|
||||
/* editor_translation_preview_button.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/button.h"
|
||||
|
||||
class EditorTranslationPreviewButton : public Button {
|
||||
GDCLASS(EditorTranslationPreviewButton, Button);
|
||||
|
||||
void _update();
|
||||
|
||||
protected:
|
||||
virtual void pressed() override;
|
||||
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
EditorTranslationPreviewButton();
|
||||
};
|
||||
81
editor/gui/editor_translation_preview_menu.cpp
Normal file
81
editor/gui/editor_translation_preview_menu.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
/**************************************************************************/
|
||||
/* editor_translation_preview_menu.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "editor/gui/editor_translation_preview_menu.h"
|
||||
|
||||
#include "core/string/translation_server.h"
|
||||
#include "editor/editor_node.h"
|
||||
|
||||
void EditorTranslationPreviewMenu::_prepare() {
|
||||
const String current_preview_locale = EditorNode::get_singleton()->get_preview_locale();
|
||||
|
||||
clear();
|
||||
reset_size();
|
||||
|
||||
add_radio_check_item(TTRC("None"));
|
||||
set_item_metadata(-1, "");
|
||||
if (current_preview_locale.is_empty()) {
|
||||
set_item_checked(-1, true);
|
||||
}
|
||||
|
||||
const Vector<String> locales = TranslationServer::get_singleton()->get_loaded_locales();
|
||||
if (!locales.is_empty()) {
|
||||
add_separator();
|
||||
}
|
||||
for (const String &locale : locales) {
|
||||
const String name = TranslationServer::get_singleton()->get_locale_name(locale);
|
||||
add_radio_check_item(name == locale ? name : name + " [" + locale + "]");
|
||||
set_item_auto_translate_mode(-1, AUTO_TRANSLATE_MODE_DISABLED);
|
||||
set_item_metadata(-1, locale);
|
||||
if (locale == current_preview_locale) {
|
||||
set_item_checked(-1, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EditorTranslationPreviewMenu::_pressed(int p_index) {
|
||||
for (int i = 0; i < get_item_count(); i++) {
|
||||
set_item_checked(i, i == p_index);
|
||||
}
|
||||
EditorNode::get_singleton()->set_preview_locale(get_item_metadata(p_index));
|
||||
}
|
||||
|
||||
void EditorTranslationPreviewMenu::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_READY: {
|
||||
connect("about_to_popup", callable_mp(this, &EditorTranslationPreviewMenu::_prepare));
|
||||
connect("index_pressed", callable_mp(this, &EditorTranslationPreviewMenu::_pressed));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
EditorTranslationPreviewMenu::EditorTranslationPreviewMenu() {
|
||||
set_hide_on_checkable_item_selection(false);
|
||||
}
|
||||
46
editor/gui/editor_translation_preview_menu.h
Normal file
46
editor/gui/editor_translation_preview_menu.h
Normal file
@ -0,0 +1,46 @@
|
||||
/**************************************************************************/
|
||||
/* editor_translation_preview_menu.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/popup_menu.h"
|
||||
|
||||
class EditorTranslationPreviewMenu : public PopupMenu {
|
||||
GDCLASS(EditorTranslationPreviewMenu, PopupMenu);
|
||||
|
||||
void _prepare();
|
||||
void _pressed(int p_index);
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
EditorTranslationPreviewMenu();
|
||||
};
|
||||
@ -41,6 +41,8 @@
|
||||
#include "editor/editor_undo_redo_manager.h"
|
||||
#include "editor/gui/editor_run_bar.h"
|
||||
#include "editor/gui/editor_toaster.h"
|
||||
#include "editor/gui/editor_translation_preview_button.h"
|
||||
#include "editor/gui/editor_translation_preview_menu.h"
|
||||
#include "editor/gui/editor_zoom_widget.h"
|
||||
#include "editor/plugins/animation_player_editor_plugin.h"
|
||||
#include "editor/plugins/editor_context_menu_plugin.h"
|
||||
@ -5395,6 +5397,13 @@ CanvasItemEditor::CanvasItemEditor() {
|
||||
controls_hb->add_child(zoom_widget);
|
||||
zoom_widget->connect("zoom_changed", callable_mp(this, &CanvasItemEditor::_update_zoom));
|
||||
|
||||
EditorTranslationPreviewButton *translation_preview_button = memnew(EditorTranslationPreviewButton);
|
||||
translation_preview_button->set_flat(true);
|
||||
translation_preview_button->add_theme_constant_override("outline_size", Math::ceil(2 * EDSCALE));
|
||||
translation_preview_button->add_theme_color_override("font_outline_color", Color(0, 0, 0));
|
||||
translation_preview_button->add_theme_color_override(SceneStringName(font_color), Color(1, 1, 1));
|
||||
controls_hb->add_child(translation_preview_button);
|
||||
|
||||
panner.instantiate();
|
||||
panner->set_callbacks(callable_mp(this, &CanvasItemEditor::_pan_callback), callable_mp(this, &CanvasItemEditor::_zoom_callback));
|
||||
|
||||
@ -5675,6 +5684,8 @@ CanvasItemEditor::CanvasItemEditor() {
|
||||
theme_menu->set_item_checked(i, i == theme_preview);
|
||||
}
|
||||
|
||||
p->add_submenu_node_item(TTRC("Preview Translation"), memnew(EditorTranslationPreviewMenu));
|
||||
|
||||
main_menu_hbox->add_child(memnew(VSeparator));
|
||||
|
||||
// Contextual toolbars.
|
||||
|
||||
@ -44,6 +44,8 @@
|
||||
#include "editor/editor_undo_redo_manager.h"
|
||||
#include "editor/gui/editor_run_bar.h"
|
||||
#include "editor/gui/editor_spin_slider.h"
|
||||
#include "editor/gui/editor_translation_preview_button.h"
|
||||
#include "editor/gui/editor_translation_preview_menu.h"
|
||||
#include "editor/plugins/animation_player_editor_plugin.h"
|
||||
#include "editor/plugins/gizmos/audio_listener_3d_gizmo_plugin.h"
|
||||
#include "editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.h"
|
||||
@ -2908,6 +2910,23 @@ void Node3DEditorViewport::_project_settings_changed() {
|
||||
viewport->set_anisotropic_filtering_level(anisotropic_filtering_level);
|
||||
}
|
||||
|
||||
static void override_button_stylebox(Button *p_button, const Ref<StyleBox> p_stylebox) {
|
||||
p_button->begin_bulk_theme_override();
|
||||
p_button->add_theme_style_override(CoreStringName(normal), p_stylebox);
|
||||
p_button->add_theme_style_override("normal_mirrored", p_stylebox);
|
||||
p_button->add_theme_style_override(SceneStringName(hover), p_stylebox);
|
||||
p_button->add_theme_style_override("hover_mirrored", p_stylebox);
|
||||
p_button->add_theme_style_override("hover_pressed", p_stylebox);
|
||||
p_button->add_theme_style_override("hover_pressed_mirrored", p_stylebox);
|
||||
p_button->add_theme_style_override(SceneStringName(pressed), p_stylebox);
|
||||
p_button->add_theme_style_override("pressed_mirrored", p_stylebox);
|
||||
p_button->add_theme_style_override("focus", p_stylebox);
|
||||
p_button->add_theme_style_override("focus_mirrored", p_stylebox);
|
||||
p_button->add_theme_style_override("disabled", p_stylebox);
|
||||
p_button->add_theme_style_override("disabled_mirrored", p_stylebox);
|
||||
p_button->end_bulk_theme_override();
|
||||
}
|
||||
|
||||
void Node3DEditorViewport::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_READY: {
|
||||
@ -3250,35 +3269,9 @@ void Node3DEditorViewport::_notification(int p_what) {
|
||||
|
||||
const Ref<StyleBox> &information_3d_stylebox = gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles));
|
||||
|
||||
view_display_menu->begin_bulk_theme_override();
|
||||
view_display_menu->add_theme_style_override(CoreStringName(normal), information_3d_stylebox);
|
||||
view_display_menu->add_theme_style_override("normal_mirrored", information_3d_stylebox);
|
||||
view_display_menu->add_theme_style_override(SceneStringName(hover), information_3d_stylebox);
|
||||
view_display_menu->add_theme_style_override("hover_mirrored", information_3d_stylebox);
|
||||
view_display_menu->add_theme_style_override("hover_pressed", information_3d_stylebox);
|
||||
view_display_menu->add_theme_style_override("hover_pressed_mirrored", information_3d_stylebox);
|
||||
view_display_menu->add_theme_style_override(SceneStringName(pressed), information_3d_stylebox);
|
||||
view_display_menu->add_theme_style_override("pressed_mirrored", information_3d_stylebox);
|
||||
view_display_menu->add_theme_style_override("focus", information_3d_stylebox);
|
||||
view_display_menu->add_theme_style_override("focus_mirrored", information_3d_stylebox);
|
||||
view_display_menu->add_theme_style_override("disabled", information_3d_stylebox);
|
||||
view_display_menu->add_theme_style_override("disabled_mirrored", information_3d_stylebox);
|
||||
view_display_menu->end_bulk_theme_override();
|
||||
|
||||
preview_camera->begin_bulk_theme_override();
|
||||
preview_camera->add_theme_style_override(CoreStringName(normal), information_3d_stylebox);
|
||||
preview_camera->add_theme_style_override("normal_mirrored", information_3d_stylebox);
|
||||
preview_camera->add_theme_style_override(SceneStringName(hover), information_3d_stylebox);
|
||||
preview_camera->add_theme_style_override("hover_mirrored", information_3d_stylebox);
|
||||
preview_camera->add_theme_style_override("hover_pressed", information_3d_stylebox);
|
||||
preview_camera->add_theme_style_override("hover_pressed_mirrored", information_3d_stylebox);
|
||||
preview_camera->add_theme_style_override(SceneStringName(pressed), information_3d_stylebox);
|
||||
preview_camera->add_theme_style_override("pressed_mirrored", information_3d_stylebox);
|
||||
preview_camera->add_theme_style_override("focus", information_3d_stylebox);
|
||||
preview_camera->add_theme_style_override("focus_mirrored", information_3d_stylebox);
|
||||
preview_camera->add_theme_style_override("disabled", information_3d_stylebox);
|
||||
preview_camera->add_theme_style_override("disabled_mirrored", information_3d_stylebox);
|
||||
preview_camera->end_bulk_theme_override();
|
||||
override_button_stylebox(view_display_menu, information_3d_stylebox);
|
||||
override_button_stylebox(translation_preview_button, information_3d_stylebox);
|
||||
override_button_stylebox(preview_camera, information_3d_stylebox);
|
||||
|
||||
frame_time_gradient->set_color(0, get_theme_color(SNAME("success_color"), EditorStringName(Editor)));
|
||||
frame_time_gradient->set_color(1, get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));
|
||||
@ -5597,12 +5590,15 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
|
||||
vbox->set_offset(SIDE_LEFT, 10 * EDSCALE);
|
||||
vbox->set_offset(SIDE_TOP, 10 * EDSCALE);
|
||||
|
||||
HBoxContainer *hbox = memnew(HBoxContainer);
|
||||
vbox->add_child(hbox);
|
||||
|
||||
view_display_menu = memnew(MenuButton);
|
||||
view_display_menu->set_flat(false);
|
||||
view_display_menu->set_h_size_flags(0);
|
||||
view_display_menu->set_shortcut_context(this);
|
||||
view_display_menu->set_accessibility_name(TTRC("View"));
|
||||
vbox->add_child(view_display_menu);
|
||||
hbox->add_child(view_display_menu);
|
||||
|
||||
view_display_menu->get_popup()->set_hide_on_checkable_item_selection(false);
|
||||
|
||||
@ -5745,6 +5741,9 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
|
||||
ED_SHORTCUT("spatial_editor/instant_scale", TTRC("Begin Scale Transformation"));
|
||||
ED_SHORTCUT("spatial_editor/collision_reposition", TTRC("Reposition Using Collisions"), KeyModifierMask::SHIFT | Key::G);
|
||||
|
||||
translation_preview_button = memnew(EditorTranslationPreviewButton);
|
||||
hbox->add_child(translation_preview_button);
|
||||
|
||||
preview_camera = memnew(CheckBox);
|
||||
preview_camera->set_text(TTR("Preview"));
|
||||
// Using Control even on macOS to avoid conflict with Quick Open shortcut.
|
||||
@ -9357,6 +9356,9 @@ Node3DEditor::Node3DEditor() {
|
||||
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTRC("View Origin")), MENU_VIEW_ORIGIN);
|
||||
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTRC("View Grid"), Key::NUMBERSIGN), MENU_VIEW_GRID);
|
||||
|
||||
p->add_separator();
|
||||
p->add_submenu_node_item(TTRC("Preview Translation"), memnew(EditorTranslationPreviewMenu));
|
||||
|
||||
p->add_separator();
|
||||
p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTRC("Settings...")), MENU_VIEW_CAMERA_SETTINGS);
|
||||
|
||||
|
||||
@ -243,6 +243,7 @@ private:
|
||||
|
||||
EditorSelection *editor_selection = nullptr;
|
||||
|
||||
Button *translation_preview_button = nullptr;
|
||||
CheckBox *preview_camera = nullptr;
|
||||
SubViewportContainer *subviewport_container = nullptr;
|
||||
|
||||
|
||||
@ -197,13 +197,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.input) {
|
||||
add_to_group("_vp_input" + itos(get_viewport()->get_instance_id()));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user