Merge pull request #112092 from timothyqiu/ts-nums

Move localized number formatting methods to `TranslationServer`
This commit is contained in:
Thaddeus Crews 2025-11-10 17:47:09 -06:00
commit 8327dfa215
No known key found for this signature in database
GPG key ID: 8C6E5FEB5FC03CCC
27 changed files with 348 additions and 394 deletions

View file

@ -1232,3 +1232,32 @@ static const char *plural_rules[][2] = {
{ "cy", "nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n==3 ? 3 : n==6 ? 4 : 5);" },
{ nullptr, nullptr }
};
static const struct NumSystemData {
const char *locales;
const char32_t *digits;
const char32_t *percent_sign;
const char32_t *exp_l;
const char32_t *exp_u;
} num_system_data[] = {
// Eastern Arabic numerals.
{ "ar ar_AE ar_BH ar_DJ ar_EG ar_ER ar_IL ar_IQ ar_JO ar_KM ar_KW ar_LB ar_MR ar_OM ar_PS ar_QA ar_SA ar_SD ar_SO ar_SS ar_SY ar_TD ar_YE ckb ckb_IQ ckb_IR sd sd_PK sd_Arab sd_Arab_PK", U"٠١٢٣٤٥٦٧٨٩٫", U"٪", U"اس", U"اس" },
// Persian and Urdu numerals.
{ "fa fa_AF fa_IR ks ks_IN ks_Arab ks_Arab_IN lrc lrc_IQ lrc_IR mzn mzn_IR pa_PK pa_Arab pa_Arab_PK ps ps_AF ps_PK ur_IN uz_AF uz_Arab uz_Arab_AF", U"۰۱۲۳۴۵۶۷۸۹٫", U"٪", U"اس", U"اس" },
// Bengali numerals.
{ "as as_IN bn bn_BD bn_IN mni mni_IN mni_Beng mni_Beng_IN", U"০১২৩৪৫৬৭৮৯.", U"%", U"e", U"E" },
// Devanagari numerals.
{ "mr mr_IN ne ne_IN ne_NP sa sa_IN", U"०१२३४५६७८९.", U"%", U"e", U"E" },
// Dzongkha numerals.
{ "dz dz_BT", U"༠༡༢༣༤༥༦༧༨༩.", U"%", U"e", U"E" },
// Santali numerals.
{ "sat sat_IN sat_Olck sat_Olck_IN", U"᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙.", U"%", U"e", U"E" },
// Burmese numerals.
{ "my my_MM", U"၀၁၂၃၄၅၆၇၈၉.", U"%", U"e", U"E" },
// Chakma numerals.
{ "ccp ccp_BD ccp_IN", U"𑄶𑄷𑄸𑄹𑄺𑄻𑄼𑄽𑄾𑄿.", U"%", U"e", U"E" },
// Adlam numerals.
{ "ff ff_Adlm_BF ff_Adlm_CM ff_Adlm_GH ff_Adlm_GM ff_Adlm_GN ff_Adlm_GW ff_Adlm_LR ff_Adlm_MR ff_Adlm_NE ff_Adlm_NG ff_Adlm_SL ff_Adlm_SN", U"𞥐𞥑𞥒𞥓𞥔𞥕𞥖𞥗𞥘𞥙.", U"%", U"𞤉", U"𞤉" },
// End sentinel.
{ nullptr, nullptr, nullptr, nullptr, nullptr }
};

View file

@ -117,6 +117,26 @@ void TranslationServer::init_locale_info() {
}
idx++;
}
// Init number systems.
num_system_map.clear();
idx = 0;
while (num_system_data[idx].locales != nullptr) {
const NumSystemData &nsd = num_system_data[idx];
// These fields must not be empty.
DEV_ASSERT(nsd.percent_sign && nsd.percent_sign[0] != '\0');
DEV_ASSERT(nsd.digits && nsd.digits[0] != '\0');
DEV_ASSERT(nsd.exp_l && nsd.exp_l[0] != '\0');
DEV_ASSERT(nsd.exp_u && nsd.exp_u[0] != '\0');
DEV_ASSERT(strlen(nsd.digits) == 11);
const Vector<String> locales = String(nsd.locales).split(" ");
for (const String &l : locales) {
num_system_map[l] = idx;
}
idx++;
}
}
TranslationServer::Locale::operator String() const {
@ -219,6 +239,66 @@ TranslationServer::Locale::Locale(const TranslationServer &p_server, const Strin
}
}
String TranslationServer::format_number(const String &p_string, const String &p_locale) const {
ERR_FAIL_COND_V(p_locale.is_empty(), p_string);
if (!num_system_map.has(p_locale)) {
return p_string;
}
int index = num_system_map[p_locale];
const NumSystemData &nsd = num_system_data[index];
String res = p_string;
res = res.replace("e", nsd.exp_l);
res = res.replace("E", nsd.exp_u);
char32_t *data = res.ptrw();
for (int j = 0; j < res.length(); j++) {
if (data[j] >= 0x30 && data[j] <= 0x39) {
data[j] = nsd.digits[data[j] - 0x30];
} else if (data[j] == '.' || data[j] == ',') {
data[j] = nsd.digits[10];
}
}
return res;
}
String TranslationServer::parse_number(const String &p_string, const String &p_locale) const {
ERR_FAIL_COND_V(p_locale.is_empty(), p_string);
if (!num_system_map.has(p_locale)) {
return p_string;
}
int index = num_system_map[p_locale];
const NumSystemData &nsd = num_system_data[index];
String res = p_string;
res = res.replace(nsd.exp_l, "e");
res = res.replace(nsd.exp_u, "E");
char32_t *data = res.ptrw();
for (int j = 0; j < res.length(); j++) {
if (data[j] == nsd.digits[10]) {
data[j] = '.';
} else {
for (int k = 0; k < 10; k++) {
if (data[j] == nsd.digits[k]) {
data[j] = 0x30 + k;
}
}
}
}
return res;
}
String TranslationServer::get_percent_sign(const String &p_locale) const {
ERR_FAIL_COND_V(p_locale.is_empty(), "%");
if (!num_system_map.has(p_locale)) {
return "%";
}
int index = num_system_map[p_locale];
return num_system_data[index].percent_sign;
}
String TranslationServer::standardize_locale(const String &p_locale, bool p_add_defaults) const {
return Locale(*this, p_locale, p_add_defaults).operator String();
}
@ -604,6 +684,10 @@ void TranslationServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_loaded_locales"), &TranslationServer::get_loaded_locales);
ClassDB::bind_method(D_METHOD("format_number", "number", "locale"), &TranslationServer::format_number);
ClassDB::bind_method(D_METHOD("get_percent_sign", "locale"), &TranslationServer::get_percent_sign);
ClassDB::bind_method(D_METHOD("parse_number", "number", "locale"), &TranslationServer::parse_number);
ClassDB::bind_method(D_METHOD("is_pseudolocalization_enabled"), &TranslationServer::is_pseudolocalization_enabled);
ClassDB::bind_method(D_METHOD("set_pseudolocalization_enabled", "enabled"), &TranslationServer::set_pseudolocalization_enabled);
ClassDB::bind_method(D_METHOD("reload_pseudolocalization"), &TranslationServer::reload_pseudolocalization);

View file

