[macOS/iOS/Windows] Add method to get full list of user preferred locales and use it for the editor locale selection.

This commit is contained in:
Pāvels Nadtočajevs
2026-04-17 23:36:20 +03:00
parent caf16709af
commit 06aa8042c2
13 changed files with 108 additions and 31 deletions
+5
View File
@@ -562,6 +562,10 @@ String OS::get_locale() const {
return ::OS::get_singleton()->get_locale();
}
Vector<String> OS::get_preferred_locales() const {
return ::OS::get_singleton()->get_preferred_locales();
}
String OS::get_locale_language() const {
return ::OS::get_singleton()->get_locale_language();
}
@@ -818,6 +822,7 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("delay_usec", "usec"), &OS::delay_usec);
ClassDB::bind_method(D_METHOD("delay_msec", "msec"), &OS::delay_msec);
ClassDB::bind_method(D_METHOD("get_locale"), &OS::get_locale);
ClassDB::bind_method(D_METHOD("get_preferred_locales"), &OS::get_preferred_locales);
ClassDB::bind_method(D_METHOD("get_locale_language"), &OS::get_locale_language);
ClassDB::bind_method(D_METHOD("get_model_name"), &OS::get_model_name);
+1
View File
@@ -249,6 +249,7 @@ public:
Vector<String> get_video_adapter_driver_info() const;
String get_locale() const;
Vector<String> get_preferred_locales() const;
String get_locale_language() const;
String get_model_name() const;
+1
View File
@@ -308,6 +308,7 @@ public:
bool is_separate_thread_rendering_enabled() const { return _separate_thread_render; }
virtual String get_locale() const;
virtual Vector<String> get_preferred_locales() const { return Vector<String>{ get_locale() }; }
String get_locale_language() const;
virtual uint64_t get_embedded_pck_offset() const;
+14 -2
View File
@@ -337,8 +337,8 @@
- [code]language[/code] - 2 or 3-letter [url=https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes]language code[/url], in lower case.
- [code skip-lint]Script[/code] - 4-letter [url=https://en.wikipedia.org/wiki/ISO_15924]script code[/url], in title case.
- [code]COUNTRY[/code] - 2 or 3-letter [url=https://en.wikipedia.org/wiki/ISO_3166-1]country code[/url], in upper case.
- [code]VARIANT[/code] - language variant, region and sort order. The variant can have any number of underscored keywords.
- [code]extra[/code] - semicolon separated list of additional key words. This may include currency, calendar, sort order and numbering system information.
- [code]VARIANT[/code] - language variant, region, and sort order. The variant can have any number of underscored keywords.
- [code]extra[/code] - semicolon separated list of additional key words. This may include currency, calendar, sort order, and numbering system information.
If you want only the language code and not the fully specified locale from the OS, you can use [method get_locale_language].
</description>
</method>
@@ -433,6 +433,18 @@
[b]Note:[/b] On Web platforms, it is still possible to determine the host platform's OS with feature tags. See [method has_feature].
</description>
</method>
<method name="get_preferred_locales" qualifiers="const">
<return type="PackedStringArray" />
<description>
Returns an array of locales preferred by the user, in order of preference. Each locale is as a [String] on the form [code]language_Script_COUNTRY_VARIANT@extra[/code]. Every substring after [code]language[/code] is optional and may not exist.
- [code]language[/code] - 2 or 3-letter [url=https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes]language code[/url], in lower case.
- [code skip-lint]Script[/code] - 4-letter [url=https://en.wikipedia.org/wiki/ISO_15924]script code[/url], in title case.
- [code]COUNTRY[/code] - 2 or 3-letter [url=https://en.wikipedia.org/wiki/ISO_3166-1]country code[/url], in upper case.
- [code]VARIANT[/code] - language variant, region, and sort order. The variant can have any number of underscored keywords.
- [code]extra[/code] - semicolon separated list of additional key words. This may include currency, calendar, sort order, and numbering system information.
[b]Note:[/b] This method is implemented on macOS, iOS, and Windows.
</description>
</method>
<method name="get_process_exit_code" qualifiers="const">
<return type="int" />
<param index="0" name="pid" type="int" />
@@ -123,6 +123,7 @@ public:
virtual String get_bundle_resource_dir() const override;
virtual String get_locale() const override;
virtual Vector<String> get_preferred_locales() const override;
virtual String get_unique_id() const override;
virtual String get_processor_name() const override;
@@ -460,6 +460,18 @@ String OS_AppleEmbedded::get_locale() const {
return String::utf8([localeIdentifier UTF8String]).replace_char('-', '_');
}
Vector<String> OS_AppleEmbedded::get_preferred_locales() const {
Vector<String> out;
for (NSString *locale_code in [NSLocale preferredLanguages]) {
out.push_back(String([locale_code UTF8String]).replace_char('-', '_'));
}
if (out.is_empty()) {
NSString *localeIdentifier = [[NSLocale currentLocale] localeIdentifier];
out.push_back(String::utf8([localeIdentifier UTF8String]).replace_char('-', '_'));
}
return out;
}
String OS_AppleEmbedded::get_unique_id() const {
NSString *uuid = [UIDevice currentDevice].identifierForVendor.UUIDString;
return String::utf8([uuid UTF8String]);
+35 -29
View File
@@ -59,7 +59,6 @@
#include "scene/gui/file_dialog.h"
#include "scene/main/node.h"
#include "scene/main/scene_tree.h"
#include "scene/main/window.h"
#include "scene/resources/animation.h"
#include "servers/display/display_server.h"
@@ -423,32 +422,35 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
/* Languages */
{
String lang_hint;
const String host_lang = OS::get_singleton()->get_locale();
// Skip locales which we can't render properly.
const LocalVector<String> locales_to_skip = _get_skipped_locales();
if (!locales_to_skip.is_empty()) {
WARN_PRINT("Some locales are not properly supported by selected Text Server and are disabled.");
}
String lang_hint;
String best = "en";
int best_score = 0;
for (const String &locale : get_editor_locales()) {
// Test against language code without regional variants (e.g. ur_PK).
String lang_code = locale.get_slicec('_', 0);
if (locales_to_skip.has(lang_code)) {
continue;
for (const String &host_lang : OS::get_singleton()->get_preferred_locales()) {
for (const String &locale : get_editor_locales()) {
// Test against language code without regional variants (e.g. ur_PK).
String lang_code = locale.get_slicec('_', 0);
if (locales_to_skip.has(lang_code)) {
continue;
}
lang_hint += ";";
const String lang_name = TranslationServer::get_singleton()->get_locale_name(locale);
lang_hint += vformat("%s/[%s] %s", locale, locale, lang_name);
int score = TranslationServer::get_singleton()->compare_locales(host_lang, locale);
if (score > 0 && score >= best_score) {
best = locale;
best_score = score;
}
}
lang_hint += ";";
const String lang_name = TranslationServer::get_singleton()->get_locale_name(locale);
lang_hint += vformat("%s/[%s] %s", locale, locale, lang_name);
int score = TranslationServer::get_singleton()->compare_locales(host_lang, locale);
if (score > 0 && score >= best_score) {
best = locale;
best_score = score;
if (best_score > 0) {
break;
}
}
lang_hint = vformat(";auto/Auto (%s);en/[en] English", TranslationServer::get_singleton()->get_locale_name(best)) + lang_hint;
@@ -2031,21 +2033,25 @@ String EditorSettings::get_language() const {
if (auto_language.is_empty()) {
// Skip locales which we can't render properly.
const LocalVector<String> locales_to_skip = _get_skipped_locales();
const String host_lang = OS::get_singleton()->get_locale();
String best = "en";
int best_score = 0;
for (const String &locale : get_editor_locales()) {
// Test against language code without regional variants (e.g. ur_PK).
String lang_code = locale.get_slicec('_', 0);
if (locales_to_skip.has(lang_code)) {
continue;
}
for (const String &host_lang : OS::get_singleton()->get_preferred_locales()) {
for (const String &locale : get_editor_locales()) {
// Test against language code without regional variants (e.g. ur_PK).
String lang_code = locale.get_slicec('_', 0);
if (locales_to_skip.has(lang_code)) {
continue;
}
int score = TranslationServer::get_singleton()->compare_locales(host_lang, locale);
if (score > 0 && score >= best_score) {
best = locale;
best_score = score;
int score = TranslationServer::get_singleton()->compare_locales(host_lang, locale);
if (score > 0 && score >= best_score) {
best = locale;
best_score = score;
}
}
if (best_score > 0) {
break;
}
}
auto_language = best;
+1
View File
@@ -130,6 +130,7 @@ public:
virtual Error shell_show_in_file_manager(String p_path, bool p_open_folder) override;
virtual String get_locale() const override;
virtual Vector<String> get_preferred_locales() const override;
virtual Vector<String> get_system_fonts() const override;
virtual String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override;
+8
View File
@@ -585,6 +585,14 @@ String OS_MacOS::get_locale() const {
return String([locale_code UTF8String]).replace_char('-', '_');
}
Vector<String> OS_MacOS::get_preferred_locales() const {
Vector<String> out;
for (NSString *locale_code in [NSLocale preferredLanguages]) {
out.push_back(String([locale_code UTF8String]).replace_char('-', '_'));
}
return out;
}
Vector<String> OS_MacOS::get_system_fonts() const {
HashSet<String> font_names;
CFArrayRef fonts = CTFontManagerCopyAvailableFontFamilyNames();
+9
View File
@@ -34,6 +34,7 @@
#include "lang_table.h"
#include "windows_terminal_logger.h"
#include "windows_utils.h"
#include "winrt_utils.h"
#include "core/config/engine.h"
#include "core/debugger/engine_debugger.h"
@@ -2292,6 +2293,14 @@ String OS_Windows::get_locale() const {
return "en";
}
Vector<String> OS_Windows::get_preferred_locales() const {
Vector<String> out = WinRTUtils::get_preferred_locales();
if (out.is_empty()) {
out.push_back(get_locale());
}
return out;
}
String OS_Windows::get_model_name() const {
HKEY hkey;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Hardware\\Description\\System\\BIOS", 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS) {
+1
View File
@@ -220,6 +220,7 @@ public:
virtual String get_executable_path() const override;
virtual String get_locale() const override;
virtual Vector<String> get_preferred_locales() const override;
virtual String get_processor_name() const override;
+18
View File
@@ -43,8 +43,10 @@ GODOT_CLANG_WARNING_PUSH
GODOT_CLANG_WARNING_IGNORE("-Wnon-virtual-dtor")
#include <inspectable.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Foundation.Metadata.h>
#include <winrt/Windows.Graphics.Display.h>
#include <winrt/Windows.System.UserProfile.h>
#include <winrt/Windows.System.h>
#include <winrt/Windows.UI.Input.h>
#include <winrt/Windows.UI.ViewManagement.Core.h>
@@ -109,7 +111,9 @@ GODOT_CLANG_WARNING_POP
using namespace winrt::Windows::Graphics::Display;
using namespace winrt::Windows::System;
using namespace winrt::Windows::System::UserProfile;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Windows::Foundation::Metadata;
using namespace winrt::Windows::UI::ViewManagement::Core;
@@ -143,6 +147,16 @@ void WinRTUtils::destroy_queue() {
ERR_FAIL_COND_MSG(action.Status() == AsyncStatus::Error, "DispatcherQueueController shutdown failed.");
}
Vector<String> WinRTUtils::get_preferred_locales() {
Vector<String> out;
IVectorView<winrt::hstring> languages = GlobalizationPreferences::Languages();
for (uint32_t i = 0; i < languages.Size(); i++) {
winrt::hstring lang = languages.GetAt(i);
out.push_back(String::utf16((const char16_t *)lang.c_str(), lang.size()).replace_char('-', '_'));
}
return out;
}
bool WinRTUtils::try_show_onecore_emoji_picker() {
if (ApiInformation::IsApiContractPresent(L"Windows.Foundation.UniversalApiContract", 7)) { // Windows 10, 1809+
return CoreInputView::GetForCurrentView().TryShow(CoreInputViewKind::Emoji);
@@ -218,6 +232,10 @@ bool WinRTUtils::create_queue() {
void WinRTUtils::destroy_queue() {}
Vector<String> WinRTUtils::get_preferred_locales() {
return Vector<String>();
}
bool WinRTUtils::window_has_display_info(const WinRTWindowData *p_data) {
return false;
}
+2
View File
@@ -45,6 +45,8 @@ public:
static bool create_queue();
static void destroy_queue();
static Vector<String> get_preferred_locales();
static WinRTWindowData *create_wd(HWND p_window, const Callable &p_color_cb, int64_t p_window_id);
static bool window_has_display_info(const WinRTWindowData *p_data);
static void window_get_advanced_color_info(const WinRTWindowData *p_data, bool &r_hdr_supported, float &r_min_luminance, float &r_max_luminance, float &r_max_average_luminance, float &r_sdr_white_level);