Merge pull request #110378 from timothyqiu/rtl-preview

Make text-related nodes translation domain aware
This commit is contained in:
Thaddeus Crews 2025-10-16 12:48:05 -05:00
commit 9e96c7d9b8
No known key found for this signature in database
GPG key ID: 8C6E5FEB5FC03CCC
23 changed files with 132 additions and 101 deletions

View file

@ -1688,6 +1688,19 @@ bool Object::_uses_signal_mutex() const {
return true; return true;
} }
String Object::_get_locale() const {
TranslationServer *ts = TranslationServer::get_singleton();
const StringName domain_name = get_translation_domain();
if (ts->has_domain(domain_name)) {
const Ref<TranslationDomain> domain = ts->get_or_add_domain(domain_name);
const String &overridden = domain->get_locale_override();
if (!overridden.is_empty()) {
return overridden;
}
}
return ts->get_locale();
}
void Object::_set_bind(const StringName &p_set, const Variant &p_value) { void Object::_set_bind(const StringName &p_set, const Variant &p_value) {
set(p_set, p_value); set(p_set, p_value);
} }

View file

@ -801,6 +801,9 @@ protected:
virtual bool _uses_signal_mutex() const; virtual bool _uses_signal_mutex() const;
// Internal helper to get the current locale, taking into account the translation domain.
String _get_locale() const;
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
struct VirtualMethodTracker { struct VirtualMethodTracker {
void **method; void **method;

View file

@ -455,6 +455,10 @@ void EditorNode::_update_from_settings() {
String current_fallback_locale = GLOBAL_GET("internationalization/locale/fallback"); String current_fallback_locale = GLOBAL_GET("internationalization/locale/fallback");
if (current_fallback_locale != TranslationServer::get_singleton()->get_fallback_locale()) { if (current_fallback_locale != TranslationServer::get_singleton()->get_fallback_locale()) {
TranslationServer::get_singleton()->set_fallback_locale(current_fallback_locale); TranslationServer::get_singleton()->set_fallback_locale(current_fallback_locale);
Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_main_domain();
if (!domain->is_enabled()) {
domain->set_locale_override(current_fallback_locale);
}
scene_root->propagate_notification(Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED); scene_root->propagate_notification(Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED);
} }
@ -4203,8 +4207,15 @@ void EditorNode::set_preview_locale(const String &p_locale) {
// Texts set in the editor could be identifiers that should never be translated. // Texts set in the editor could be identifiers that should never be translated.
// So we need to disable translation entirely. // So we need to disable translation entirely.
Ref<TranslationDomain> main_domain = TranslationServer::get_singleton()->get_main_domain(); Ref<TranslationDomain> main_domain = TranslationServer::get_singleton()->get_main_domain();
main_domain->set_enabled(!p_locale.is_empty()); if (p_locale.is_empty()) {
main_domain->set_locale_override(p_locale); // Disable preview. Use the fallback locale.
main_domain->set_enabled(false);
main_domain->set_locale_override(TranslationServer::get_singleton()->get_fallback_locale());
} else {
// Preview a specific locale.
main_domain->set_enabled(true);
main_domain->set_locale_override(p_locale);
}
_translation_resources_changed(); _translation_resources_changed();
} }
@ -7638,7 +7649,10 @@ EditorNode::EditorNode() {
ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &EditorNode::_update_from_settings)); 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)); GDExtensionManager::get_singleton()->connect("extensions_reloaded", callable_mp(this, &EditorNode::_gdextensions_reloaded));
TranslationServer::get_singleton()->get_main_domain()->set_enabled(false); Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_main_domain();
domain->set_enabled(false);
domain->set_locale_override(TranslationServer::get_singleton()->get_fallback_locale());
// Load settings. // Load settings.
if (!EditorSettings::get_singleton()) { if (!EditorSettings::get_singleton()) {
EditorSettings::create(); EditorSettings::create();

View file

@ -215,11 +215,8 @@ void Label3D::_notification(int p_what) {
window->disconnect("size_changed", callable_mp(this, &Label3D::_font_changed)); window->disconnect("size_changed", callable_mp(this, &Label3D::_font_changed));
} break; } break;
case NOTIFICATION_TRANSLATION_CHANGED: { case NOTIFICATION_TRANSLATION_CHANGED: {
String new_text = atr(text); // Language update might change the appearance of some characters.
if (new_text == xl_text) { xl_text = atr(text);
return; // Nothing new.
}
xl_text = new_text;
dirty_text = true; dirty_text = true;
_queue_update(); _queue_update();
} break; } break;
@ -483,8 +480,9 @@ void Label3D::_shape() {
TS->shaped_text_clear(text_rid); TS->shaped_text_clear(text_rid);
TS->shaped_text_set_direction(text_rid, text_direction); TS->shaped_text_set_direction(text_rid, text_direction);
String txt = (uppercase) ? TS->string_to_upper(xl_text, language) : xl_text; const String &lang = language.is_empty() ? _get_locale() : language;
TS->shaped_text_add_string(text_rid, txt, font->get_rids(), font_size, font->get_opentype_features(), language); String txt = uppercase ? TS->string_to_upper(xl_text, lang) : xl_text;
TS->shaped_text_add_string(text_rid, txt, font->get_rids(), font_size, font->get_opentype_features(), lang);
TypedArray<Vector3i> stt; TypedArray<Vector3i> stt;
if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) { if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) {

View file

@ -566,7 +566,8 @@ void Button::_shape(Ref<TextParagraph> p_paragraph, String p_text) const {
} else { } else {
p_paragraph->set_direction((TextServer::Direction)text_direction); p_paragraph->set_direction((TextServer::Direction)text_direction);
} }
p_paragraph->add_string(p_text, font, font_size, language); const String &lang = language.is_empty() ? _get_locale() : language;
p_paragraph->add_string(p_text, font, font_size, lang);
p_paragraph->set_text_overrun_behavior(overrun_behavior); p_paragraph->set_text_overrun_behavior(overrun_behavior);
} }

