From c610b611261ae2bdb5df7bac6104f1c1e98b6354 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 23 Feb 2026 13:39:16 +0100 Subject: [PATCH] [common, hle] add new updates Polish+Thai languages (#3587) Signed-off-by: lizzie Co-authored-by: maufeat Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3587 Reviewed-by: Maufeat Reviewed-by: DraVee Co-authored-by: lizzie Co-committed-by: lizzie --- .../app/src/main/res/values/arrays.xml | 5 +- .../app/src/main/res/values/strings.xml | 4 +- src/common/settings_enums.h | 2 +- src/core/file_sys/control_metadata.cpp | 159 +++++-------- src/core/file_sys/control_metadata.h | 225 +++++++++++++++--- src/core/hle/service/ns/language.cpp | 82 +++++++ src/core/hle/service/ns/language.h | 5 + src/core/hle/service/set/settings_types.h | 15 +- src/qt_common/config/shared_translation.cpp | 3 +- 9 files changed, 358 insertions(+), 142 deletions(-) diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index b0487302b3..565decb390 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -64,7 +64,8 @@ @string/language_spanish @string/language_taiwanese @string/language_traditional_chinese - @string/language_serbian + @string/language_polish + @string/language_thai @@ -87,6 +88,7 @@ 11 16 18 + 19 @@ -407,6 +409,7 @@ @string/app_language_persian @string/app_language_hebrew @string/app_language_serbian + @string/app_language_thai 0 diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 8a1193303e..a34d75d7cb 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -1011,7 +1011,8 @@ 简体中文 正體中文 Português do Brasil - српски + Polska + แบบไทย B @@ -1216,6 +1217,7 @@ فارسی עברית Српски + แบบไทย Theme Color diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h index d4935d9b6d..638be4127f 100644 --- a/src/common/settings_enums.h +++ b/src/common/settings_enums.h @@ -120,7 +120,7 @@ ENUM(AudioMode, Mono, Stereo, Surround); ENUM(Language, Japanese, EnglishAmerican, French, German, Italian, Spanish, Chinese, Korean, Dutch, Portuguese, Russian, Taiwanese, EnglishBritish, FrenchCanadian, SpanishLatin, - ChineseSimplified, ChineseTraditional, PortugueseBrazilian, Serbian); + ChineseSimplified, ChineseTraditional, PortugueseBrazilian, Polish, Thai); ENUM(Region, Japan, Usa, Europe, Australia, China, Korea, Taiwan); ENUM(TimeZone, Auto, Default, Cet, Cst6Cdt, Cuba, Eet, Egypt, Eire, Est, Est5Edt, Gb, GbEire, Gmt, GmtPlusZero, GmtMinusZero, GmtZero, Greenwich, Hongkong, Hst, Iceland, Iran, Israel, Jamaica, diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp index 7ca7703afa..3676c1bbc8 100644 --- a/src/core/file_sys/control_metadata.cpp +++ b/src/core/file_sys/control_metadata.cpp @@ -12,6 +12,7 @@ #include #include "common/settings.h" +#include "common/settings_enums.h" #include "common/string_util.h" #include "common/swap.h" #include "core/file_sys/control_metadata.h" @@ -19,7 +20,7 @@ namespace FileSys { -const std::array LANGUAGE_NAMES{{ +const std::array LANGUAGE_NAMES{{ "AmericanEnglish", "BritishEnglish", "Japanese", @@ -36,137 +37,95 @@ const std::array LANGUAGE_NAMES{{ "TraditionalChinese", "SimplifiedChinese", "BrazilianPortuguese", + "Polish", + "Thai", }}; -namespace { -constexpr std::size_t LEGACY_LANGUAGE_REGION_SIZE = sizeof(std::array); -constexpr std::size_t PACKED_LANGUAGE_REGION_MAX_SIZE = sizeof(LanguageEntry) * 32; +namespace +{ + constexpr std::size_t MAX_EXPANDED_LANG_SIZE = sizeof(LanguageEntry) * 32; -bool InflateRawDeflate(std::span compressed, std::vector& out) { - if (compressed.empty() || compressed.size() > std::numeric_limits::max()) { - return false; - } - z_stream stream{}; - stream.next_in = const_cast(reinterpret_cast(compressed.data())); - stream.avail_in = static_cast(compressed.size()); - if (inflateInit2(&stream, -MAX_WBITS) != Z_OK) { - return false; - } + bool InflateRawDeflate(std::span compressed, std::vector& out) + { + if (compressed.empty()) return false; - std::array chunk{}; - int ret = Z_OK; - while (ret == Z_OK) { - stream.next_out = reinterpret_cast(chunk.data()); - stream.avail_out = static_cast(chunk.size()); - ret = inflate(&stream, Z_NO_FLUSH); - if (ret != Z_OK && ret != Z_STREAM_END) { - inflateEnd(&stream); + z_stream stream{}; + stream.next_in = const_cast(reinterpret_cast(compressed.data())); + stream.avail_in = static_cast(compressed.size()); + if (inflateInit2(&stream, -MAX_WBITS) != Z_OK) { return false; } - const auto produced = chunk.size() - static_cast(stream.avail_out); - if (produced != 0) { - if (out.size() + produced > PACKED_LANGUAGE_REGION_MAX_SIZE) { - inflateEnd(&stream); - return false; - } - out.insert(out.end(), chunk.begin(), - chunk.begin() + static_cast(produced)); + out.resize(MAX_EXPANDED_LANG_SIZE); + stream.next_out = reinterpret_cast(out.data()); + stream.avail_out = static_cast(out.size()); + + int ret = inflate(&stream, Z_FINISH); + inflateEnd(&stream); + + if (ret != Z_STREAM_END && ret != Z_OK) { + return false; } + + // Shrink to actual decompressed size + out.resize(stream.total_out); + return true; } - - inflateEnd(&stream); - return ret == Z_STREAM_END; -} - -void DecodePackedLanguageEntries(RawNACP& raw) { - auto* packed_region = reinterpret_cast(raw.language_entries.data()); - u16_le compressed_size_le{}; - std::memcpy(&compressed_size_le, packed_region, sizeof(compressed_size_le)); - const auto compressed_size = static_cast(compressed_size_le); - - if (compressed_size == 0 || compressed_size > LEGACY_LANGUAGE_REGION_SIZE - sizeof(u16_le)) { - return; - } - - std::vector decompressed; - if (!InflateRawDeflate( - std::span(packed_region + sizeof(u16_le), compressed_size), decompressed)) { - return; - } - - if (decompressed.size() < LEGACY_LANGUAGE_REGION_SIZE || - decompressed.size() % sizeof(LanguageEntry) != 0) { - return; - } - - std::memcpy(raw.language_entries.data(), decompressed.data(), LEGACY_LANGUAGE_REGION_SIZE); -} } // namespace std::string LanguageEntry::GetApplicationName() const { - return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), - application_name.size()); + return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), application_name.size()); } std::string LanguageEntry::GetDeveloperName() const { - return Common::StringFromFixedZeroTerminatedBuffer(developer_name.data(), - developer_name.size()); + return Common::StringFromFixedZeroTerminatedBuffer(developer_name.data(), developer_name.size()); } -constexpr std::array language_to_codes = {{ - Language::Japanese, - Language::AmericanEnglish, - Language::French, - Language::German, - Language::Italian, - Language::Spanish, - Language::SimplifiedChinese, - Language::Korean, - Language::Dutch, - Language::Portuguese, - Language::Russian, - Language::TraditionalChinese, - Language::BritishEnglish, - Language::CanadianFrench, - Language::LatinAmericanSpanish, - Language::SimplifiedChinese, - Language::TraditionalChinese, - Language::BrazilianPortuguese, -}}; - NACP::NACP() = default; -NACP::NACP(VirtualFile file) { +NACP::NACP(VirtualFile file) +{ file->ReadObject(&raw); - DecodePackedLanguageEntries(raw); + if (raw.titles_data_format == TitleDataFormat::Compressed) { + const u16 compressed_size = raw.language_entries.compressed_data.buffer_size; + std::span compressed_payload{raw.language_entries.compressed_data.buffer, + compressed_size}; + + std::vector decompressed; + if (InflateRawDeflate(compressed_payload, decompressed)) { + const size_t entry_count = decompressed.size() / sizeof(LanguageEntry); + language_entries.resize(entry_count); + std::memcpy(language_entries.data(), decompressed.data(), decompressed.size()); + } + } else { + language_entries.resize(16); + std::memcpy(language_entries.data(), raw.language_entries.language_entries.data(), + sizeof(raw.language_entries.language_entries)); + } } NACP::~NACP() = default; const LanguageEntry& NACP::GetLanguageEntry() const { - Language language = - language_to_codes[static_cast(Settings::values.language_index.GetValue())]; + u32 index = static_cast(Settings::values.language_index.GetValue()); - { - const auto& language_entry = raw.language_entries.at(static_cast(language)); - if (!language_entry.GetApplicationName().empty()) - return language_entry; + if (index < language_entries.size()) { + return language_entries[index]; } - for (const auto& language_entry : raw.language_entries) { - if (!language_entry.GetApplicationName().empty()) - return language_entry; + for (const auto& entry : language_entries) { + return entry; } - return raw.language_entries.at(static_cast(Language::AmericanEnglish)); + return language_entries.at(static_cast(Language::AmericanEnglish)); } -std::array NACP::GetApplicationNames() const { - std::array names{}; - for (size_t i = 0; i < raw.language_entries.size(); ++i) { - names[i] = raw.language_entries[i].GetApplicationName(); +std::vector NACP::GetApplicationNames() const { + std::vector names; + names.reserve(language_entries.size()); + for (const auto& entry : language_entries) { + names.push_back(entry.GetApplicationName()); } return names; } @@ -205,7 +164,7 @@ bool NACP::GetUserAccountSwitchLock() const { } u32 NACP::GetSupportedLanguages() const { - return raw.supported_languages; + return u32(raw.supported_languages); } u64 NACP::GetDeviceSaveDataSize() const { diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index bd109f783f..7b90ba235d 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h @@ -25,22 +25,176 @@ struct LanguageEntry { std::string GetApplicationName() const; std::string GetDeveloperName() const; }; -static_assert(sizeof(LanguageEntry) == 0x300, "LanguageEntry has incorrect size."); +static_assert(sizeof(LanguageEntry) == 0x300); + +struct LanguageEntryData { + union { + // TitleDataFormat::Uncompressed (16 entries) + std::array language_entries; + + // TitleDataFormat::Compressed (18+ entries) + struct { + u16 buffer_size; + u8 buffer[0x2FFE]; + } compressed_data; + }; +}; + +enum class TitleDataFormat : u8 { + Uncompressed = 0, + Compressed = 1, +}; + +struct ApplicationNeighborDetectionGroupConfiguration { + u64 group_id; ///< GroupId + std::array key; +}; +static_assert(sizeof(ApplicationNeighborDetectionGroupConfiguration) == 0x18); + +// NeighborDetectionClientConfiguration +struct NeighborDetectionClientConfiguration { + ApplicationNeighborDetectionGroupConfiguration send_group_configuration; ///< SendGroupConfiguration + std::array receivable_group_configurations; ///< ReceivableGroupConfigurations +}; +static_assert(sizeof(NeighborDetectionClientConfiguration) == 0x198); + +enum class ApparentPlatform : u8 { + NX = 0, + Ounce = 1, + Count = 2 +}; + +enum class JitConfigurationFlag : u64 { + None = 0, + IsEnabled = 1, +}; + +struct JitConfiguration { + JitConfigurationFlag jit_configuration_flag; + u64 memory_size; +}; +static_assert(sizeof(JitConfiguration) == 0x10); + +enum RequiredAddOnContentsSetDescriptorFlag : u16 { + None = 0, + Continue = 1 +}; +struct RequiredAddOnContentsSetDescriptor { + u16 index : 15; + RequiredAddOnContentsSetDescriptorFlag flag : 1; +}; +static_assert(sizeof(RequiredAddOnContentsSetDescriptor) == 0x2); + +struct RequiredAddOnContentsSetBinaryDescriptor { + RequiredAddOnContentsSetDescriptor descriptors[0x20]; +}; +static_assert(sizeof(RequiredAddOnContentsSetBinaryDescriptor) == 0x40); + +enum class PlayReportPermission : u8 { + None = 0, + TargetMarketing = 1, +}; + +enum class CrashScreenshotForProd : u8 { + Deny = 0, + Allow = 1, +}; + +enum class CrashScreenshotForDev : u8 { + Deny = 0, + Allow = 1, +}; + +enum class ContentsAvailabilityTransitionPolicy : u8 { + NoPolicy = 0, + Stable = 1, + Changeable = 2, +}; + +struct AccessibleLaunchRequiredVersion { + std::array application_id; +}; +static_assert(sizeof(AccessibleLaunchRequiredVersion) == 0x40); + +enum class CrashReport : u8 { + Deny = 0, + Allow = 1, +}; + +enum class PlayLogQueryCapability : u8 { + None = 0, + WhiteList = 1, + All = 2, +}; + +struct ApplicationControlDataConditionData { + u8 priority; + INSERT_PADDING_BYTES(7); + u16 aoc_index; + INSERT_PADDING_BYTES(6); +}; +static_assert(sizeof(ApplicationControlDataConditionData) == 0x10); + +#pragma pack(push, 1) +struct ApplicationControlDataCondition { + u64 type; + std::array data; + u8 count; +}; +#pragma pack(pop) +static_assert(sizeof(ApplicationControlDataCondition) == 0x89); + +// A language on the NX. These are for names and icons. +#define NACP_LANGUAGE_LIST \ + NACP_LANGUAGE_ELEM(AmericanEnglish, 0) \ + NACP_LANGUAGE_ELEM(BritishEnglish, 1) \ + NACP_LANGUAGE_ELEM(Japanese, 2) \ + NACP_LANGUAGE_ELEM(French, 3) \ + NACP_LANGUAGE_ELEM(German, 4) \ + NACP_LANGUAGE_ELEM(LatinAmericanSpanish, 5) \ + NACP_LANGUAGE_ELEM(Spanish, 6) \ + NACP_LANGUAGE_ELEM(Italian, 7) \ + NACP_LANGUAGE_ELEM(Dutch, 8) \ + NACP_LANGUAGE_ELEM(CanadianFrench, 9) \ + NACP_LANGUAGE_ELEM(Portuguese, 10) \ + NACP_LANGUAGE_ELEM(Russian, 11) \ + NACP_LANGUAGE_ELEM(Korean, 12) \ + NACP_LANGUAGE_ELEM(TraditionalChinese, 13) \ + NACP_LANGUAGE_ELEM(SimplifiedChinese, 14) \ + NACP_LANGUAGE_ELEM(BrazilianPortuguese, 15) \ + NACP_LANGUAGE_ELEM(Polish, 16) \ + NACP_LANGUAGE_ELEM(Thai, 17) \ + +enum class Language : u8 { +#define NACP_LANGUAGE_ELEM(X, N) X = N, + NACP_LANGUAGE_LIST +#undef NACP_LANGUAGE_ELEM + Count = 18, + Default = 255, +}; + +// Yes it's duplicated, why? Bits i guess +enum class SupportedLanguage : u32 { +#define NACP_LANGUAGE_ELEM(X, N) X = 1ULL << N, + NACP_LANGUAGE_LIST +#undef NACP_LANGUAGE_ELEM +}; +#undef NACP_LANGUAGE_LIST // The raw file format of a NACP file. struct RawNACP { - std::array language_entries; + LanguageEntryData language_entries; std::array isbn; u8 startup_user_account; u8 user_account_switch_lock; u8 addon_content_registration_type; u32_le application_attribute; - u32_le supported_languages; + SupportedLanguage supported_languages; u32_le parental_control; bool screenshot_enabled; u8 video_capture_mode; bool data_loss_confirmation; - INSERT_PADDING_BYTES(1); + u8 play_log_policy; u64_le presence_group_id; std::array rating_age; std::array version_string; @@ -56,10 +210,14 @@ struct RawNACP { u8 logo_type; u8 logo_handling; bool runtime_add_on_content_install; - INSERT_PADDING_BYTES(5); + u8 runtime_parameter_delivery; + u8 appropriate_age_for_china; + INSERT_PADDING_BYTES(1); + CrashReport crash_report; u64_le seed_for_pseudo_device_id; std::array bcat_passphrase; - INSERT_PADDING_BYTES(7); + u8 startup_user_account_option; + INSERT_PADDING_BYTES(6); // ReservedForUserAccountSaveDataOperation u64_le user_account_save_data_max_size; u64_le user_account_save_data_max_journal_size; u64_le device_save_data_max_size; @@ -69,13 +227,28 @@ struct RawNACP { u64_le cache_storage_journal_size; u64_le cache_storage_data_and_journal_max_size; u16_le cache_storage_max_index; - INSERT_PADDING_BYTES(0x8B); + u8 runtime_upgrade; + u32_le supporting_limited_application_licenses; + std::array play_log_queryable_application_id; + PlayLogQueryCapability play_log_query_capability; + u8 repair_flag; + u8 program_index; + u8 required_network_service_license_on_launch_flag; u8 app_error_code_prefix; - INSERT_PADDING_BYTES(1); + TitleDataFormat titles_data_format; u8 acd_index; - u8 apparent_platform; - INSERT_PADDING_BYTES(0x22F); - std::array app_control_data_condition; + ApparentPlatform apparent_platform; + // NeighborDetectionClientConfiguration neighbor_detection_client_configuration; + // JitConfiguration jit_configuration; + // RequiredAddOnContentsSetBinaryDescriptor required_add_on_contents_set_binary_descriptor; + // PlayReportPermission play_report_permission; + // CrashScreenshotForProd crash_screenshot_for_prod; + // CrashScreenshotForDev crash_screenshot_for_dev; + // ContentsAvailabilityTransitionPolicy contents_availability_transition_policy; + // SupportedLanguage supported_language_copy; ///< TODO: add to XML generation. + INSERT_PADDING_BYTES(0x1EF); + AccessibleLaunchRequiredVersion accessible_launch_required_version; + ApplicationControlDataCondition application_control_data_condition; ///< Used for Switch 2 upgrade packs, which are distributed as AddOnContent titles u8 initial_program_index; INSERT_PADDING_BYTES(2); u32_le accessible_program_index_flags; @@ -85,34 +258,13 @@ struct RawNACP { u8 has_ingame_voice_chat; INSERT_PADDING_BYTES(3); u32_le supported_extra_addon_content_flag; - INSERT_PADDING_BYTES(0x698); + u8 has_karaoke_feature; + INSERT_PADDING_BYTES(0x697); std::array platform_specific_region; }; static_assert(sizeof(RawNACP) == 0x4000, "RawNACP has incorrect size."); -// A language on the NX. These are for names and icons. -enum class Language : u8 { - AmericanEnglish = 0, - BritishEnglish = 1, - Japanese = 2, - French = 3, - German = 4, - LatinAmericanSpanish = 5, - Spanish = 6, - Italian = 7, - Dutch = 8, - CanadianFrench = 9, - Portuguese = 10, - Russian = 11, - Korean = 12, - TraditionalChinese = 13, - SimplifiedChinese = 14, - BrazilianPortuguese = 15, - - Default = 255, -}; - -extern const std::array LANGUAGE_NAMES; +extern const std::array LANGUAGE_NAMES; // A class representing the format used by NX metadata files, typically named Control.nacp. // These store application name, dev name, title id, and other miscellaneous data. @@ -131,7 +283,7 @@ public: u64 GetDefaultNormalSaveSize() const; u64 GetDefaultJournalSaveSize() const; u32 GetSupportedLanguages() const; - std::array GetApplicationNames() const; + std::vector GetApplicationNames() const; std::vector GetRawBytes() const; bool GetUserAccountSwitchLock() const; u64 GetDeviceSaveDataSize() const; @@ -140,6 +292,7 @@ public: private: RawNACP raw{}; + std::vector language_entries; }; } // namespace FileSys diff --git a/src/core/hle/service/ns/language.cpp b/src/core/hle/service/ns/language.cpp index d187be935a..ff5ccdd6d3 100644 --- a/src/core/hle/service/ns/language.cpp +++ b/src/core/hle/service/ns/language.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -22,6 +25,8 @@ constexpr ApplicationLanguagePriorityList priority_list_american_english = {{ ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::TraditionalChinese, ApplicationLanguage::Korean, + ApplicationLanguage::Polish, + ApplicationLanguage::Thai, }}; constexpr ApplicationLanguagePriorityList priority_list_british_english = {{ @@ -40,6 +45,8 @@ constexpr ApplicationLanguagePriorityList priority_list_british_english = {{ ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::TraditionalChinese, ApplicationLanguage::Korean, + ApplicationLanguage::Polish, + ApplicationLanguage::Thai, }}; constexpr ApplicationLanguagePriorityList priority_list_japanese = {{ @@ -58,6 +65,8 @@ constexpr ApplicationLanguagePriorityList priority_list_japanese = {{ ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::TraditionalChinese, ApplicationLanguage::Korean, + ApplicationLanguage::Polish, + ApplicationLanguage::Thai, }}; constexpr ApplicationLanguagePriorityList priority_list_french = {{ @@ -76,6 +85,8 @@ constexpr ApplicationLanguagePriorityList priority_list_french = {{ ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::TraditionalChinese, ApplicationLanguage::Korean, + ApplicationLanguage::Polish, + ApplicationLanguage::Thai, }}; constexpr ApplicationLanguagePriorityList priority_list_german = {{ @@ -94,6 +105,8 @@ constexpr ApplicationLanguagePriorityList priority_list_german = {{ ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::TraditionalChinese, ApplicationLanguage::Korean, + ApplicationLanguage::Polish, + ApplicationLanguage::Thai, }}; constexpr ApplicationLanguagePriorityList priority_list_latin_american_spanish = {{ @@ -112,6 +125,8 @@ constexpr ApplicationLanguagePriorityList priority_list_latin_american_spanish = ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::TraditionalChinese, ApplicationLanguage::Korean, + ApplicationLanguage::Polish, + ApplicationLanguage::Thai, }}; constexpr ApplicationLanguagePriorityList priority_list_spanish = {{ @@ -130,6 +145,8 @@ constexpr ApplicationLanguagePriorityList priority_list_spanish = {{ ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::TraditionalChinese, ApplicationLanguage::Korean, + ApplicationLanguage::Polish, + ApplicationLanguage::Thai, }}; constexpr ApplicationLanguagePriorityList priority_list_italian = {{ @@ -148,6 +165,8 @@ constexpr ApplicationLanguagePriorityList priority_list_italian = {{ ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::TraditionalChinese, ApplicationLanguage::Korean, + ApplicationLanguage::Polish, + ApplicationLanguage::Thai, }}; constexpr ApplicationLanguagePriorityList priority_list_dutch = {{ @@ -166,6 +185,8 @@ constexpr ApplicationLanguagePriorityList priority_list_dutch = {{ ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::TraditionalChinese, ApplicationLanguage::Korean, + ApplicationLanguage::Polish, + ApplicationLanguage::Thai, }}; constexpr ApplicationLanguagePriorityList priority_list_canadian_french = {{ @@ -184,6 +205,8 @@ constexpr ApplicationLanguagePriorityList priority_list_canadian_french = {{ ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::TraditionalChinese, ApplicationLanguage::Korean, + ApplicationLanguage::Polish, + ApplicationLanguage::Thai, }}; constexpr ApplicationLanguagePriorityList priority_list_portuguese = {{ @@ -202,6 +225,8 @@ constexpr ApplicationLanguagePriorityList priority_list_portuguese = {{ ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::TraditionalChinese, ApplicationLanguage::Korean, + ApplicationLanguage::Polish, + ApplicationLanguage::Thai, }}; constexpr ApplicationLanguagePriorityList priority_list_russian = {{ @@ -220,6 +245,8 @@ constexpr ApplicationLanguagePriorityList priority_list_russian = {{ ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::TraditionalChinese, ApplicationLanguage::Korean, + ApplicationLanguage::Polish, + ApplicationLanguage::Thai, }}; constexpr ApplicationLanguagePriorityList priority_list_korean = {{ @@ -238,6 +265,8 @@ constexpr ApplicationLanguagePriorityList priority_list_korean = {{ ApplicationLanguage::Japanese, ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::TraditionalChinese, + ApplicationLanguage::Polish, + ApplicationLanguage::Thai, }}; constexpr ApplicationLanguagePriorityList priority_list_traditional_chinese = {{ @@ -256,6 +285,8 @@ constexpr ApplicationLanguagePriorityList priority_list_traditional_chinese = {{ ApplicationLanguage::Portuguese, ApplicationLanguage::Russian, ApplicationLanguage::Korean, + ApplicationLanguage::Polish, + ApplicationLanguage::Thai, }}; constexpr ApplicationLanguagePriorityList priority_list_simplified_chinese = {{ @@ -274,6 +305,8 @@ constexpr ApplicationLanguagePriorityList priority_list_simplified_chinese = {{ ApplicationLanguage::Portuguese, ApplicationLanguage::Russian, ApplicationLanguage::Korean, + ApplicationLanguage::Polish, + ApplicationLanguage::Thai, }}; constexpr ApplicationLanguagePriorityList priority_list_brazilian_portuguese = {{ @@ -293,6 +326,43 @@ constexpr ApplicationLanguagePriorityList priority_list_brazilian_portuguese = { ApplicationLanguage::Korean, ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::TraditionalChinese, + ApplicationLanguage::Polish, + ApplicationLanguage::Thai, +}}; + +constexpr ApplicationLanguagePriorityList priority_list_thai = {{ + ApplicationLanguage::Thai, + ApplicationLanguage::AmericanEnglish, + ApplicationLanguage::BritishEnglish, + ApplicationLanguage::Japanese, + ApplicationLanguage::French, + ApplicationLanguage::German, + ApplicationLanguage::Spanish, + ApplicationLanguage::Italian, + ApplicationLanguage::Dutch, + ApplicationLanguage::CanadianFrench, + ApplicationLanguage::Russian, + ApplicationLanguage::Korean, + ApplicationLanguage::SimplifiedChinese, + ApplicationLanguage::TraditionalChinese, + ApplicationLanguage::Polish, +}}; + +constexpr ApplicationLanguagePriorityList priority_list_polish = {{ + ApplicationLanguage::Polish, + ApplicationLanguage::AmericanEnglish, + ApplicationLanguage::BritishEnglish, + ApplicationLanguage::Japanese, + ApplicationLanguage::French, + ApplicationLanguage::German, + ApplicationLanguage::Spanish, + ApplicationLanguage::Italian, + ApplicationLanguage::Dutch, + ApplicationLanguage::CanadianFrench, + ApplicationLanguage::Russian, + ApplicationLanguage::Korean, + ApplicationLanguage::SimplifiedChinese, + ApplicationLanguage::TraditionalChinese, }}; const ApplicationLanguagePriorityList* GetApplicationLanguagePriorityList( @@ -330,6 +400,10 @@ const ApplicationLanguagePriorityList* GetApplicationLanguagePriorityList( return &priority_list_simplified_chinese; case ApplicationLanguage::BrazilianPortuguese: return &priority_list_brazilian_portuguese; + case ApplicationLanguage::Polish: + return &priority_list_polish; + case ApplicationLanguage::Thai: + return &priority_list_thai; default: return nullptr; } @@ -372,6 +446,10 @@ std::optional ConvertToApplicationLanguage( return ApplicationLanguage::SimplifiedChinese; case Set::LanguageCode::PT_BR: return ApplicationLanguage::BrazilianPortuguese; + case Set::LanguageCode::TH: + return ApplicationLanguage::Thai; + case Set::LanguageCode::PL: + return ApplicationLanguage::Polish; default: return std::nullopt; } @@ -411,6 +489,10 @@ std::optional ConvertToLanguageCode(const ApplicationLanguage return Set::LanguageCode::ZH_HANS; case ApplicationLanguage::BrazilianPortuguese: return Set::LanguageCode::PT_BR; + case ApplicationLanguage::Thai: + return Set::LanguageCode::TH; + case ApplicationLanguage::Polish: + return Set::LanguageCode::PL; default: return std::nullopt; } diff --git a/src/core/hle/service/ns/language.h b/src/core/hle/service/ns/language.h index dad9934f2e..d86f59df49 100644 --- a/src/core/hle/service/ns/language.h +++ b/src/core/hle/service/ns/language.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -26,6 +29,8 @@ enum class ApplicationLanguage : u8 { TraditionalChinese, SimplifiedChinese, BrazilianPortuguese, + Polish, + Thai, Count }; using ApplicationLanguagePriorityList = diff --git a/src/core/hle/service/set/settings_types.h b/src/core/hle/service/set/settings_types.h index 7f152cb523..469b8d745c 100644 --- a/src/core/hle/service/set/settings_types.h +++ b/src/core/hle/service/set/settings_types.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later @@ -169,6 +172,8 @@ enum class Language : u32 { SimplifiedCHhinese, TraditionalChinese, BrazilianPortuguese, + Polish, + Thai }; /// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64. @@ -191,6 +196,8 @@ enum class LanguageCode : u64 { ZH_HANS = 0x00736E61482D687A, ZH_HANT = 0x00746E61482D687A, PT_BR = 0x00000052422D7470, + PL = 0x000000000000706C, + TH = 0x0000000000006874, }; /// This is nn::settings::system::NotificationVolume @@ -248,7 +255,7 @@ enum class PlatformRegion : s32 { Terra = 2, }; -constexpr std::array available_language_codes = {{ +constexpr std::array available_language_codes = {{ LanguageCode::JA, LanguageCode::EN_US, LanguageCode::FR, @@ -267,9 +274,11 @@ constexpr std::array available_language_codes = {{ LanguageCode::ZH_HANS, LanguageCode::ZH_HANT, LanguageCode::PT_BR, + LanguageCode::PL, + LanguageCode::TH }}; -static constexpr std::array, 18> language_to_layout{{ +static constexpr std::array, 20> language_to_layout{{ {LanguageCode::JA, KeyboardLayout::Japanese}, {LanguageCode::EN_US, KeyboardLayout::EnglishUs}, {LanguageCode::FR, KeyboardLayout::French}, @@ -288,6 +297,8 @@ static constexpr std::array, 18> languag {LanguageCode::ZH_HANS, KeyboardLayout::ChineseSimplified}, {LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional}, {LanguageCode::PT_BR, KeyboardLayout::Portuguese}, + {LanguageCode::PL, KeyboardLayout::EnglishUsInternational}, + {LanguageCode::TH, KeyboardLayout::EnglishUsInternational} }}; /// This is nn::settings::system::AccountNotificationFlag diff --git a/src/qt_common/config/shared_translation.cpp b/src/qt_common/config/shared_translation.cpp index f4355197b0..9666092802 100644 --- a/src/qt_common/config/shared_translation.cpp +++ b/src/qt_common/config/shared_translation.cpp @@ -651,7 +651,8 @@ std::unique_ptr ComboboxEnumeration(QObject* parent) PAIR(Language, ChineseSimplified, tr("Simplified Chinese")), PAIR(Language, ChineseTraditional, tr("Traditional Chinese (正體中文)")), PAIR(Language, PortugueseBrazilian, tr("Brazilian Portuguese (português do Brasil)")), - PAIR(Language, Serbian, tr("Serbian (српски)")), + PAIR(Language, Polish, tr("Polish (polska)")), + PAIR(Language, Thai, tr("Thai (แบบไทย)")), }}); translations->insert({Settings::EnumMetadata::Index(), {