[common, hle] add new updates Polish+Thai languages (#3587)

Signed-off-by: lizzie <lizzie@eden-emu.dev>
Co-authored-by: maufeat <sahyno1996@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3587
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: DraVee <dravee@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
lizzie 2026-02-23 13:39:16 +01:00 committed by crueter
parent 963f9981ce
commit c610b61126
No known key found for this signature in database
GPG Key ID: 425ACD2D4830EBC6
9 changed files with 358 additions and 142 deletions

View File

@ -64,7 +64,8 @@
<item>@string/language_spanish</item>
<item>@string/language_taiwanese</item>
<item>@string/language_traditional_chinese</item>
<item>@string/language_serbian</item>
<item>@string/language_polish</item>
<item>@string/language_thai</item>
</string-array>
<integer-array name="languageValues">
@ -87,6 +88,7 @@
<item>11</item>
<item>16</item>
<item>18</item>
<item>19</item>
</integer-array>
<string-array name="rendererApiNames">
@ -407,6 +409,7 @@
<item>@string/app_language_persian</item>
<item>@string/app_language_hebrew</item>
<item>@string/app_language_serbian</item>
<item>@string/app_language_thai</item>
</string-array>
<integer-array name="appLanguageValues">
<item>0</item>

View File

@ -1011,7 +1011,8 @@
<string name="language_simplified_chinese" translatable="false">简体中文</string>
<string name="language_traditional_chinese" translatable="false">正體中文</string>
<string name="language_brazilian_portuguese" translatable="false">Português do Brasil</string>
<string name="language_serbian" translatable="false">српски</string>
<string name="language_polish" translatable="false">Polska</string>
<string name="language_thai" translatable="false">แบบไทย</string>
<!-- Memory Sizes -->
<string name="memory_byte_shorthand">B</string>
@ -1216,6 +1217,7 @@
<string name="app_language_persian" translatable="false">فارسی</string>
<string name="app_language_hebrew" translatable="false">עברית</string>
<string name="app_language_serbian" translatable="false">Српски</string>
<string name="app_language_thai" translatable="false">แบบไทย</string>
<!-- Static Themes -->
<string name="static_theme_color">Theme Color</string>

View File

@ -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,

View File

@ -12,6 +12,7 @@
#include <zlib.h>
#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<const char*, 16> LANGUAGE_NAMES{{
const std::array<const char*, size_t(Language::Count)> LANGUAGE_NAMES{{
"AmericanEnglish",
"BritishEnglish",
"Japanese",
@ -36,137 +37,95 @@ const std::array<const char*, 16> LANGUAGE_NAMES{{
"TraditionalChinese",
"SimplifiedChinese",
"BrazilianPortuguese",
"Polish",
"Thai",
}};
namespace {
constexpr std::size_t LEGACY_LANGUAGE_REGION_SIZE = sizeof(std::array<LanguageEntry, 16>);
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<const u8> compressed, std::vector<u8>& out) {
if (compressed.empty() || compressed.size() > std::numeric_limits<uInt>::max()) {
return false;
}
z_stream stream{};
stream.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef*>(compressed.data()));
stream.avail_in = static_cast<uInt>(compressed.size());
if (inflateInit2(&stream, -MAX_WBITS) != Z_OK) {
return false;
}
bool InflateRawDeflate(std::span<const u8> compressed, std::vector<u8>& out)
{
if (compressed.empty()) return false;
std::array<u8, 0x1000> chunk{};
int ret = Z_OK;
while (ret == Z_OK) {
stream.next_out = reinterpret_cast<Bytef*>(chunk.data());
stream.avail_out = static_cast<uInt>(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<Bytef*>(reinterpret_cast<const Bytef*>(compressed.data()));
stream.avail_in = static_cast<uInt>(compressed.size());
if (inflateInit2(&stream, -MAX_WBITS) != Z_OK) {
return false;
}
const auto produced = chunk.size() - static_cast<std::size_t>(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<std::ptrdiff_t>(produced));
out.resize(MAX_EXPANDED_LANG_SIZE);
stream.next_out = reinterpret_cast<Bytef*>(out.data());
stream.avail_out = static_cast<uInt>(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<u8*>(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<std::size_t>(compressed_size_le);
if (compressed_size == 0 || compressed_size > LEGACY_LANGUAGE_REGION_SIZE - sizeof(u16_le)) {
return;
}
std::vector<u8> decompressed;
if (!InflateRawDeflate(
std::span<const u8>(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, 18> 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<const u8> compressed_payload{raw.language_entries.compressed_data.buffer,
compressed_size};
std::vector<u8> 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<s32>(Settings::values.language_index.GetValue())];
u32 index = static_cast<u32>(Settings::values.language_index.GetValue());
{
const auto& language_entry = raw.language_entries.at(static_cast<u8>(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<u8>(Language::AmericanEnglish));
return language_entries.at(static_cast<u8>(Language::AmericanEnglish));
}
std::array<std::string, 16> NACP::GetApplicationNames() const {
std::array<std::string, 16> names{};
for (size_t i = 0; i < raw.language_entries.size(); ++i) {
names[i] = raw.language_entries[i].GetApplicationName();
std::vector<std::string> NACP::GetApplicationNames() const {
std::vector<std::string> 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 {

View File

@ -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<LanguageEntry, 16> 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<u8, 0x10> key;
};
static_assert(sizeof(ApplicationNeighborDetectionGroupConfiguration) == 0x18);
// NeighborDetectionClientConfiguration
struct NeighborDetectionClientConfiguration {
ApplicationNeighborDetectionGroupConfiguration send_group_configuration; ///< SendGroupConfiguration
std::array<ApplicationNeighborDetectionGroupConfiguration, 0x10> 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<u64, 8> 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<ApplicationControlDataConditionData, 0x8> 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<LanguageEntry, 16> language_entries;
LanguageEntryData language_entries;
std::array<u8, 0x25> 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<u8, 0x20> rating_age;
std::array<char, 0x10> 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<u8, 0x41> 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<u8, 0x8*16> 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<u8, 0x89> 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<u8, 0x400> 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<const char*, 16> LANGUAGE_NAMES;
extern const std::array<const char*, size_t(Language::Count)> 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<std::string, 16> GetApplicationNames() const;
std::vector<std::string> GetApplicationNames() const;
std::vector<u8> GetRawBytes() const;
bool GetUserAccountSwitchLock() const;
u64 GetDeviceSaveDataSize() const;
@ -140,6 +292,7 @@ public:
private:
RawNACP raw{};
std::vector<LanguageEntry> language_entries;
};
} // namespace FileSys

View File

@ -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<ApplicationLanguage> 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<Set::LanguageCode> 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;
}

View File

@ -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 =

View File

@ -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<LanguageCode, 18> available_language_codes = {{
constexpr std::array<LanguageCode, 20> available_language_codes = {{
LanguageCode::JA,
LanguageCode::EN_US,
LanguageCode::FR,
@ -267,9 +274,11 @@ constexpr std::array<LanguageCode, 18> available_language_codes = {{
LanguageCode::ZH_HANS,
LanguageCode::ZH_HANT,
LanguageCode::PT_BR,
LanguageCode::PL,
LanguageCode::TH
}};
static constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 18> language_to_layout{{
static constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 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<std::pair<LanguageCode, KeyboardLayout>, 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

View File

@ -651,7 +651,8 @@ std::unique_ptr<ComboboxTranslationMap> 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<Settings::Region>::Index(),
{