View file

@ -188,13 +188,14 @@ void CodeEdit::_notification(int p_what) {
code_completion_line_ofs = CLAMP((code_completion_force_item_center < 0 ? code_completion_current_selected : code_completion_force_item_center) - lines / 2, 0, code_completion_options_count - lines); code_completion_line_ofs = CLAMP((code_completion_force_item_center < 0 ? code_completion_current_selected : code_completion_force_item_center) - lines / 2, 0, code_completion_options_count - lines);
RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(code_completion_rect.position.x, code_completion_rect.position.y + (code_completion_current_selected - code_completion_line_ofs) * row_height), Size2(code_completion_rect.size.width, row_height)), theme_cache.code_completion_selected_color); RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(code_completion_rect.position.x, code_completion_rect.position.y + (code_completion_current_selected - code_completion_line_ofs) * row_height), Size2(code_completion_rect.size.width, row_height)), theme_cache.code_completion_selected_color);
const String &lang = _get_locale();
for (int i = 0; i < lines; i++) { for (int i = 0; i < lines; i++) {
int l = code_completion_line_ofs + i; int l = code_completion_line_ofs + i;
ERR_CONTINUE(l < 0 || l >= code_completion_options_count); ERR_CONTINUE(l < 0 || l >= code_completion_options_count);
Ref<TextLine> tl; Ref<TextLine> tl;
tl.instantiate(); tl.instantiate();
tl->add_string(code_completion_options[l].display, theme_cache.font, theme_cache.font_size); tl->add_string(code_completion_options[l].display, theme_cache.font, theme_cache.font_size, lang);
int yofs = (row_height - tl->get_size().y) / 2; int yofs = (row_height - tl->get_size().y) / 2;
Point2 title_pos(code_completion_rect.position.x, code_completion_rect.position.y + i * row_height + yofs); Point2 title_pos(code_completion_rect.position.x, code_completion_rect.position.y + i * row_height + yofs);
@ -1521,14 +1522,15 @@ void CodeEdit::_line_number_draw_callback(int p_line, int p_gutter, const Rect2
if (E) { if (E) {
text_rid = E->value; text_rid = E->value;
} else { } else {
const String &lang = _get_locale();
String fc = String::num_int64(p_line + 1).lpad(line_number_digits, line_number_padding); String fc = String::num_int64(p_line + 1).lpad(line_number_digits, line_number_padding);
if (is_localizing_numeral_system()) { if (is_localizing_numeral_system()) {
fc = TS->format_number(fc); fc = TS->format_number(fc, lang);
} }
text_rid = TS->create_shaped_text(); text_rid = TS->create_shaped_text();
if (theme_cache.font.is_valid()) { if (theme_cache.font.is_valid()) {
TS->shaped_text_add_string(text_rid, fc, theme_cache.font->get_rids(), theme_cache.font_size, theme_cache.font->get_opentype_features()); TS->shaped_text_add_string(text_rid, fc, theme_cache.font->get_rids(), theme_cache.font_size, theme_cache.font->get_opentype_features(), lang);
} }
line_number_text_cache.insert(p_line, text_rid); line_number_text_cache.insert(p_line, text_rid);
} }

View file

@ -36,7 +36,6 @@
#include "core/input/input_map.h" #include "core/input/input_map.h"
#include "core/os/os.h" #include "core/os/os.h"
#include "core/string/string_builder.h" #include "core/string/string_builder.h"
#include "core/string/translation_server.h"
#include "scene/gui/scroll_container.h" #include "scene/gui/scroll_container.h"
#include "scene/main/canvas_layer.h" #include "scene/main/canvas_layer.h"
#include "scene/main/window.h" #include "scene/main/window.h"
@ -3548,12 +3547,9 @@ bool Control::is_layout_rtl() const {
} else if (proj_root_layout_direction == 2) { } else if (proj_root_layout_direction == 2) {
data.is_rtl = true; data.is_rtl = true;
} else if (proj_root_layout_direction == 3) { } else if (proj_root_layout_direction == 3) {
String locale = OS::get_singleton()->get_locale(); data.is_rtl = TS->is_locale_right_to_left(OS::get_singleton()->get_locale());
data.is_rtl = TS->is_locale_right_to_left(locale);
} else { } else {
const Ref<Translation> &t = TranslationServer::get_singleton()->get_translation_object(TranslationServer::get_singleton()->get_locale()); data.is_rtl = TS->is_locale_right_to_left(_get_locale());
String locale = t.is_valid() ? t->get_locale() : TranslationServer::get_singleton()->get_fallback_locale();
data.is_rtl = TS->is_locale_right_to_left(locale);
} }
return data.is_rtl; return data.is_rtl;
} }
@ -3564,8 +3560,9 @@ bool Control::is_layout_rtl() const {
return data.is_rtl; return data.is_rtl;
} }
#endif // TOOLS_ENABLED #endif // TOOLS_ENABLED
const StringName domain_name = get_translation_domain();
Node *parent_node = get_parent(); Node *parent_node = get_parent();
while (parent_node) { while (parent_node && domain_name == parent_node->get_translation_domain()) {
Control *parent_control = Object::cast_to<Control>(parent_node); Control *parent_control = Object::cast_to<Control>(parent_node);
if (parent_control) { if (parent_control) {
data.is_rtl = parent_control->is_layout_rtl(); data.is_rtl = parent_control->is_layout_rtl();
@ -3588,22 +3585,19 @@ bool Control::is_layout_rtl() const {
String locale = OS::get_singleton()->get_locale(); String locale = OS::get_singleton()->get_locale();
data.is_rtl = TS->is_locale_right_to_left(locale); data.is_rtl = TS->is_locale_right_to_left(locale);
} else { } else {
String locale = TranslationServer::get_singleton()->get_tool_locale(); data.is_rtl = TS->is_locale_right_to_left(_get_locale());
data.is_rtl = TS->is_locale_right_to_left(locale);
} }
} else if (data.layout_dir == LAYOUT_DIRECTION_APPLICATION_LOCALE) { } else if (data.layout_dir == LAYOUT_DIRECTION_APPLICATION_LOCALE) {
if (GLOBAL_GET_CACHED(bool, "internationalization/rendering/force_right_to_left_layout_direction")) { if (GLOBAL_GET_CACHED(bool, "internationalization/rendering/force_right_to_left_layout_direction")) {
data.is_rtl = true; data.is_rtl = true;
} else { } else {
String locale = TranslationServer::get_singleton()->get_tool_locale(); data.is_rtl = TS->is_locale_right_to_left(_get_locale());
data.is_rtl = TS->is_locale_right_to_left(locale);
} }
} else if (data.layout_dir == LAYOUT_DIRECTION_SYSTEM_LOCALE) { } else if (data.layout_dir == LAYOUT_DIRECTION_SYSTEM_LOCALE) {
if (GLOBAL_GET_CACHED(bool, "internationalization/rendering/force_right_to_left_layout_direction")) { if (GLOBAL_GET_CACHED(bool, "internationalization/rendering/force_right_to_left_layout_direction")) {
const_cast<Control *>(this)->data.is_rtl = true; data.is_rtl = true;
} else { } else {
String locale = OS::get_singleton()->get_locale(); data.is_rtl = TS->is_locale_right_to_left(OS::get_singleton()->get_locale());
const_cast<Control *>(this)->data.is_rtl = TS->is_locale_right_to_left(locale);
} }
} else { } else {
data.is_rtl = (data.layout_dir == LAYOUT_DIRECTION_RTL); data.is_rtl = (data.layout_dir == LAYOUT_DIRECTION_RTL);

View file

@ -488,7 +488,8 @@ void FoldableContainer::_shape() {
} }
text_buf->set_horizontal_alignment(_get_actual_alignment()); text_buf->set_horizontal_alignment(_get_actual_alignment());
text_buf->set_text_overrun_behavior(overrun_behavior); text_buf->set_text_overrun_behavior(overrun_behavior);
text_buf->add_string(atr(title), font, font_size, language); const String &lang = language.is_empty() ? _get_locale() : language;
text_buf->add_string(atr(title), font, font_size, lang);
} }
HorizontalAlignment FoldableContainer::_get_actual_alignment() const { HorizontalAlignment FoldableContainer::_get_actual_alignment() const {

View file

@ -43,7 +43,8 @@ void ItemList::_shape_text(int p_idx) {
} else { } else {
item.text_buf->set_direction((TextServer::Direction)item.text_direction); item.text_buf->set_direction((TextServer::Direction)item.text_direction);
} }
item.text_buf->add_string(item.xl_text, theme_cache.font, theme_cache.font_size, item.language); const String &lang = item.language.is_empty() ? _get_locale() : item.language;
item.text_buf->add_string(item.xl_text, theme_cache.font, theme_cache.font_size, lang);
if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) { if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) {
item.text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_TRIM_START_EDGE_SPACES | TextServer::BREAK_TRIM_END_EDGE_SPACES); item.text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_TRIM_START_EDGE_SPACES | TextServer::BREAK_TRIM_END_EDGE_SPACES);
} else { } else {

View file

@ -136,6 +136,8 @@ int Label::get_line_height(int p_line) const {
} }
void Label::_shape() const { void Label::_shape() const {
const String &lang = language.is_empty() ? _get_locale() : language;
Ref<StyleBox> style = theme_cache.normal_style; Ref<StyleBox> style = theme_cache.normal_style;
int width = (get_size().width - style->get_minimum_size().width); int width = (get_size().width - style->get_minimum_size().width);
@ -149,7 +151,7 @@ void Label::_shape() const {
} }
paragraphs.clear(); paragraphs.clear();
String txt = (uppercase) ? TS->string_to_upper(xl_text, language) : xl_text; String txt = (uppercase) ? TS->string_to_upper(xl_text, lang) : xl_text;
if (visible_chars >= 0 && visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) { if (visible_chars >= 0 && visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) {
txt = txt.substr(0, visible_chars); txt = txt.substr(0, visible_chars);
} }
@ -183,7 +185,7 @@ void Label::_shape() const {
ERR_FAIL_COND(font.is_null()); ERR_FAIL_COND(font.is_null());
if (para.dirty) { if (para.dirty) {
TS->shaped_text_add_string(para.text_rid, para.text, font->get_rids(), font_size, font->get_opentype_features(), language); TS->shaped_text_add_string(para.text_rid, para.text, font->get_rids(), font_size, font->get_opentype_features(), lang);
} else { } else {
int spans = TS->shaped_get_span_count(para.text_rid); int spans = TS->shaped_get_span_count(para.text_rid);
for (int i = 0; i < spans; i++) { for (int i = 0; i < spans; i++) {
@ -709,15 +711,14 @@ void Label::_notification(int p_what) {
} break; } break;
case NOTIFICATION_TRANSLATION_CHANGED: { case NOTIFICATION_TRANSLATION_CHANGED: {
String new_text = atr(text); const String new_text = atr(text);
if (new_text == xl_text) { if (new_text != xl_text) {
return; // Nothing new. xl_text = new_text;
if (visible_ratio < 1) {
visible_chars = get_total_character_count() * visible_ratio;
}
} }
xl_text = new_text; text_dirty = true; // Language update might change the appearance of some characters.
if (visible_ratio < 1) {
visible_chars = get_total_character_count() * visible_ratio;
}
text_dirty = true;
queue_accessibility_update(); queue_accessibility_update();
queue_redraw(); queue_redraw();

View file

@ -1202,11 +1202,8 @@ void LineEdit::_notification(int p_what) {
DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_REPLACE_SELECTED_TEXT, callable_mp(this, &LineEdit::_accessibility_action_replace_selected)); DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_REPLACE_SELECTED_TEXT, callable_mp(this, &LineEdit::_accessibility_action_replace_selected));
DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_SET_VALUE, callable_mp(this, &LineEdit::_accessibility_action_set_value)); DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_SET_VALUE, callable_mp(this, &LineEdit::_accessibility_action_set_value));
DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_SHOW_CONTEXT_MENU, callable_mp(this, &LineEdit::_accessibility_action_menu)); DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_SHOW_CONTEXT_MENU, callable_mp(this, &LineEdit::_accessibility_action_menu));
if (!language.is_empty()) { const String &lang = language.is_empty() ? _get_locale() : language;
DisplayServer::get_singleton()->accessibility_update_set_language(ae, language); DisplayServer::get_singleton()->accessibility_update_set_language(ae, lang);
} else {
DisplayServer::get_singleton()->accessibility_update_set_language(ae, TranslationServer::get_singleton()->get_tool_locale());
}
bool rtl = is_layout_rtl(); bool rtl = is_layout_rtl();
Ref<StyleBox> style = theme_cache.normal; Ref<StyleBox> style = theme_cache.normal;
@ -2979,7 +2976,8 @@ void LineEdit::_shape() {
} }
TS->shaped_text_set_preserve_control(text_rid, draw_control_chars); TS->shaped_text_set_preserve_control(text_rid, draw_control_chars);
TS->shaped_text_add_string(text_rid, t, font->get_rids(), font_size, font->get_opentype_features(), language); const String &lang = language.is_empty() ? _get_locale() : language;
TS->shaped_text_add_string(text_rid, t, font->get_rids(), font_size, font->get_opentype_features(), lang);
TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, t)); TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, t));
full_width = TS->shaped_text_get_size(text_rid).x; full_width = TS->shaped_text_get_size(text_rid).x;