@ -91,6 +91,7 @@ class TranslationServer : public Object {
static inline HashMap<String, String> country_rename_map;
static inline HashMap<String, String> variant_map;
static inline HashMap<String, String> plural_rules_map;
static inline HashMap<String, int> num_system_map;
void init_locale_info();
@ -137,6 +138,10 @@ public:
void set_pseudolocalization_enabled(bool p_enabled);
void reload_pseudolocalization();
String format_number(const String &p_string, const String &p_locale) const;
String parse_number(const String &p_string, const String &p_locale) const;
String get_percent_sign(const String &p_locale) const;
String standardize_locale(const String &p_locale, bool p_add_defaults = false) const;
int compare_locales(const String &p_locale_a, const String &p_locale_b) const;

View file

@ -1075,13 +1075,13 @@
Returns the dictionary of the supported OpenType variation coordinates.
</description>
</method>
<method name="format_number" qualifiers="const">
<method name="format_number" qualifiers="const" deprecated="Use [method TranslationServer.format_number] instead.">
<return type="String" />
<param index="0" name="number" type="String" />
<param index="1" name="language" type="String" default="&quot;&quot;" />
<description>
Converts a number from the Western Arabic (0..9) to the numeral systems used in [param language].
If [param language] is omitted, the active locale will be used.
Converts a number from Western Arabic (0..9) to the numeral system used in the given [param language].
If [param language] is an empty string, the active locale will be used.
</description>
</method>
<method name="free_rid">
@ -1197,12 +1197,13 @@
Converts readable feature, variation, script, or language name to OpenType tag.
</description>
</method>
<method name="parse_number" qualifiers="const">
<method name="parse_number" qualifiers="const" deprecated="Use [method TranslationServer.parse_number] instead.">
<return type="String" />
<param index="0" name="number" type="String" />
<param index="1" name="language" type="String" default="&quot;&quot;" />
<description>
Converts [param number] from the numeral systems used in [param language] to Western Arabic (0..9).
Converts [param number] from the numeral system used in the given [param language] to Western Arabic (0..9).
If [param language] is an empty string, the active locale will be used.
</description>
</method>
<method name="parse_structured_text" qualifiers="const">
@ -1214,11 +1215,12 @@
Default implementation of the BiDi algorithm override function.
</description>
</method>
<method name="percent_sign" qualifiers="const">
<method name="percent_sign" qualifiers="const" deprecated="Use [method TranslationServer.get_percent_sign] instead.">
<return type="String" />
<param index="0" name="language" type="String" default="&quot;&quot;" />
<description>
Returns percent sign used in the [param language].
Returns the percent sign used in the given [param language].
If [param language] is an empty string, the active locale will be used.
</description>
</method>
<method name="save_support_data" qualifiers="const">

View file

@ -1054,12 +1054,13 @@
Returns the dictionary of the supported OpenType variation coordinates.
</description>
</method>
<method name="_format_number" qualifiers="virtual const">
<method name="_format_number" qualifiers="virtual const" deprecated="Use [method TranslationServer.format_number] instead.">
<return type="String" />
<param index="0" name="number" type="String" />
<param index="1" name="language" type="String" />
<description>
Converts a number from the Western Arabic (0..9) to the numeral systems used in [param language].
Converts a number from Western Arabic (0..9) to the numeral system used in the given [param language].
If [param language] is an empty string, the active locale will be used.
</description>
</method>
<method name="_free_rid" qualifiers="virtual required">
@ -1163,12 +1164,13 @@
Converts readable feature, variation, script, or language name to OpenType tag.
</description>
</method>
<method name="_parse_number" qualifiers="virtual const">
<method name="_parse_number" qualifiers="virtual const" deprecated="Use [method TranslationServer.parse_number] instead.">
<return type="String" />
<param index="0" name="number" type="String" />
<param index="1" name="language" type="String" />
<description>
Converts [param number] from the numeral systems used in [param language] to Western Arabic (0..9).
Converts [param number] from the numeral system used in the given [param language] to Western Arabic (0..9).
If [param language] is an empty string, the active locale will be used.
</description>
</method>
<method name="_parse_structured_text" qualifiers="virtual const">
@ -1180,11 +1182,11 @@
Default implementation of the BiDi algorithm override function.
</description>
</method>
<method name="_percent_sign" qualifiers="virtual const">
<method name="_percent_sign" qualifiers="virtual const" deprecated="Use [method TranslationServer.get_percent_sign] instead.">
<return type="String" />
<param index="0" name="language" type="String" />
<description>
Returns percent sign used in the [param language].
Returns percent sign used in the given [param language].
</description>
</method>
<method name="_reference_oversampling_level" qualifiers="virtual">

View file

@ -33,6 +33,14 @@
Compares two locales and returns a similarity score between [code]0[/code] (no match) and [code]10[/code] (full match).
</description>
</method>
<method name="format_number" qualifiers="const">
<return type="String" />
<param index="0" name="number" type="String" />
<param index="1" name="locale" type="String" />
<description>
Converts a number from Western Arabic (0..9) to the numeral system used in the given [param locale].
</description>
</method>
<method name="get_all_countries" qualifiers="const">
<return type="PackedStringArray" />
<description>
@ -92,6 +100,13 @@
Returns the translation domain with the specified name. An empty translation domain will be created and added if it does not exist.
</description>
</method>
<method name="get_percent_sign" qualifiers="const">
<return type="String" />
<param index="0" name="locale" type="String" />
<description>
Returns the percent sign used in the given [param locale].
</description>
</method>
<method name="get_plural_rules" qualifiers="const">
<return type="String" />
<param index="0" name="locale" type="String" />
@ -127,6 +142,14 @@
Returns [code]true[/code] if a translation domain with the specified name exists.
</description>
</method>
<method name="parse_number" qualifiers="const">
<return type="String" />
<param index="0" name="number" type="String" />
<param index="1" name="locale" type="String" />
<description>
Converts [param number] from the numeral system used in the given [param locale] to Western Arabic (0..9).
</description>
</method>
<method name="pseudolocalize" qualifiers="const">
<return type="StringName" />
<param index="0" name="message" type="StringName" />

View file

@ -30,6 +30,7 @@
#include "animation_bezier_editor.h"
#include "core/string/translation_server.h"
#include "editor/animation/animation_player_editor_plugin.h"
#include "editor/editor_node.h"
#include "editor/editor_string_names.h"
@ -303,6 +304,8 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
const int h_separation = get_theme_constant(SNAME("h_separation"), SNAME("AnimationBezierTrackEdit"));
const int v_separation = get_theme_constant(SNAME("h_separation"), SNAME("AnimationBezierTrackEdit"));
const String &lang = _get_locale();
if (has_focus(true)) {
draw_rect(Rect2(Point2(), get_size()), focus_color, false, Math::round(EDSCALE));
}
@ -577,7 +580,9 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
draw_line(Point2(limit, i), Point2(right_limit, i), lc, Math::round(EDSCALE));
Color c = color;
c.a *= 0.5;
draw_string(font, Point2(limit + 8, i - 2), TS->format_number(rtos(Math::snapped((iv + 1) * scale, step))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, c);
const String &formatted = TranslationServer::get_singleton()->format_number(rtos(Math::snapped((iv + 1) * scale, step)), lang);
draw_string(font, Point2(limit + 8, i - 2), formatted, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, c);
}
first = false;
@ -716,8 +721,12 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
ep.point_rect.size = bezier_icon->get_size();
if (is_selected) {
draw_texture(selected_icon, ep.point_rect.position);
draw_string(font, ep.point_rect.position + Vector2(8, -font->get_height(font_size) - 8), TTR("Time:") + " " + TS->format_number(rtos(Math::snapped(offset, 0.0001))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent);
draw_string(font, ep.point_rect.position + Vector2(8, -8), TTR("Value:") + " " + TS->format_number(rtos(Math::snapped(value, 0.001))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent);
const String &formatted_offset = TranslationServer::get_singleton()->format_number(rtos(Math::snapped(offset, 0.0001)), lang);
draw_string(font, ep.point_rect.position + Vector2(8, -font->get_height(font_size) - 8), TTR("Time:") + " " + formatted_offset, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent);
const String &formatted_value = TranslationServer::get_singleton()->format_number(rtos(Math::snapped(value, 0.001)), lang);
draw_string(font, ep.point_rect.position + Vector2(8, -8), TTR("Value:") + " " + formatted_value, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent);
} else {
Color track_color = Color(1, 1, 1, 1);
if (i != selected_track) {

View file

@ -34,6 +34,7 @@
#include "core/config/project_settings.h"
#include "core/error/error_macros.h"
#include "core/input/input.h"
#include "core/string/translation_server.h"
#include "editor/animation/animation_bezier_editor.h"
#include "editor/animation/animation_player_editor_plugin.h"
#include "editor/docks/inspector_dock.h"
@ -2876,7 +2877,7 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
}
if (key_idx != -1) {
String text = TTR("Time (s):") + " " + TS->format_number(rtos(Math::snapped(animation->track_get_key_time(track, key_idx), SECOND_DECIMAL))) + "\n";
String text = TTR("Time (s):") + " " + TranslationServer::get_singleton()->format_number(rtos(Math::snapped(animation->track_get_key_time(track, key_idx), SECOND_DECIMAL)), _get_locale()) + "\n";
switch (animation->track_get_type(track)) {
case Animation::TYPE_POSITION_3D: {
Vector3 t = animation->track_get_key_value(track, key_idx);
@ -9011,7 +9012,7 @@ String AnimationMarkerEdit::get_tooltip(const Point2 &p_pos) const {
if (key_idx != -1) {
String name = names[key_idx];
String text = TTR("Time (s):") + " " + TS->format_number(rtos(Math::snapped(animation->get_marker_time(name), 0.0001))) + "\n";
String text = TTR("Time (s):") + " " + TranslationServer::get_singleton()->format_number(rtos(Math::snapped(animation->get_marker_time(name), 0.0001)), _get_locale()) + "\n";
text += TTR("Marker:") + " " + name + "\n";
return text;
}

View file

@ -30,6 +30,7 @@
#include "editor_performance_profiler.h"
#include "core/string/translation_server.h"
#include "editor/editor_string_names.h"
#include "editor/inspector/editor_property_name_processor.h"
#include "editor/settings/editor_settings.h"
@ -45,29 +46,6 @@ EditorPerformanceProfiler::Monitor::Monitor(const String &p_name, const String &
base = p_base;
}
void EditorPerformanceProfiler::Monitor::update_value(float p_value) {
ERR_FAIL_NULL(item);
String label = EditorPerformanceProfiler::_create_label(p_value, type);
String tooltip = label;
switch (type) {
case Performance::MONITOR_TYPE_MEMORY: {
tooltip = label;
} break;
case Performance::MONITOR_TYPE_TIME: {
tooltip = label;
} break;
default: {
tooltip += " " + item->get_text(0);
} break;
}
item->set_text(1, label);
item->set_tooltip_text(1, tooltip);
if (p_value > max) {
max = p_value;
}
}
void EditorPerformanceProfiler::Monitor::reset() {
history.clear();
max = 0.0f;
@ -77,26 +55,53 @@ void EditorPerformanceProfiler::Monitor::reset() {
}
}
String EditorPerformanceProfiler::_create_label(float p_value, Performance::MonitorType p_type) {
String EditorPerformanceProfiler::_format_label(float p_value, Performance::MonitorType p_type) const {
const String &lang = _get_locale();
const TranslationServer *ts = TranslationServer::get_singleton();
switch (p_type) {
case Performance::MONITOR_TYPE_QUANTITY: {
return TS->format_number(itos(p_value));
return ts->format_number(itos(p_value), lang);
}
case Performance::MONITOR_TYPE_MEMORY: {
return String::humanize_size(p_value);
}
case Performance::MONITOR_TYPE_TIME: {
return TS->format_number(rtos(p_value * 1000).pad_decimals(2)) + " " + TTR("ms");
return ts->format_number(rtos(p_value * 1000).pad_decimals(2), lang) + " " + TTR("ms");
}
case Performance::MONITOR_TYPE_PERCENTAGE: {
return TS->format_number(rtos(p_value * 100).pad_decimals(2)) + "%";
return ts->format_number(rtos(p_value * 100).pad_decimals(2), lang) + "%";
}
default: {
return TS->format_number(rtos(p_value));
return ts->format_number(rtos(p_value), lang);
}
}
}
void EditorPerformanceProfiler::_update_monitor_value(Monitor *p_monitor, float p_value) {
TreeItem *item = p_monitor->item;
ERR_FAIL_NULL(item);
const String label = EditorPerformanceProfiler::_format_label(p_value, p_monitor->type);
item->set_text(1, label);
String tooltip;
switch (p_monitor->type) {
case Performance::MONITOR_TYPE_MEMORY:
case Performance::MONITOR_TYPE_TIME: {
item->set_tooltip_text(1, label);
} break;
default: {
item->set_tooltip_text(1, label + " " + item->get_text(0));
} break;
}
if (p_value > p_monitor->max) {
p_monitor->max = p_value;
}
}
void EditorPerformanceProfiler::_monitor_select() {
monitor_draw->queue_redraw();
}
@ -159,12 +164,12 @@ void EditorPerformanceProfiler::_monitor_draw() {
Color horizontal_line_color;
horizontal_line_color.set_hsv(draw_color.get_h(), draw_color.get_s() * 0.5f, draw_color.get_v() * 0.5f, 0.3f);
monitor_draw->draw_line(rect.position, rect.position + Vector2(rect.size.width, 0), horizontal_line_color, Math::round(EDSCALE));
monitor_draw->draw_string(graph_font, rect.position + Vector2(0, graph_font->get_ascent(font_size)), _create_label(current.max, current.type), HORIZONTAL_ALIGNMENT_LEFT, rect.size.width, font_size, horizontal_line_color);
monitor_draw->draw_string(graph_font, rect.position + Vector2(0, graph_font->get_ascent(font_size)), _format_label(current.max, current.type), HORIZONTAL_ALIGNMENT_LEFT, rect.size.width, font_size, horizontal_line_color);
for (int j = 0; j < line_count; j++) {
Vector2 y_offset = Vector2(0, rect.size.height * (1.0f - float(j) / float(line_count)));
monitor_draw->draw_line(rect.position + y_offset, rect.position + Vector2(rect.size.width, 0) + y_offset, horizontal_line_color, Math::round(EDSCALE));
monitor_draw->draw_string(graph_font, rect.position - Vector2(0, graph_font->get_descent(font_size)) + y_offset, _create_label(current.max * float(j) / float(line_count), current.type), HORIZONTAL_ALIGNMENT_LEFT, rect.size.width, font_size, horizontal_line_color);
monitor_draw->draw_string(graph_font, rect.position - Vector2(0, graph_font->get_descent(font_size)) + y_offset, _format_label(current.max * float(j) / float(line_count), current.type), HORIZONTAL_ALIGNMENT_LEFT, rect.size.width, font_size, horizontal_line_color);
}
}
@ -189,7 +194,7 @@ void EditorPerformanceProfiler::_monitor_draw() {
line_color.set_hsv(draw_color.get_h(), draw_color.get_s() * 0.8f, draw_color.get_v(), 0.5f);
monitor_draw->draw_line(rect.position + Point2(from, 0), rect.position + Point2(from, rect.size.y), line_color, Math::round(EDSCALE));
String label = _create_label(e->get(), current.type);
String label = _format_label(e->get(), current.type);
Size2 size = graph_font->get_string_size(label, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size);
Vector2 text_top_left_position = Vector2(from, h2) - (size + Vector2(MARKER_MARGIN, MARKER_MARGIN));
if (text_top_left_position.x < 0) {
@ -225,7 +230,7 @@ void EditorPerformanceProfiler::_build_monitor_tree() {
item->set_checked(0, monitor_checked.has(E.key));
E.value.item = item;
if (!E.value.history.is_empty()) {
E.value.update_value(E.value.history.front()->get());
_update_monitor_value(&E.value, E.value.history.front()->get());
}
}
}
@ -366,7 +371,7 @@ void EditorPerformanceProfiler::add_profile_frame(const Vector<float> &p_values)
value = p_values[E.value.frame_index];
}
E.value.history.push_front(value);
E.value.update_value(value);
_update_monitor_value(&E.value, value);
}
marker_frame++;
monitor_draw->queue_redraw();

View file

@ -53,7 +53,6 @@ private:
Monitor() {}
Monitor(const String &p_name, const String &p_base, int p_frame_index, Performance::MonitorType p_type, TreeItem *p_item);
void update_value(float p_value);
void reset();
};
@ -69,7 +68,8 @@ private:
const int POINT_SEPARATION = 5;
const int MARKER_MARGIN = 2;
static String _create_label(float p_value, Performance::MonitorType p_type);
String _format_label(float p_value, Performance::MonitorType p_type) const;
void _update_monitor_value(Monitor *p_monitor, float p_value);
void _monitor_select();
void _monitor_draw();
void _build_monitor_tree();

View file

@ -31,6 +31,7 @@
#include "editor_profiler.h"
#include "core/io/image.h"
#include "core/string/translation_server.h"
#include "editor/editor_string_names.h"
#include "editor/run/editor_run_bar.h"
#include "editor/settings/editor_settings.h"
@ -116,29 +117,31 @@ void EditorProfiler::clear() {
emit_signal(SNAME("enable_profiling"), activate->is_pressed());
}
static String _get_percent_txt(float p_value, float p_total) {
if (p_total == 0) {
p_total = 0.00001;
}
return TS->format_number(String::num((p_value / p_total) * 100, 1)) + TS->percent_sign();
}
String EditorProfiler::_get_time_as_text(const Metric &m, float p_time, int p_calls) {
const int dmode = display_mode->get_selected();
const String &lang = _get_locale();
const TranslationServer *ts = TranslationServer::get_singleton();
if (dmode == DISPLAY_FRAME_TIME) {
return TS->format_number(rtos(p_time * 1000).pad_decimals(2)) + " " + TTR("ms");
} else if (dmode == DISPLAY_AVERAGE_TIME) {
if (p_calls == 0) {
return TS->format_number("0.00") + " " + TTR("ms");
} else {
return TS->format_number(rtos((p_time / p_calls) * 1000).pad_decimals(2)) + " " + TTR("ms");
}
} else if (dmode == DISPLAY_FRAME_PERCENT) {
return _get_percent_txt(p_time, m.frame_time);
} else if (dmode == DISPLAY_PHYSICS_FRAME_PERCENT) {
return _get_percent_txt(p_time, m.physics_frame_time);
switch (display_mode->get_selected()) {
case DISPLAY_FRAME_TIME: {
return ts->format_number(rtos(p_time * 1000).pad_decimals(2), lang) + " " + TTR("ms");
} break;
case DISPLAY_AVERAGE_TIME: {
if (p_calls == 0) {
return ts->format_number("0.00", lang) + " " + TTR("ms");
}
return ts->format_number(rtos((p_time / p_calls) * 1000).pad_decimals(2), lang) + " " + TTR("ms");
} break;
case DISPLAY_FRAME_PERCENT: {
float total = m.frame_time == 0 ? 0.00001 : m.frame_time;
return ts->format_number(String::num((p_time / total) * 100, 1), lang) + ts->get_percent_sign(lang);
} break;
case DISPLAY_PHYSICS_FRAME_PERCENT: {
float total = m.physics_frame_time == 0 ? 0.00001 : m.physics_frame_time;
return ts->format_number(String::num((p_time / total) * 100, 1), lang) + ts->get_percent_sign(lang);
} break;
}
return "err";

View file

@ -31,6 +31,7 @@
#include "editor_visual_profiler.h"
#include "core/io/image.h"
#include "core/string/translation_server.h"
#include "editor/editor_string_names.h"
#include "editor/run/editor_run_bar.h"
#include "editor/settings/editor_settings.h"
@ -123,12 +124,14 @@ void EditorVisualProfiler::clear() {
}
String EditorVisualProfiler::_get_time_as_text(float p_time) {
const String &lang = _get_locale();
int dmode = display_mode->get_selected();
if (dmode == DISPLAY_FRAME_TIME) {
return TS->format_number(String::num(p_time, 2)) + " " + TTR("ms");
return TranslationServer::get_singleton()->format_number(String::num(p_time, 2), lang) + " " + TTR("ms");
} else if (dmode == DISPLAY_FRAME_PERCENT) {
return TS->format_number(String::num(p_time * 100 / graph_limit, 2)) + " " + TS->percent_sign();
return TranslationServer::get_singleton()->format_number(String::num(p_time * 100 / graph_limit, 2), lang) + " " + TranslationServer::get_singleton()->get_percent_sign(lang);
}
return "err";

View file

@ -33,6 +33,7 @@
#include "core/input/input.h"
#include "core/math/expression.h"
#include "core/os/keyboard.h"
#include "core/string/translation_server.h"
#include "editor/settings/editor_settings.h"
#include "editor/themes/editor_scale.h"
#include "scene/theme/theme_db.h"
@ -51,9 +52,7 @@ String EditorSpinSlider::get_tooltip(const Point2 &p_pos) const {
}
String EditorSpinSlider::get_text_value() const {
return TS->format_number(editing_integer
? itos(get_value())
: String::num(get_value(), Math::range_step_decimals(get_step())));
return TranslationServer::get_singleton()->format_number(editing_integer ? itos(get_value()) : String::num(get_value(), Math::range_step_decimals(get_step())), _get_locale());
}
void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
@ -582,19 +581,21 @@ String EditorSpinSlider::get_suffix() const {
}
void EditorSpinSlider::_evaluate_input_text() {
const String &lang = _get_locale();
Ref<Expression> expr;
expr.instantiate();
// Convert commas ',' to dots '.' for French/German etc. keyboard layouts.
String text = value_input->get_text().replace_char(',', '.');
text = text.replace_char(';', ',');
text = TS->parse_number(text);
text = TranslationServer::get_singleton()->parse_number(text, lang);
Error err = expr->parse(text);
if (err != OK) {
// If the expression failed try without converting commas to dots - they might have been for parameter separation.
text = value_input->get_text();
text = TS->parse_number(text);
text = TranslationServer::get_singleton()->parse_number(text, lang);
err = expr->parse(text);
if (err != OK) {

View file

@ -31,22 +31,25 @@
#include "editor_zoom_widget.h"
#include "core/os/keyboard.h"
#include "core/string/translation_server.h"
#include "editor/settings/editor_settings.h"
#include "editor/themes/editor_scale.h"
void EditorZoomWidget::_update_zoom_label() {
const String &lang = _get_locale();
String zoom_text;
// The zoom level displayed is relative to the editor scale
// (like in most image editors). Its lower bound is clamped to 1 as some people
// lower the editor scale to increase the available real estate,
// even if their display doesn't have a particularly low DPI.
if (zoom >= 10) {
zoom_text = TS->format_number(rtos(Math::round((zoom / MAX(1, EDSCALE)) * 100)));
zoom_text = TranslationServer::get_singleton()->format_number(rtos(Math::round((zoom / MAX(1, EDSCALE)) * 100)), lang);
} else {
// 2 decimal places if the zoom is below 10%, 1 decimal place if it's below 1000%.
zoom_text = TS->format_number(rtos(Math::snapped((zoom / MAX(1, EDSCALE)) * 100, (zoom >= 0.1) ? 0.1 : 0.01)));
zoom_text = TranslationServer::get_singleton()->format_number(rtos(Math::snapped((zoom / MAX(1, EDSCALE)) * 100, (zoom >= 0.1) ? 0.1 : 0.01)), lang);
}
zoom_text += " " + TS->percent_sign();
zoom_text += " " + TranslationServer::get_singleton()->get_percent_sign(lang);
zoom_reset->set_text(zoom_text);
}

View file

@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/input/input_map.h"
#include "core/string/translation_server.h"
#include "editor/docks/inspector_dock.h"
#include "editor/docks/scene_tree_dock.h"
#include "editor/editor_node.h"
@ -1749,7 +1750,9 @@ void EditorPropertyEasing::_draw_easing() {
} else {
decimals = 1;
}
f->draw_string(ci, Point2(10, 10 + f->get_ascent(font_size)), TS->format_number(rtos(exp).pad_decimals(decimals)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
const String &formatted = TranslationServer::get_singleton()->format_number(rtos(exp).pad_decimals(decimals), _get_locale());
f->draw_string(ci, Point2(10, 10 + f->get_ascent(font_size)), formatted, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
}
void EditorPropertyEasing::update_property() {
@ -1767,7 +1770,7 @@ void EditorPropertyEasing::_set_preset(int p_preset) {
void EditorPropertyEasing::_setup_spin() {
spin->setup_and_show();
spin->get_line_edit()->set_text(TS->format_number(rtos(get_edited_property_value())));
spin->get_line_edit()->set_text(TranslationServer::get_singleton()->format_number(rtos(get_edited_property_value()), _get_locale()));
spin->show();
}

View file

@ -36,6 +36,7 @@
#include "core/math/math_funcs.h"
#include "core/math/projection.h"
#include "core/os/keyboard.h"
#include "core/string/translation_server.h"
#include "editor/animation/animation_player_editor_plugin.h"
#include "editor/debugger/editor_debugger_node.h"
#include "editor/docks/scene_tree_dock.h"
@ -3230,7 +3231,7 @@ void Node3DEditorViewport::_notification(int p_what) {
geometry->surface_end();
float distance = start_pos.distance_to(end_pos);
ruler_label->set_text(TS->format_number(vformat("%.3f m", distance)));
ruler_label->set_text(TranslationServer::get_singleton()->format_number(vformat("%.3f m", distance), _get_locale()));
Vector3 center = (start_pos + end_pos) / 2;
Vector2 screen_position = camera->unproject_position(center) - (ruler_label->get_custom_minimum_size() / 2);

View file

@ -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/animation/animation_player_editor_plugin.h"
#include "editor/debugger/editor_debugger_node.h"
#include "editor/docks/scene_tree_dock.h"
@ -3083,14 +3084,15 @@ void CanvasItemEditor::_draw_text_at_position(Point2 p_position, const String &p
}
void CanvasItemEditor::_draw_margin_at_position(int p_value, Point2 p_position, Side p_side) {
String str = TS->format_number(vformat("%d " + TTR("px"), p_value));
String str = TranslationServer::get_singleton()->format_number(vformat("%d " + TTR("px"), p_value), _get_locale());
if (p_value != 0) {
_draw_text_at_position(p_position, str, p_side);
}
}
void CanvasItemEditor::_draw_percentage_at_position(real_t p_value, Point2 p_position, Side p_side) {
String str = TS->format_number(vformat("%.1f ", p_value * 100.0)) + TS->percent_sign();
const String &lang = _get_locale();
String str = TranslationServer::get_singleton()->format_number(vformat("%.1f ", p_value * 100.0), lang) + TranslationServer::get_singleton()->get_percent_sign(lang);
if (p_value != 0) {
_draw_text_at_position(p_position, str, p_side);
}
@ -3132,8 +3134,9 @@ void CanvasItemEditor::_draw_guides() {
Color text_color = get_theme_color(SceneStringName(font_color), EditorStringName(Editor));
Color outline_color = text_color.inverted();
const float outline_size = 2;
const String &lang = _get_locale();
if (drag_type == DRAG_DOUBLE_GUIDE || drag_type == DRAG_V_GUIDE) {
String str = TS->format_number(vformat("%d px", Math::round(xform.affine_inverse().xform(dragged_guide_pos).x)));
String str = TranslationServer::get_singleton()->format_number(vformat("%d px", Math::round(xform.affine_inverse().xform(dragged_guide_pos).x)), lang);
Ref<Font> font = get_theme_font(SNAME("bold"), EditorStringName(EditorFonts));
int font_size = 1.3 * get_theme_font_size(SNAME("bold_size"), EditorStringName(EditorFonts));
Size2 text_size = font->get_string_size(str, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size);
@ -3142,7 +3145,7 @@ void CanvasItemEditor::_draw_guides() {
viewport->draw_line(Point2(dragged_guide_pos.x, 0), Point2(dragged_guide_pos.x, viewport->get_size().y), guide_color, Math::round(EDSCALE));
}
if (drag_type == DRAG_DOUBLE_GUIDE || drag_type == DRAG_H_GUIDE) {
String str = TS->format_number(vformat("%d px", Math::round(xform.affine_inverse().xform(dragged_guide_pos).y)));
String str = TranslationServer::get_singleton()->format_number(vformat("%d px", Math::round(xform.affine_inverse().xform(dragged_guide_pos).y)), lang);
Ref<Font> font = get_theme_font(SNAME("bold"), EditorStringName(EditorFonts));
int font_size = 1.3 * get_theme_font_size(SNAME("bold_size"), EditorStringName(EditorFonts));
Size2 text_size = font->get_string_size(str, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size);
@ -3173,6 +3176,7 @@ void CanvasItemEditor::_draw_rulers() {
font_color.a = 0.8;
Ref<Font> font = get_theme_font(SNAME("rulers"), EditorStringName(EditorFonts));
real_t ruler_tick_scale = ruler_width_scaled / 15.0;
const String lang = _get_locale();
// The rule transform
Transform2D ruler_transform;
@ -3219,7 +3223,8 @@ void CanvasItemEditor::_draw_rulers() {
if (i % (major_subdivision * minor_subdivision) == 0) {
viewport->draw_line(Point2(position.x, 0), Point2(position.x, ruler_width_scaled), graduation_color, Math::round(EDSCALE));
real_t val = (ruler_transform * major_subdivide * minor_subdivide).xform(Point2(i, 0)).x;
viewport->draw_string(font, Point2(position.x + MAX(Math::round(ruler_font_size / 8.0), 2), font->get_ascent(ruler_font_size) + Math::round(EDSCALE)), TS->format_number(vformat(((int)val == val) ? "%d" : "%.1f", val)), HORIZONTAL_ALIGNMENT_LEFT, -1, ruler_font_size, font_color);
const String &formatted = TranslationServer::get_singleton()->format_number(vformat(((int)val == val) ? "%d" : "%.1f", val), lang);
viewport->draw_string(font, Point2(position.x + MAX(Math::round(ruler_font_size / 8.0), 2), font->get_ascent(ruler_font_size) + Math::round(EDSCALE)), formatted, HORIZONTAL_ALIGNMENT_LEFT, -1, ruler_font_size, font_color);
} else {
if (i % minor_subdivision == 0) {
viewport->draw_line(Point2(position.x, ruler_width_scaled * 0.33), Point2(position.x, ruler_width_scaled), graduation_color, Math::round(EDSCALE));
@ -3239,7 +3244,8 @@ void CanvasItemEditor::_draw_rulers() {
Transform2D text_xform = Transform2D(-Math::PI / 2.0, Point2(font->get_ascent(ruler_font_size) + Math::round(EDSCALE), position.y - 2));
viewport->draw_set_transform_matrix(viewport->get_transform() * text_xform);
viewport->draw_string(font, Point2(), TS->format_number(vformat(((int)val == val) ? "%d" : "%.1f", val)), HORIZONTAL_ALIGNMENT_LEFT, -1, ruler_font_size, font_color);
const String &formatted = TranslationServer::get_singleton()->format_number(vformat(((int)val == val) ? "%d" : "%.1f", val), lang);
viewport->draw_string(font, Point2(), formatted, HORIZONTAL_ALIGNMENT_LEFT, -1, ruler_font_size, font_color);
viewport->draw_set_transform_matrix(viewport->get_transform());
} else {
@ -3334,6 +3340,9 @@ void CanvasItemEditor::_draw_ruler_tool() {
const Ref<Texture2D> position_icon = get_editor_theme_icon(SNAME("EditorPosition"));
if (ruler_tool_active) {
const String &lang = _get_locale();
const TranslationServer *ts = TranslationServer::get_singleton();
Color ruler_primary_color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));
Color ruler_secondary_color = ruler_primary_color;
ruler_secondary_color.a = 0.5;
@ -3405,8 +3414,8 @@ void CanvasItemEditor::_draw_ruler_tool() {
return;
}
viewport->draw_string_outline(font, text_pos, TS->format_number(vformat("%.1f px", length_vector.length())), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, text_pos, TS->format_number(vformat("%.1f px", length_vector.length())), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
viewport->draw_string_outline(font, text_pos, ts->format_number(vformat("%.1f px", length_vector.length()), lang), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, text_pos, ts->format_number(vformat("%.1f px", length_vector.length()), lang), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
if (draw_secondary_lines) {
const int horizontal_angle = std::round(180 * horizontal_angle_rad / Math::PI);
@ -3414,19 +3423,19 @@ void CanvasItemEditor::_draw_ruler_tool() {
Point2 text_pos2 = text_pos;
text_pos2.x = begin.x < text_pos.x ? MIN(text_pos.x - text_width, begin.x - text_width / 2) : MAX(text_pos.x + text_width, begin.x - text_width / 2);
viewport->draw_string_outline(font, text_pos2, TS->format_number(vformat("%.1f px", length_vector.y)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, text_pos2, TS->format_number(vformat("%.1f px", length_vector.y)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color);
viewport->draw_string_outline(font, text_pos2, ts->format_number(vformat("%.1f px", length_vector.y), lang), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, text_pos2, ts->format_number(vformat("%.1f px", length_vector.y), lang), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color);
Point2 v_angle_text_pos;
v_angle_text_pos.x = CLAMP(begin.x - angle_text_width / 2, angle_text_width / 2, viewport->get_rect().size.x - angle_text_width);
v_angle_text_pos.y = begin.y < end.y ? MIN(text_pos2.y - 2 * text_height, begin.y - text_height * 0.5) : MAX(text_pos2.y + text_height * 3, begin.y + text_height * 1.5);
viewport->draw_string_outline(font, v_angle_text_pos, TS->format_number(vformat(U"%d°", vertical_angle)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, v_angle_text_pos, TS->format_number(vformat(U"%d°", vertical_angle)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color);
viewport->draw_string_outline(font, v_angle_text_pos, ts->format_number(vformat(U"%d°", vertical_angle), lang), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, v_angle_text_pos, ts->format_number(vformat(U"%d°", vertical_angle), lang), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color);
text_pos2 = text_pos;
text_pos2.y = end.y < text_pos.y ? MIN(text_pos.y - text_height * 2, end.y - text_height / 2) : MAX(text_pos.y + text_height * 2, end.y - text_height / 2);
viewport->draw_string_outline(font, text_pos2, TS->format_number(vformat("%.1f px", length_vector.x)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, text_pos2, TS->format_number(vformat("%.1f px", length_vector.x)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color);
viewport->draw_string_outline(font, text_pos2, ts->format_number(vformat("%.1f px", length_vector.x), lang), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, text_pos2, ts->format_number(vformat("%.1f px", length_vector.x), lang), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color);
Point2 h_angle_text_pos;
h_angle_text_pos.x = CLAMP(end.x - angle_text_width / 2, angle_text_width / 2, viewport->get_rect().size.x - angle_text_width);
@ -3443,8 +3452,8 @@ void CanvasItemEditor::_draw_ruler_tool() {
h_angle_text_pos.y = MIN(text_pos.y - height_multiplier * text_height, MIN(end.y - text_height * 0.5, text_pos2.y - height_multiplier * text_height));
}
}
viewport->draw_string_outline(font, h_angle_text_pos, TS->format_number(vformat(U"%d°", horizontal_angle)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, h_angle_text_pos, TS->format_number(vformat(U"%d°", horizontal_angle)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color);
viewport->draw_string_outline(font, h_angle_text_pos, ts->format_number(vformat(U"%d°", horizontal_angle), lang), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, h_angle_text_pos, ts->format_number(vformat(U"%d°", horizontal_angle), lang), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color);
}
if (grid_snap_active) {
@ -3453,21 +3462,21 @@ void CanvasItemEditor::_draw_ruler_tool() {
text_pos.y = CLAMP(text_pos.y, text_height * 2.5, viewport->get_rect().size.y - text_height / 2);
if (draw_secondary_lines) {
viewport->draw_string_outline(font, text_pos, TS->format_number(vformat("%.2f " + TTR("units"), (length_vector / grid_step).length())), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, text_pos, TS->format_number(vformat("%.2f " + TTR("units"), (length_vector / grid_step).length())), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
viewport->draw_string_outline(font, text_pos, ts->format_number(vformat("%.2f " + TTR("units"), (length_vector / grid_step).length()), lang), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, text_pos, ts->format_number(vformat("%.2f " + TTR("units"), (length_vector / grid_step).length()), lang), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
Point2 text_pos2 = text_pos;
text_pos2.x = begin.x < text_pos.x ? MIN(text_pos.x - text_width, begin.x - text_width / 2) : MAX(text_pos.x + text_width, begin.x - text_width / 2);
viewport->draw_string_outline(font, text_pos2, TS->format_number(vformat("%d " + TTR("units"), std::round(length_vector.y / grid_step.y))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, text_pos2, TS->format_number(vformat("%d " + TTR("units"), std::round(length_vector.y / grid_step.y))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color);
viewport->draw_string_outline(font, text_pos2, ts->format_number(vformat("%d " + TTR("units"), std::round(length_vector.y / grid_step.y)), lang), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, text_pos2, ts->format_number(vformat("%d " + TTR("units"), std::round(length_vector.y / grid_step.y)), lang), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color);
text_pos2 = text_pos;
text_pos2.y = end.y < text_pos.y ? MIN(text_pos.y - text_height * 2, end.y + text_height / 2) : MAX(text_pos.y + text_height * 2, end.y + text_height / 2);
viewport->draw_string_outline(font, text_pos2, TS->format_number(vformat("%d " + TTR("units"), std::round(length_vector.x / grid_step.x))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, text_pos2, TS->format_number(vformat("%d " + TTR("units"), std::round(length_vector.x / grid_step.x))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color);
viewport->draw_string_outline(font, text_pos2, ts->format_number(vformat("%d " + TTR("units"), std::round(length_vector.x / grid_step.x)), lang), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, text_pos2, ts->format_number(vformat("%d " + TTR("units"), std::round(length_vector.x / grid_step.x)), lang), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color);
} else {
viewport->draw_string_outline(font, text_pos, TS->format_number(vformat("%d " + TTR("units"), std::round((length_vector / grid_step).length()))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, text_pos, TS->format_number(vformat("%d " + TTR("units"), std::round((length_vector / grid_step).length()))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
viewport->draw_string_outline(font, text_pos, ts->format_number(vformat("%d " + TTR("units"), std::round((length_vector / grid_step).length())), lang), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, text_pos, ts->format_number(vformat("%d " + TTR("units"), std::round((length_vector / grid_step).length())), lang), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
}
}
} else {
@ -4065,7 +4074,8 @@ void CanvasItemEditor::_draw_message() {
double snap = EDITOR_GET("interface/inspector/default_float_step");
int snap_step_decimals = Math::range_step_decimals(snap);
#define FORMAT(value) (TS->format_number(String::num(value, snap_step_decimals)))
const String &lang = _get_locale();
#define FORMAT(value) (TranslationServer::get_singleton()->format_number(String::num(value, snap_step_decimals), lang))
switch (drag_type) {
case DRAG_MOVE:
@ -6395,7 +6405,8 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian
} else {
double snap = EDITOR_GET("interface/inspector/default_float_step");
int snap_step_decimals = Math::range_step_decimals(snap);
#define FORMAT(value) (TS->format_number(String::num(value, snap_step_decimals)))
const String &lang = _get_locale();
#define FORMAT(value) (TranslationServer::get_singleton()->format_number(String::num(value, snap_step_decimals), lang))
Vector2 preview_node_pos = preview_node->get_global_position();
canvas_item_editor->message = TTR("Instantiating: ") + "(" + FORMAT(preview_node_pos.x) + ", " + FORMAT(preview_node_pos.y) + ") px";
}

View file

@ -7509,258 +7509,6 @@ double TextServerAdvanced::_shaped_text_get_underline_thickness(const RID &p_sha
return sd->uthk;
}
void TextServerAdvanced::_insert_num_systems_lang() {
// Eastern Arabic numerals.
{
NumSystemData ar;
ar.lang.insert(StringName("ar")); // Arabic
ar.lang.insert(StringName("ar_AE"));
ar.lang.insert(StringName("ar_BH"));
ar.lang.insert(StringName("ar_DJ"));
ar.lang.insert(StringName("ar_EG"));
ar.lang.insert(StringName("ar_ER"));
ar.lang.insert(StringName("ar_IL"));
ar.lang.insert(StringName("ar_IQ"));
ar.lang.insert(StringName("ar_JO"));
ar.lang.insert(StringName("ar_KM"));
ar.lang.insert(StringName("ar_KW"));
ar.lang.insert(StringName("ar_LB"));
ar.lang.insert(StringName("ar_MR"));
ar.lang.insert(StringName("ar_OM"));
ar.lang.insert(StringName("ar_PS"));
ar.lang.insert(StringName("ar_QA"));
ar.lang.insert(StringName("ar_SA"));
ar.lang.insert(StringName("ar_SD"));
ar.lang.insert(StringName("ar_SO"));
ar.lang.insert(StringName("ar_SS"));
ar.lang.insert(StringName("ar_SY"));
ar.lang.insert(StringName("ar_TD"));
ar.lang.insert(StringName("ar_YE"));
ar.lang.insert(StringName("ckb")); // Central Kurdish
ar.lang.insert(StringName("ckb_IQ"));
ar.lang.insert(StringName("ckb_IR"));
ar.lang.insert(StringName("sd")); // Sindhi
ar.lang.insert(StringName("sd_PK"));
ar.lang.insert(StringName("sd_Arab"));
ar.lang.insert(StringName("sd_Arab_PK"));
ar.digits = U"٠١٢٣٤٥٦٧٨٩٫";
ar.percent_sign = U"٪";
ar.exp_l = U"اس";
ar.exp_u = U"اس";
num_systems.push_back(ar);
}
// Persian and Urdu numerals.
{
NumSystemData pr;
pr.lang.insert(StringName("fa")); // Persian
pr.lang.insert(StringName("fa_AF"));
pr.lang.insert(StringName("fa_IR"));
pr.lang.insert(StringName("ks")); // Kashmiri
pr.lang.insert(StringName("ks_IN"));
pr.lang.insert(StringName("ks_Arab"));
pr.lang.insert(StringName("ks_Arab_IN"));
pr.lang.insert(StringName("lrc")); // Northern Luri
pr.lang.insert(StringName("lrc_IQ"));
pr.lang.insert(StringName("lrc_IR"));
pr.lang.insert(StringName("mzn")); // Mazanderani
pr.lang.insert(StringName("mzn_IR"));
pr.lang.insert(StringName("pa_PK")); // Panjabi
pr.lang.insert(StringName("pa_Arab"));
pr.lang.insert(StringName("pa_Arab_PK"));
pr.lang.insert(StringName("ps")); // Pushto
pr.lang.insert(StringName("ps_AF"));
pr.lang.insert(StringName("ps_PK"));
pr.lang.insert(StringName("ur_IN")); // Urdu
pr.lang.insert(StringName("uz_AF")); // Uzbek
pr.lang.insert(StringName("uz_Arab"));
pr.lang.insert(StringName("uz_Arab_AF"));
pr.digits = U"۰۱۲۳۴۵۶۷۸۹٫";
pr.percent_sign = U"٪";
pr.exp_l = U"اس";
pr.exp_u = U"اس";
num_systems.push_back(pr);
}
// Bengali numerals.
{
NumSystemData bn;
bn.lang.insert(StringName("as")); // Assamese
bn.lang.insert(StringName("as_IN"));
bn.lang.insert(StringName("bn")); // Bengali
bn.lang.insert(StringName("bn_BD"));
bn.lang.insert(StringName("bn_IN"));
bn.lang.insert(StringName("mni")); // Manipuri
bn.lang.insert(StringName("mni_IN"));
bn.lang.insert(StringName("mni_Beng"));
bn.lang.insert(StringName("mni_Beng_IN"));
bn.digits = U"০১২৩৪৫৬৭৮৯.";
bn.percent_sign = U"%";
bn.exp_l = U"e";
bn.exp_u = U"E";
num_systems.push_back(bn);
}
// Devanagari numerals.
{
NumSystemData mr;
mr.lang.insert(StringName("mr")); // Marathi
mr.lang.insert(StringName("mr_IN"));
mr.lang.insert(StringName("ne")); // Nepali
mr.lang.insert(StringName("ne_IN"));
mr.lang.insert(StringName("ne_NP"));
mr.lang.insert(StringName("sa")); // Sanskrit
mr.lang.insert(StringName("sa_IN"));
mr.digits = U"०१२३४५६७८९.";
mr.percent_sign = U"%";
mr.exp_l = U"e";
mr.exp_u = U"E";
num_systems.push_back(mr);
}
// Dzongkha numerals.
{
NumSystemData dz;
dz.lang.insert(StringName("dz")); // Dzongkha
dz.lang.insert(StringName("dz_BT"));
dz.digits = U"༠༡༢༣༤༥༦༧༨༩.";
dz.percent_sign = U"%";
dz.exp_l = U"e";
dz.exp_u = U"E";
num_systems.push_back(dz);
}
// Santali numerals.
{
NumSystemData sat;
sat.lang.insert(StringName("sat")); // Santali
sat.lang.insert(StringName("sat_IN"));
sat.lang.insert(StringName("sat_Olck"));
sat.lang.insert(StringName("sat_Olck_IN"));
sat.digits = U"᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙.";
sat.percent_sign = U"%";
sat.exp_l = U"e";
sat.exp_u = U"E";
num_systems.push_back(sat);
}
// Burmese numerals.
{
NumSystemData my;
my.lang.insert(StringName("my")); // Burmese
my.lang.insert(StringName("my_MM"));
my.digits = U"၀၁၂၃၄၅၆၇၈၉.";
my.percent_sign = U"%";
my.exp_l = U"e";
my.exp_u = U"E";
num_systems.push_back(my);
}
// Chakma numerals.
{
NumSystemData ccp;
ccp.lang.insert(StringName("ccp")); // Chakma
ccp.lang.insert(StringName("ccp_BD"));
ccp.lang.insert(StringName("ccp_IN"));
ccp.digits = U"𑄶𑄷𑄸𑄹𑄺𑄻𑄼𑄽𑄾𑄿.";
ccp.percent_sign = U"%";
ccp.exp_l = U"e";
ccp.exp_u = U"E";
num_systems.push_back(ccp);
}
// Adlam numerals.
{
NumSystemData ff;
ff.lang.insert(StringName("ff")); // Fulah
ff.lang.insert(StringName("ff_Adlm_BF"));
ff.lang.insert(StringName("ff_Adlm_CM"));
ff.lang.insert(StringName("ff_Adlm_GH"));
ff.lang.insert(StringName("ff_Adlm_GM"));
ff.lang.insert(StringName("ff_Adlm_GN"));
ff.lang.insert(StringName("ff_Adlm_GW"));
ff.lang.insert(StringName("ff_Adlm_LR"));
ff.lang.insert(StringName("ff_Adlm_MR"));
ff.lang.insert(StringName("ff_Adlm_NE"));
ff.lang.insert(StringName("ff_Adlm_NG"));
ff.lang.insert(StringName("ff_Adlm_SL"));
ff.lang.insert(StringName("ff_Adlm_SN"));
ff.digits = U"𞥐𞥑𞥒𞥓𞥔𞥕𞥖𞥗𞥘𞥙.";
ff.percent_sign = U"%";
ff.exp_l = U"𞤉";
ff.exp_u = U"𞤉";
num_systems.push_back(ff);
}
}
String TextServerAdvanced::_format_number(const String &p_string, const String &p_language) const {
const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
String res = p_string;
for (int i = 0; i < num_systems.size(); i++) {
if (num_systems[i].lang.has(lang)) {
if (num_systems[i].digits.is_empty()) {
return p_string;
}
res = res.replace("e", num_systems[i].exp_l);
res = res.replace("E", num_systems[i].exp_u);
char32_t *data = res.ptrw();
for (int j = 0; j < res.length(); j++) {
if (data[j] >= 0x30 && data[j] <= 0x39) {
data[j] = num_systems[i].digits[data[j] - 0x30];
} else if (data[j] == '.' || data[j] == ',') {
data[j] = num_systems[i].digits[10];
}
}
break;
}
}
return res;
}
String TextServerAdvanced::_parse_number(const String &p_string, const String &p_language) const {
const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
String res = p_string;
for (int i = 0; i < num_systems.size(); i++) {
if (num_systems[i].lang.has(lang)) {
if (num_systems[i].digits.is_empty()) {
return p_string;
}
res = res.replace(num_systems[i].exp_l, "e");
res = res.replace(num_systems[i].exp_u, "E");
char32_t *data = res.ptrw();
for (int j = 0; j < res.length(); j++) {
if (data[j] == num_systems[i].digits[10]) {
data[j] = '.';
} else {
for (int k = 0; k < 10; k++) {
if (data[j] == num_systems[i].digits[k]) {
data[j] = 0x30 + k;
}
}
}
}
break;
}
}
return res;
}
String TextServerAdvanced::_percent_sign(const String &p_language) const {
const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
for (int i = 0; i < num_systems.size(); i++) {
if (num_systems[i].lang.has(lang)) {
if (num_systems[i].percent_sign.is_empty()) {
return "%";
}
return num_systems[i].percent_sign;
}
}
return "%";
}
int64_t TextServerAdvanced::_is_confusable(const String &p_string, const PackedStringArray &p_dict) const {
#ifndef ICU_STATIC_DATA
if (!icu_data_loaded) {
@ -8316,7 +8064,6 @@ void TextServerAdvanced::_update_settings() {
}
TextServerAdvanced::TextServerAdvanced() {
_insert_num_systems_lang();
_insert_feature_sets();
_bmp_create_font_funcs();
_update_settings();

View file

@ -143,16 +143,6 @@ class TextServerAdvanced : public TextServerExtension {
GDCLASS(TextServerAdvanced, TextServerExtension);
_THREAD_SAFE_CLASS_
struct NumSystemData {
HashSet<StringName> lang;
String digits;
String percent_sign;
String exp_l;
String exp_u;
};
Vector<NumSystemData> num_systems;
struct FeatureInfo {
StringName name;
Variant::Type vtype = Variant::INT;
@ -173,7 +163,6 @@ class TextServerAdvanced : public TextServerExtension {
LineBreakStrictness lb_strictness = LB_AUTO;
void _update_settings();
void _insert_num_systems_lang();
void _insert_feature_sets();
_FORCE_INLINE_ void _insert_feature(const StringName &p_name, int32_t p_tag, Variant::Type p_vtype = Variant::INT, bool p_hidden = false);
@ -1121,10 +1110,6 @@ public:
MODBIND1RC(PackedInt32Array, shaped_text_get_character_breaks, const RID &);
MODBIND2RC(String, format_number, const String &, const String &);
MODBIND2RC(String, parse_number, const String &, const String &);
MODBIND1RC(String, percent_sign, const String &);
MODBIND3RC(PackedInt32Array, string_get_word_breaks, const String &, const String &, int64_t);
MODBIND2RC(PackedInt32Array, string_get_character_breaks, const String &, const String &);

View file

@ -34,6 +34,7 @@
#include "core/config/project_settings.h"
#include "core/os/keyboard.h"
#include "core/string/string_builder.h"
#include "core/string/translation_server.h"
#include "core/string/ustring.h"
#include "scene/theme/theme_db.h"
@ -1545,7 +1546,7 @@ void CodeEdit::_line_number_draw_callback(int p_line, int p_gutter, const Rect2
const String &lang = _get_locale();
String fc = String::num_int64(p_line + 1).lpad(line_number_digits, line_number_padding);
if (is_localizing_numeral_system()) {
fc = TS->format_number(fc, lang);
fc = TranslationServer::get_singleton()->format_number(fc, lang);
}
text_rid = TS->create_shaped_text();

View file

@ -30,6 +30,7 @@
#include "progress_bar.h"
#include "core/string/translation_server.h"
#include "scene/resources/text_line.h"
#include "scene/theme/theme_db.h"
@ -168,7 +169,7 @@ void ProgressBar::_notification(int p_what) {
if (is_localizing_numeral_system()) {
const String &lang = _get_locale();
txt = TS->format_number(txt, lang) + TS->percent_sign(lang);
txt = TranslationServer::get_singleton()->format_number(txt, lang) + TranslationServer::get_singleton()->get_percent_sign(lang);
} else {
txt += String("%");
}

View file

@ -36,6 +36,7 @@
#include "core/math/math_defs.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/string/translation_server.h"
#include "scene/gui/label.h"
#include "scene/gui/rich_text_effect.h"
#include "scene/main/timer.h"
@ -252,7 +253,7 @@ String RichTextLabel::_get_prefix(Item *p_item, const Vector<int> &p_list_index,
if (p_list_items[i]->list_type == LIST_NUMBERS) {
segment = itos(p_list_index[i]);
if (is_localizing_numeral_system()) {
segment = TS->format_number(segment, _find_language(p_item));
segment = TranslationServer::get_singleton()->format_number(segment, _find_language(p_item));
}
segments++;
} else if (p_list_items[i]->list_type == LIST_LETTERS) {

View file

@ -32,6 +32,7 @@
#include "core/input/input.h"
#include "core/math/expression.h"
#include "core/string/translation_server.h"
#include "scene/theme/theme_db.h"
void SpinBoxLineEdit::_accessibility_action_inc(const Variant &p_data) {
@ -88,7 +89,7 @@ void SpinBox::_update_text(bool p_only_update_if_value_changed) {
double step = get_step();
String value = String::num(get_value(), Math::range_step_decimals(step));
if (is_localizing_numeral_system()) {
value = TS->format_number(value, _get_locale());
value = TranslationServer::get_singleton()->format_number(value, _get_locale());
}
if (p_only_update_if_value_changed && value == last_text_value) {
@ -139,7 +140,7 @@ void SpinBox::_text_submitted(const String &p_string) {
const String &lang = _get_locale();
text = text.replace_char(';', ',');
text = TS->parse_number(text, lang);
text = TranslationServer::get_singleton()->parse_number(text, lang);
// Ignore the prefix and suffix in the expression.
text = text.trim_prefix(prefix + " ").trim_suffix(" " + suffix);
@ -148,7 +149,7 @@ void SpinBox::_text_submitted(const String &p_string) {
if (err != OK) {
// If the expression failed try without converting commas to dots - they might have been for parameter separation.
text = p_string;
text = TS->parse_number(text, lang);
text = TranslationServer::get_singleton()->parse_number(text, lang);
text = text.trim_prefix(prefix + " ").trim_suffix(" " + suffix);
err = expr->parse(text);

View file

@ -36,6 +36,10 @@
#include "core/variant/typed_array.h"
#include "servers/rendering/rendering_server.h"
#ifndef DISABLE_DEPRECATED
#include "core/string/translation_server.h"
#endif // DISABLE_DEPRECATED
TextServerManager *TextServerManager::singleton = nullptr;
void TextServerManager::_bind_methods() {
@ -507,9 +511,11 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("shaped_text_get_dominant_direction_in_range", "shaped", "start", "end"), &TextServer::shaped_text_get_dominant_direction_in_range);
#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("format_number", "number", "language"), &TextServer::format_number, DEFVAL(""));
ClassDB::bind_method(D_METHOD("parse_number", "number", "language"), &TextServer::parse_number, DEFVAL(""));
ClassDB::bind_method(D_METHOD("percent_sign", "language"), &TextServer::percent_sign, DEFVAL(""));
#endif // DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("string_get_word_breaks", "string", "language", "chars_per_line"), &TextServer::string_get_word_breaks, DEFVAL(""), DEFVAL(0));
ClassDB::bind_method(D_METHOD("string_get_character_breaks", "string", "language"), &TextServer::string_get_character_breaks, DEFVAL(""));
@ -2109,6 +2115,23 @@ String TextServer::strip_diacritics(const String &p_string) const {
return result;
}
#ifndef DISABLE_DEPRECATED
String TextServer::format_number(const String &p_string, const String &p_language) const {
const StringName lang = p_language.is_empty() ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
return TranslationServer::get_singleton()->format_number(p_string, lang);
}
String TextServer::parse_number(const String &p_string, const String &p_language) const {
const StringName lang = p_language.is_empty() ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
return TranslationServer::get_singleton()->parse_number(p_string, lang);
}
String TextServer::percent_sign(const String &p_language) const {
const StringName lang = p_language.is_empty() ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
return TranslationServer::get_singleton()->get_percent_sign(lang);
}
#endif // DISABLE_DEPRECATED
TypedArray<Vector3i> TextServer::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
TypedArray<Vector3i> ret;
switch (p_parser_type) {

View file

@ -584,10 +584,12 @@ public:
void shaped_text_debug_print(const RID &p_shaped) const;
#endif
#ifndef DISABLE_DEPRECATED
// Number conversion.
virtual String format_number(const String &p_string, const String &p_language = "") const = 0;
virtual String parse_number(const String &p_string, const String &p_language = "") const = 0;
virtual String percent_sign(const String &p_language = "") const = 0;
virtual String format_number(const String &p_string, const String &p_language = "") const;
virtual String parse_number(const String &p_string, const String &p_language = "") const;
virtual String percent_sign(const String &p_language = "") const;
#endif // DISABLE_DEPRECATED
// String functions.
virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "", int64_t p_chars_per_line = 0) const = 0;

View file

@ -365,9 +365,11 @@ void TextServerExtension::_bind_methods() {
GDVIRTUAL_BIND(_shaped_text_prev_character_pos, "shaped", "pos");
GDVIRTUAL_BIND(_shaped_text_closest_character_pos, "shaped", "pos");
#ifndef DISABLE_DEPRECATED
GDVIRTUAL_BIND(_format_number, "number", "language");
GDVIRTUAL_BIND(_parse_number, "number", "language");
GDVIRTUAL_BIND(_percent_sign, "language");
#endif
GDVIRTUAL_BIND(_strip_diacritics, "string");
GDVIRTUAL_BIND(_is_valid_identifier, "string");
@ -1652,12 +1654,13 @@ int64_t TextServerExtension::shaped_text_closest_character_pos(const RID &p_shap
return TextServer::shaped_text_closest_character_pos(p_shaped, p_pos);
}
#ifndef DISABLE_DEPRECATED
String TextServerExtension::format_number(const String &p_string, const String &p_language) const {
String ret;
if (GDVIRTUAL_CALL(_format_number, p_string, p_language, ret)) {
return ret;
}
return p_string;
return TextServer::format_number(p_string, p_language);
}
String TextServerExtension::parse_number(const String &p_string, const String &p_language) const {
@ -1665,14 +1668,17 @@ String TextServerExtension::parse_number(const String &p_string, const String &p
if (GDVIRTUAL_CALL(_parse_number, p_string, p_language, ret)) {
return ret;
}
return p_string;
return TextServer::parse_number(p_string, p_language);
}
String TextServerExtension::percent_sign(const String &p_language) const {
String ret = "%";
GDVIRTUAL_CALL(_percent_sign, p_language, ret);
return ret;
if (GDVIRTUAL_CALL(_percent_sign, p_language, ret)) {
return ret;
}
return TextServer::percent_sign(p_language);
}
#endif // DISABLE_DEPRECATED
bool TextServerExtension::is_valid_identifier(const String &p_string) const {
bool ret;

View file

@ -607,12 +607,14 @@ public:
GDVIRTUAL2RC(int64_t, _shaped_text_prev_character_pos, RID, int64_t);
GDVIRTUAL2RC(int64_t, _shaped_text_closest_character_pos, RID, int64_t);
#ifndef DISABLE_DEPRECATED
virtual String format_number(const String &p_string, const String &p_language = "") const override;
virtual String parse_number(const String &p_string, const String &p_language = "") const override;
virtual String percent_sign(const String &p_language = "") const override;
GDVIRTUAL2RC(String, _format_number, const String &, const String &);
GDVIRTUAL2RC(String, _parse_number, const String &, const String &);
GDVIRTUAL1RC(String, _percent_sign, const String &);
#endif // DISABLE_DEPRECATED
virtual String strip_diacritics(const String &p_string) const override;
GDVIRTUAL1RC(String, _strip_diacritics, const String &);