View file

@ -43,7 +43,8 @@ void LinkButton::_shape() {
text_buf->set_direction((TextServer::Direction)text_direction); text_buf->set_direction((TextServer::Direction)text_direction);
} }
TS->shaped_text_set_bidi_override(text_buf->get_rid(), structured_text_parser(st_parser, st_args, xl_text)); TS->shaped_text_set_bidi_override(text_buf->get_rid(), structured_text_parser(st_parser, st_args, xl_text));
text_buf->add_string(xl_text, font, font_size, language); const String &lang = language.is_empty() ? _get_locale() : language;
text_buf->add_string(xl_text, font, font_size, lang);
queue_accessibility_update(); queue_accessibility_update();
} }

View file

@ -517,7 +517,8 @@ void MenuBar::shape(Menu &p_menu) {
} else { } else {
p_menu.text_buf->set_direction((TextServer::Direction)text_direction); p_menu.text_buf->set_direction((TextServer::Direction)text_direction);
} }
p_menu.text_buf->add_string(atr(p_menu.name), theme_cache.font, theme_cache.font_size, language); const String &lang = language.is_empty() ? _get_locale() : language;
p_menu.text_buf->add_string(atr(p_menu.name), theme_cache.font, theme_cache.font_size, lang);
} }
void MenuBar::_refresh_menu_names() { void MenuBar::_refresh_menu_names() {

View file

@ -1018,11 +1018,12 @@ void PopupMenu::_shape_item(int p_idx) const {
} else { } else {
items.write[p_idx].text_buf->set_direction((TextServer::Direction)items[p_idx].text_direction); items.write[p_idx].text_buf->set_direction((TextServer::Direction)items[p_idx].text_direction);
} }
items.write[p_idx].text_buf->add_string(items.write[p_idx].xl_text, font, font_size, items[p_idx].language); const String &lang = items[p_idx].language.is_empty() ? _get_locale() : items[p_idx].language;
items.write[p_idx].text_buf->add_string(items.write[p_idx].xl_text, font, font_size, lang);
items.write[p_idx].accel_text_buf->clear(); items.write[p_idx].accel_text_buf->clear();
items.write[p_idx].accel_text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); items.write[p_idx].accel_text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
items.write[p_idx].accel_text_buf->add_string(_get_accel_text(items.write[p_idx]), font, font_size); items.write[p_idx].accel_text_buf->add_string(_get_accel_text(items.write[p_idx]), font, font_size, lang);
items.write[p_idx].dirty = false; items.write[p_idx].dirty = false;
} }
} }

View file

@ -167,7 +167,8 @@ void ProgressBar::_notification(int p_what) {
String txt = itos(int(ratio * 100)); String txt = itos(int(ratio * 100));
if (is_localizing_numeral_system()) { if (is_localizing_numeral_system()) {
txt = TS->format_number(txt) + TS->percent_sign(); const String &lang = _get_locale();
txt = TS->format_number(txt, lang) + TS->percent_sign(lang);
} else { } else {
txt += String("%"); txt += String("%");
} }

View file

@ -3461,21 +3461,20 @@ TextServer::StructuredTextParser RichTextLabel::_find_stt(Item *p_item) {
} }
String RichTextLabel::_find_language(Item *p_item) { String RichTextLabel::_find_language(Item *p_item) {
Item *item = p_item; String lang = language;
for (Item *item = p_item; item; item = item->parent) {
while (item) {
if (item->type == ITEM_LANGUAGE) { if (item->type == ITEM_LANGUAGE) {
ItemLanguage *p = static_cast<ItemLanguage *>(item); ItemLanguage *p = static_cast<ItemLanguage *>(item);
return p->language; lang = p->language;
} else if (item->type == ITEM_PARAGRAPH) { break;
ItemParagraph *p = static_cast<ItemParagraph *>(item); }
return p->language; if (item->type == ITEM_PARAGRAPH) {
ItemParagraph *p = static_cast<ItemParagraph *>(item);
lang = p->language;
break;
} }
item = item->parent;
} }
return lang.is_empty() ? _get_locale() : lang;
return language;
} }
Color RichTextLabel::_find_color(Item *p_item, const Color &p_default_color) { Color RichTextLabel::_find_color(Item *p_item, const Color &p_default_color) {

View file

@ -88,7 +88,7 @@ void SpinBox::_update_text(bool p_only_update_if_value_changed) {
double step = get_step(); double step = get_step();
String value = String::num(get_value(), Math::range_step_decimals(step)); String value = String::num(get_value(), Math::range_step_decimals(step));
if (is_localizing_numeral_system()) { if (is_localizing_numeral_system()) {
value = TS->format_number(value); value = TS->format_number(value, _get_locale());
} }
if (p_only_update_if_value_changed && value == last_text_value) { if (p_only_update_if_value_changed && value == last_text_value) {
@ -137,8 +137,9 @@ void SpinBox::_text_submitted(const String &p_string) {
Ref<Expression> expr; Ref<Expression> expr;
expr.instantiate(); expr.instantiate();
const String &lang = _get_locale();
text = text.replace_char(';', ','); text = text.replace_char(';', ',');
text = TS->parse_number(text); text = TS->parse_number(text, lang);
// Ignore the prefix and suffix in the expression. // Ignore the prefix and suffix in the expression.
text = text.trim_prefix(prefix + " ").trim_suffix(" " + suffix); text = text.trim_prefix(prefix + " ").trim_suffix(" " + suffix);
@ -147,7 +148,7 @@ void SpinBox::_text_submitted(const String &p_string) {
if (err != OK) { if (err != OK) {
// If the expression failed try without converting commas to dots - they might have been for parameter separation. // If the expression failed try without converting commas to dots - they might have been for parameter separation.
text = p_string; text = p_string;
text = TS->parse_number(text); text = TS->parse_number(text, lang);
text = text.trim_prefix(prefix + " ").trim_suffix(" " + suffix); text = text.trim_prefix(prefix + " ").trim_suffix(" " + suffix);
err = expr->parse(text); err = expr->parse(text);

View file

@ -363,7 +363,8 @@ void TabBar::_shape(int p_tab) {
tabs.write[p_tab].text_buf->set_direction((TextServer::Direction)tabs[p_tab].text_direction); tabs.write[p_tab].text_buf->set_direction((TextServer::Direction)tabs[p_tab].text_direction);
} }
tabs.write[p_tab].text_buf->add_string(atr(tabs[p_tab].text), theme_cache.font, theme_cache.font_size, tabs[p_tab].language); const String &lang = tabs[p_tab].language.is_empty() ? _get_locale() : tabs[p_tab].language;
tabs.write[p_tab].text_buf->add_string(atr(tabs[p_tab].text), theme_cache.font, theme_cache.font_size, lang);
} }
RID TabBar::get_tab_accessibility_element(int p_tab) const { RID TabBar::get_tab_accessibility_element(int p_tab) const {

View file

@ -39,7 +39,6 @@
#include "core/os/os.h" #include "core/os/os.h"
#include "core/string/alt_codes.h" #include "core/string/alt_codes.h"
#include "core/string/string_builder.h" #include "core/string/string_builder.h"
#include "core/string/translation_server.h"
#include "scene/gui/label.h" #include "scene/gui/label.h"
#include "scene/main/window.h" #include "scene/main/window.h"
#include "scene/theme/theme_db.h" #include "scene/theme/theme_db.h"
@ -863,7 +862,7 @@ void TextEdit::_notification(int p_what) {
case NOTIFICATION_TRANSLATION_CHANGED: case NOTIFICATION_TRANSLATION_CHANGED:
case NOTIFICATION_THEME_CHANGED: { case NOTIFICATION_THEME_CHANGED: {
if (is_inside_tree()) { if (is_inside_tree()) {
_update_caches(); _update_caches(p_what == NOTIFICATION_TRANSLATION_CHANGED);
_update_wrap_at_column(true); _update_wrap_at_column(true);
} }
} break; } break;
@ -1435,7 +1434,7 @@ void TextEdit::_notification(int p_what) {
Ref<TextLine> tl; Ref<TextLine> tl;
tl.instantiate(); tl.instantiate();
tl->add_string(txt, theme_cache.font, theme_cache.font_size); tl->add_string(txt, theme_cache.font, theme_cache.font_size, _get_locale());
int yofs = ofs_y + (row_height - tl->get_size().y) / 2; int yofs = ofs_y + (row_height - tl->get_size().y) / 2;
if (theme_cache.outline_size > 0 && theme_cache.outline_color.a > 0) { if (theme_cache.outline_size > 0 && theme_cache.outline_color.a > 0) {
@ -3356,7 +3355,8 @@ void TextEdit::_update_placeholder() {
placeholder_data_buf->set_direction((TextServer::Direction)text_direction); placeholder_data_buf->set_direction((TextServer::Direction)text_direction);
} }
placeholder_data_buf->set_preserve_control(draw_control_chars); placeholder_data_buf->set_preserve_control(draw_control_chars);
placeholder_data_buf->add_string(placeholder_translated, theme_cache.font, theme_cache.font_size, language); const String &lang = language.is_empty() ? _get_locale() : language;
placeholder_data_buf->add_string(placeholder_translated, theme_cache.font, theme_cache.font_size, lang);
placeholder_bidi_override = structured_text_parser(st_parser, st_args, placeholder_translated); placeholder_bidi_override = structured_text_parser(st_parser, st_args, placeholder_translated);
if (placeholder_bidi_override.is_empty()) { if (placeholder_bidi_override.is_empty()) {
@ -3402,7 +3402,7 @@ void TextEdit::_update_theme_item_cache() {
} }
} }
void TextEdit::_update_caches() { void TextEdit::_update_caches(bool p_invalidate_all) {
/* Text properties. */ /* Text properties. */
TextServer::Direction dir; TextServer::Direction dir;
if (text_direction == Control::TEXT_DIRECTION_INHERITED) { if (text_direction == Control::TEXT_DIRECTION_INHERITED) {
@ -3410,11 +3410,16 @@ void TextEdit::_update_caches() {
} else { } else {
dir = (TextServer::Direction)text_direction; dir = (TextServer::Direction)text_direction;
} }
text.set_direction_and_language(dir, (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale()); const String &lang = language.is_empty() ? _get_locale() : language;
text.set_direction_and_language(dir, lang);
text.set_draw_control_chars(draw_control_chars); text.set_draw_control_chars(draw_control_chars);
text.set_font(theme_cache.font); text.set_font(theme_cache.font);
text.set_font_size(theme_cache.font_size); text.set_font_size(theme_cache.font_size);
text.invalidate_font(); if (p_invalidate_all) {
text.invalidate_all();
} else {
text.invalidate_font();
}
_update_placeholder(); _update_placeholder();
/* Syntax highlighting. */ /* Syntax highlighting. */
@ -3741,8 +3746,9 @@ void TextEdit::set_text_direction(Control::TextDirection p_text_direction) {
} else { } else {
dir = (TextServer::Direction)text_direction; dir = (TextServer::Direction)text_direction;
} }
text.set_direction_and_language(dir, (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale()); const String &lang = language.is_empty() ? _get_locale() : language;
text.invalidate_font(); text.set_direction_and_language(dir, lang);
text.invalidate_all();
_update_placeholder(); _update_placeholder();
if (menu_dir) { if (menu_dir) {
@ -3769,7 +3775,8 @@ void TextEdit::set_language(const String &p_language) {
} else { } else {
dir = (TextServer::Direction)text_direction; dir = (TextServer::Direction)text_direction;
} }
text.set_direction_and_language(dir, (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale()); const String &lang = language.is_empty() ? _get_locale() : language;
text.set_direction_and_language(dir, lang);
text.invalidate_all(); text.invalidate_all();
_update_placeholder(); _update_placeholder();
queue_accessibility_update(); queue_accessibility_update();

View file

@ -333,7 +333,7 @@ private:
Array st_args; Array st_args;
void _clear(); void _clear();
void _update_caches(); void _update_caches(bool p_invalidate_all = false);
void _close_ime_window(); void _close_ime_window();
void _update_ime_window_position(); void _update_ime_window_position();

View file

@ -2131,7 +2131,8 @@ void Tree::update_column(int p_col) {
} }
columns.write[p_col].xl_title = atr(columns[p_col].title); columns.write[p_col].xl_title = atr(columns[p_col].title);
columns.write[p_col].text_buf->add_string(columns[p_col].xl_title, theme_cache.tb_font, theme_cache.tb_font_size, columns[p_col].language); const String &lang = columns[p_col].language.is_empty() ? _get_locale() : columns[p_col].language;
columns.write[p_col].text_buf->add_string(columns[p_col].xl_title, theme_cache.tb_font, theme_cache.tb_font_size, lang);
columns.write[p_col].cached_minimum_width_dirty = true; columns.write[p_col].cached_minimum_width_dirty = true;
} }
@ -2200,7 +2201,8 @@ void Tree::update_item_cell(TreeItem *p_item, int p_col) const {
} else { } else {
font_size = theme_cache.font_size; font_size = theme_cache.font_size;
} }
p_item->cells.write[p_col].text_buf->add_string(valtext, font, font_size, p_item->cells[p_col].language); const String &lang = p_item->cells[p_col].language.is_empty() ? _get_locale() : p_item->cells[p_col].language;
p_item->cells.write[p_col].text_buf->add_string(valtext, font, font_size, lang);
BitField<TextServer::LineBreakFlag> break_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_TRIM_START_EDGE_SPACES | TextServer::BREAK_TRIM_END_EDGE_SPACES; BitField<TextServer::LineBreakFlag> break_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_TRIM_START_EDGE_SPACES | TextServer::BREAK_TRIM_END_EDGE_SPACES;
switch (p_item->cells.write[p_col].autowrap_mode) { switch (p_item->cells.write[p_col].autowrap_mode) {

View file

@ -32,7 +32,6 @@
#include "core/config/project_settings.h" #include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h" #include "core/debugger/engine_debugger.h"
#include "core/string/translation_server.h"
#include "scene/gui/control.h" #include "scene/gui/control.h"
#include "scene/theme/theme_db.h" #include "scene/theme/theme_db.h"
#include "scene/theme/theme_owner.h" #include "scene/theme/theme_owner.h"
@ -2934,12 +2933,9 @@ bool Window::is_layout_rtl() const {
} else if (proj_root_layout_direction == 2) { } else if (proj_root_layout_direction == 2) {
return true; return true;
} else if (proj_root_layout_direction == 3) { } else if (proj_root_layout_direction == 3) {
String locale = OS::get_singleton()->get_locale(); return TS->is_locale_right_to_left(OS::get_singleton()->get_locale());
return TS->is_locale_right_to_left(locale);
} else { } else {
const Ref<Translation> &t = TranslationServer::get_singleton()->get_translation_object(TranslationServer::get_singleton()->get_locale()); return TS->is_locale_right_to_left(_get_locale());
String locale = t.is_valid() ? t->get_locale() : TranslationServer::get_singleton()->get_fallback_locale();
return TS->is_locale_right_to_left(locale);
} }
} }
} }
@ -2948,8 +2944,9 @@ bool Window::is_layout_rtl() const {
return true; return true;
} }
#endif #endif
const StringName domain_name = get_translation_domain();
Node *parent_node = get_parent(); Node *parent_node = get_parent();
while (parent_node) { while (parent_node && parent_node->get_translation_domain() == domain_name) {
Control *parent_control = Object::cast_to<Control>(parent_node); Control *parent_control = Object::cast_to<Control>(parent_node);
if (parent_control) { if (parent_control) {
return parent_control->is_layout_rtl(); return parent_control->is_layout_rtl();
@ -2967,25 +2964,21 @@ bool Window::is_layout_rtl() const {
} else if (root_layout_direction == 2) { } else if (root_layout_direction == 2) {
return true; return true;
} else if (root_layout_direction == 3) { } else if (root_layout_direction == 3) {
String locale = OS::get_singleton()->get_locale(); return TS->is_locale_right_to_left(OS::get_singleton()->get_locale());
return TS->is_locale_right_to_left(locale);
} else { } else {
String locale = TranslationServer::get_singleton()->get_tool_locale(); return TS->is_locale_right_to_left(_get_locale());
return TS->is_locale_right_to_left(locale);
} }
} else if (layout_dir == LAYOUT_DIRECTION_APPLICATION_LOCALE) { } else if (layout_dir == LAYOUT_DIRECTION_APPLICATION_LOCALE) {
if (GLOBAL_GET_CACHED(bool, "internationalization/rendering/force_right_to_left_layout_direction")) { if (GLOBAL_GET_CACHED(bool, "internationalization/rendering/force_right_to_left_layout_direction")) {
return true; return true;
} else { } else {
String locale = TranslationServer::get_singleton()->get_tool_locale(); return TS->is_locale_right_to_left(_get_locale());
return TS->is_locale_right_to_left(locale);
} }
} else if (layout_dir == LAYOUT_DIRECTION_SYSTEM_LOCALE) { } else if (layout_dir == LAYOUT_DIRECTION_SYSTEM_LOCALE) {
if (GLOBAL_GET_CACHED(bool, "internationalization/rendering/force_right_to_left_layout_direction")) { if (GLOBAL_GET_CACHED(bool, "internationalization/rendering/force_right_to_left_layout_direction")) {
return true; return true;
} else { } else {
String locale = OS::get_singleton()->get_locale(); return TS->is_locale_right_to_left(OS::get_singleton()->get_locale());
return TS->is_locale_right_to_left(locale);
} }
} else { } else {
return (layout_dir == LAYOUT_DIRECTION_RTL); return (layout_dir == LAYOUT_DIRECTION_RTL);

View file

@ -3227,8 +3227,9 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
TS->shaped_text_clear(text_rid); TS->shaped_text_clear(text_rid);
TS->shaped_text_set_direction(text_rid, text_direction); TS->shaped_text_set_direction(text_rid, text_direction);
String txt = (uppercase) ? TS->string_to_upper(xl_text, language) : xl_text; const String &lang = language.is_empty() ? _get_locale() : language;
TS->shaped_text_add_string(text_rid, txt, font->get_rids(), font_size, font->get_opentype_features(), language); String txt = (uppercase) ? TS->string_to_upper(xl_text, lang) : xl_text;
TS->shaped_text_add_string(text_rid, txt, font->get_rids(), font_size, font->get_opentype_features(), lang);
TypedArray<Vector3i> stt; TypedArray<Vector3i> stt;
if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) { if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) {
@ -3686,11 +3687,8 @@ void TextMesh::_bind_methods() {
void TextMesh::_notification(int p_what) { void TextMesh::_notification(int p_what) {
switch (p_what) { switch (p_what) {
case MainLoop::NOTIFICATION_TRANSLATION_CHANGED: { case MainLoop::NOTIFICATION_TRANSLATION_CHANGED: {
String new_text = tr(text); // Language update might change the appearance of some characters.
if (new_text == xl_text) { xl_text = tr(text);
return; // Nothing new.
}
xl_text = new_text;
dirty_text = true; dirty_text = true;
request_update(); request_update();
} break; } break;