Browse Source

[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>
pull/3619/head
lizzie 2 weeks ago
committed by crueter
parent
commit
c610b61126
No known key found for this signature in database GPG Key ID: 425ACD2D4830EBC6
  1. 5
      src/android/app/src/main/res/values/arrays.xml
  2. 4
      src/android/app/src/main/res/values/strings.xml
  3. 2
      src/common/settings_enums.h
  4. 147
      src/core/file_sys/control_metadata.cpp
  5. 225
      src/core/file_sys/control_metadata.h
  6. 82
      src/core/hle/service/ns/language.cpp
  7. 5
      src/core/hle/service/ns/language.h
  8. 15
      src/core/hle/service/set/settings_types.h
  9. 3
      src/qt_common/config/shared_translation.cpp

5
src/android/app/src/main/res/values/arrays.xml

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

4
src/android/app/src/main/res/values/strings.xml

@ -1011,7 +1011,8 @@
<string name="language_simplified_chinese" translatable="false">简体中文</string> <string name="language_simplified_chinese" translatable="false">简体中文</string>
<string name="language_traditional_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_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 --> <!-- Memory Sizes -->
<string name="memory_byte_shorthand">B</string> <string name="memory_byte_shorthand">B</string>
@ -1216,6 +1217,7 @@
<string name="app_language_persian" translatable="false">فارسی</string> <string name="app_language_persian" translatable="false">فارسی</string>
<string name="app_language_hebrew" translatable="false">עברית</string> <string name="app_language_hebrew" translatable="false">עברית</string>
<string name="app_language_serbian" translatable="false">Српски</string> <string name="app_language_serbian" translatable="false">Српски</string>
<string name="app_language_thai" translatable="false">แบบไทย</string>
<!-- Static Themes --> <!-- Static Themes -->
<string name="static_theme_color">Theme Color</string> <string name="static_theme_color">Theme Color</string>

2
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, ENUM(Language, Japanese, EnglishAmerican, French, German, Italian, Spanish, Chinese, Korean, Dutch,
Portuguese, Russian, Taiwanese, EnglishBritish, FrenchCanadian, SpanishLatin, 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(Region, Japan, Usa, Europe, Australia, China, Korea, Taiwan);
ENUM(TimeZone, Auto, Default, Cet, Cst6Cdt, Cuba, Eet, Egypt, Eire, Est, Est5Edt, Gb, GbEire, Gmt, 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, GmtPlusZero, GmtMinusZero, GmtZero, Greenwich, Hongkong, Hst, Iceland, Iran, Israel, Jamaica,

147
src/core/file_sys/control_metadata.cpp

@ -12,6 +12,7 @@
#include <zlib.h> #include <zlib.h>
#include "common/settings.h" #include "common/settings.h"
#include "common/settings_enums.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "common/swap.h" #include "common/swap.h"
#include "core/file_sys/control_metadata.h" #include "core/file_sys/control_metadata.h"
@ -19,7 +20,7 @@
namespace FileSys { namespace FileSys {
const std::array<const char*, 16> LANGUAGE_NAMES{{
const std::array<const char*, size_t(Language::Count)> LANGUAGE_NAMES{{
"AmericanEnglish", "AmericanEnglish",
"BritishEnglish", "BritishEnglish",
"Japanese", "Japanese",
@ -36,16 +37,18 @@ const std::array<const char*, 16> LANGUAGE_NAMES{{
"TraditionalChinese", "TraditionalChinese",
"SimplifiedChinese", "SimplifiedChinese",
"BrazilianPortuguese", "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;
}
bool InflateRawDeflate(std::span<const u8> compressed, std::vector<u8>& out)
{
if (compressed.empty()) return false;
z_stream stream{}; z_stream stream{};
stream.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef*>(compressed.data())); stream.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef*>(compressed.data()));
@ -54,119 +57,75 @@ bool InflateRawDeflate(std::span<const u8> compressed, std::vector<u8>& out) {
return false; 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);
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); 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 (ret != Z_STREAM_END && ret != Z_OK) {
return false;
} }
if (decompressed.size() < LEGACY_LANGUAGE_REGION_SIZE ||
decompressed.size() % sizeof(LanguageEntry) != 0) {
return;
// Shrink to actual decompressed size
out.resize(stream.total_out);
return true;
} }
std::memcpy(raw.language_entries.data(), decompressed.data(), LEGACY_LANGUAGE_REGION_SIZE);
}
} // namespace } // namespace
std::string LanguageEntry::GetApplicationName() const { 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 { std::string LanguageEntry::GetDeveloperName() const {
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,
}};
return Common::StringFromFixedZeroTerminatedBuffer(developer_name.data(), developer_name.size());
}
NACP::NACP() = default; NACP::NACP() = default;
NACP::NACP(VirtualFile file) {
NACP::NACP(VirtualFile file)
{
file->ReadObject(&raw); 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; NACP::~NACP() = default;
const LanguageEntry& NACP::GetLanguageEntry() const { 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; return names;
} }
@ -205,7 +164,7 @@ bool NACP::GetUserAccountSwitchLock() const {
} }
u32 NACP::GetSupportedLanguages() const { u32 NACP::GetSupportedLanguages() const {
return raw.supported_languages;
return u32(raw.supported_languages);
} }
u64 NACP::GetDeviceSaveDataSize() const { u64 NACP::GetDeviceSaveDataSize() const {

225
src/core/file_sys/control_metadata.h

@ -25,22 +25,176 @@ struct LanguageEntry {
std::string GetApplicationName() const; std::string GetApplicationName() const;
std::string GetDeveloperName() 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. // The raw file format of a NACP file.
struct RawNACP { struct RawNACP {
std::array<LanguageEntry, 16> language_entries;
LanguageEntryData language_entries;
std::array<u8, 0x25> isbn; std::array<u8, 0x25> isbn;
u8 startup_user_account; u8 startup_user_account;
u8 user_account_switch_lock; u8 user_account_switch_lock;
u8 addon_content_registration_type; u8 addon_content_registration_type;
u32_le application_attribute; u32_le application_attribute;
u32_le supported_languages;
SupportedLanguage supported_languages;
u32_le parental_control; u32_le parental_control;
bool screenshot_enabled; bool screenshot_enabled;
u8 video_capture_mode; u8 video_capture_mode;
bool data_loss_confirmation; bool data_loss_confirmation;
INSERT_PADDING_BYTES(1);
u8 play_log_policy;
u64_le presence_group_id; u64_le presence_group_id;
std::array<u8, 0x20> rating_age; std::array<u8, 0x20> rating_age;
std::array<char, 0x10> version_string; std::array<char, 0x10> version_string;
@ -56,10 +210,14 @@ struct RawNACP {
u8 logo_type; u8 logo_type;
u8 logo_handling; u8 logo_handling;
bool runtime_add_on_content_install; 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; u64_le seed_for_pseudo_device_id;
std::array<u8, 0x41> bcat_passphrase; 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_size;
u64_le user_account_save_data_max_journal_size; u64_le user_account_save_data_max_journal_size;
u64_le device_save_data_max_size; u64_le device_save_data_max_size;
@ -69,13 +227,28 @@ struct RawNACP {
u64_le cache_storage_journal_size; u64_le cache_storage_journal_size;
u64_le cache_storage_data_and_journal_max_size; u64_le cache_storage_data_and_journal_max_size;
u16_le cache_storage_max_index; 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; u8 app_error_code_prefix;
INSERT_PADDING_BYTES(1);
TitleDataFormat titles_data_format;
u8 acd_index; 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; u8 initial_program_index;
INSERT_PADDING_BYTES(2); INSERT_PADDING_BYTES(2);
u32_le accessible_program_index_flags; u32_le accessible_program_index_flags;
@ -85,34 +258,13 @@ struct RawNACP {
u8 has_ingame_voice_chat; u8 has_ingame_voice_chat;
INSERT_PADDING_BYTES(3); INSERT_PADDING_BYTES(3);
u32_le supported_extra_addon_content_flag; 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; std::array<u8, 0x400> platform_specific_region;
}; };
static_assert(sizeof(RawNACP) == 0x4000, "RawNACP has incorrect size."); 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. // 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. // These store application name, dev name, title id, and other miscellaneous data.
@ -131,7 +283,7 @@ public:
u64 GetDefaultNormalSaveSize() const; u64 GetDefaultNormalSaveSize() const;
u64 GetDefaultJournalSaveSize() const; u64 GetDefaultJournalSaveSize() const;
u32 GetSupportedLanguages() const; u32 GetSupportedLanguages() const;
std::array<std::string, 16> GetApplicationNames() const;
std::vector<std::string> GetApplicationNames() const;
std::vector<u8> GetRawBytes() const; std::vector<u8> GetRawBytes() const;
bool GetUserAccountSwitchLock() const; bool GetUserAccountSwitchLock() const;
u64 GetDeviceSaveDataSize() const; u64 GetDeviceSaveDataSize() const;
@ -140,6 +292,7 @@ public:
private: private:
RawNACP raw{}; RawNACP raw{};
std::vector<LanguageEntry> language_entries;
}; };
} // namespace FileSys } // namespace FileSys

82
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-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -22,6 +25,8 @@ constexpr ApplicationLanguagePriorityList priority_list_american_english = {{
ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese, ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean, ApplicationLanguage::Korean,
ApplicationLanguage::Polish,
ApplicationLanguage::Thai,
}}; }};
constexpr ApplicationLanguagePriorityList priority_list_british_english = {{ constexpr ApplicationLanguagePriorityList priority_list_british_english = {{
@ -40,6 +45,8 @@ constexpr ApplicationLanguagePriorityList priority_list_british_english = {{
ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese, ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean, ApplicationLanguage::Korean,
ApplicationLanguage::Polish,
ApplicationLanguage::Thai,
}}; }};
constexpr ApplicationLanguagePriorityList priority_list_japanese = {{ constexpr ApplicationLanguagePriorityList priority_list_japanese = {{
@ -58,6 +65,8 @@ constexpr ApplicationLanguagePriorityList priority_list_japanese = {{
ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese, ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean, ApplicationLanguage::Korean,
ApplicationLanguage::Polish,
ApplicationLanguage::Thai,
}}; }};
constexpr ApplicationLanguagePriorityList priority_list_french = {{ constexpr ApplicationLanguagePriorityList priority_list_french = {{
@ -76,6 +85,8 @@ constexpr ApplicationLanguagePriorityList priority_list_french = {{
ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese, ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean, ApplicationLanguage::Korean,
ApplicationLanguage::Polish,
ApplicationLanguage::Thai,
}}; }};
constexpr ApplicationLanguagePriorityList priority_list_german = {{ constexpr ApplicationLanguagePriorityList priority_list_german = {{
@ -94,6 +105,8 @@ constexpr ApplicationLanguagePriorityList priority_list_german = {{
ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese, ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean, ApplicationLanguage::Korean,
ApplicationLanguage::Polish,
ApplicationLanguage::Thai,
}}; }};
constexpr ApplicationLanguagePriorityList priority_list_latin_american_spanish = {{ constexpr ApplicationLanguagePriorityList priority_list_latin_american_spanish = {{
@ -112,6 +125,8 @@ constexpr ApplicationLanguagePriorityList priority_list_latin_american_spanish =
ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese, ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean, ApplicationLanguage::Korean,
ApplicationLanguage::Polish,
ApplicationLanguage::Thai,
}}; }};
constexpr ApplicationLanguagePriorityList priority_list_spanish = {{ constexpr ApplicationLanguagePriorityList priority_list_spanish = {{
@ -130,6 +145,8 @@ constexpr ApplicationLanguagePriorityList priority_list_spanish = {{
ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese, ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean, ApplicationLanguage::Korean,
ApplicationLanguage::Polish,
ApplicationLanguage::Thai,
}}; }};
constexpr ApplicationLanguagePriorityList priority_list_italian = {{ constexpr ApplicationLanguagePriorityList priority_list_italian = {{
@ -148,6 +165,8 @@ constexpr ApplicationLanguagePriorityList priority_list_italian = {{
ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese, ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean, ApplicationLanguage::Korean,
ApplicationLanguage::Polish,
ApplicationLanguage::Thai,
}}; }};
constexpr ApplicationLanguagePriorityList priority_list_dutch = {{ constexpr ApplicationLanguagePriorityList priority_list_dutch = {{
@ -166,6 +185,8 @@ constexpr ApplicationLanguagePriorityList priority_list_dutch = {{
ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese, ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean, ApplicationLanguage::Korean,
ApplicationLanguage::Polish,
ApplicationLanguage::Thai,
}}; }};
constexpr ApplicationLanguagePriorityList priority_list_canadian_french = {{ constexpr ApplicationLanguagePriorityList priority_list_canadian_french = {{
@ -184,6 +205,8 @@ constexpr ApplicationLanguagePriorityList priority_list_canadian_french = {{
ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese, ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean, ApplicationLanguage::Korean,
ApplicationLanguage::Polish,
ApplicationLanguage::Thai,
}}; }};
constexpr ApplicationLanguagePriorityList priority_list_portuguese = {{ constexpr ApplicationLanguagePriorityList priority_list_portuguese = {{
@ -202,6 +225,8 @@ constexpr ApplicationLanguagePriorityList priority_list_portuguese = {{
ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese, ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean, ApplicationLanguage::Korean,
ApplicationLanguage::Polish,
ApplicationLanguage::Thai,
}}; }};
constexpr ApplicationLanguagePriorityList priority_list_russian = {{ constexpr ApplicationLanguagePriorityList priority_list_russian = {{
@ -220,6 +245,8 @@ constexpr ApplicationLanguagePriorityList priority_list_russian = {{
ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese, ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean, ApplicationLanguage::Korean,
ApplicationLanguage::Polish,
ApplicationLanguage::Thai,
}}; }};
constexpr ApplicationLanguagePriorityList priority_list_korean = {{ constexpr ApplicationLanguagePriorityList priority_list_korean = {{
@ -238,6 +265,8 @@ constexpr ApplicationLanguagePriorityList priority_list_korean = {{
ApplicationLanguage::Japanese, ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese, ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Polish,
ApplicationLanguage::Thai,
}}; }};
constexpr ApplicationLanguagePriorityList priority_list_traditional_chinese = {{ constexpr ApplicationLanguagePriorityList priority_list_traditional_chinese = {{
@ -256,6 +285,8 @@ constexpr ApplicationLanguagePriorityList priority_list_traditional_chinese = {{
ApplicationLanguage::Portuguese, ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian, ApplicationLanguage::Russian,
ApplicationLanguage::Korean, ApplicationLanguage::Korean,
ApplicationLanguage::Polish,
ApplicationLanguage::Thai,
}}; }};
constexpr ApplicationLanguagePriorityList priority_list_simplified_chinese = {{ constexpr ApplicationLanguagePriorityList priority_list_simplified_chinese = {{
@ -274,6 +305,8 @@ constexpr ApplicationLanguagePriorityList priority_list_simplified_chinese = {{
ApplicationLanguage::Portuguese, ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian, ApplicationLanguage::Russian,
ApplicationLanguage::Korean, ApplicationLanguage::Korean,
ApplicationLanguage::Polish,
ApplicationLanguage::Thai,
}}; }};
constexpr ApplicationLanguagePriorityList priority_list_brazilian_portuguese = {{ constexpr ApplicationLanguagePriorityList priority_list_brazilian_portuguese = {{
@ -293,6 +326,43 @@ constexpr ApplicationLanguagePriorityList priority_list_brazilian_portuguese = {
ApplicationLanguage::Korean, ApplicationLanguage::Korean,
ApplicationLanguage::SimplifiedChinese, ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese, 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( const ApplicationLanguagePriorityList* GetApplicationLanguagePriorityList(
@ -330,6 +400,10 @@ const ApplicationLanguagePriorityList* GetApplicationLanguagePriorityList(
return &priority_list_simplified_chinese; return &priority_list_simplified_chinese;
case ApplicationLanguage::BrazilianPortuguese: case ApplicationLanguage::BrazilianPortuguese:
return &priority_list_brazilian_portuguese; return &priority_list_brazilian_portuguese;
case ApplicationLanguage::Polish:
return &priority_list_polish;
case ApplicationLanguage::Thai:
return &priority_list_thai;
default: default:
return nullptr; return nullptr;
} }
@ -372,6 +446,10 @@ std::optional<ApplicationLanguage> ConvertToApplicationLanguage(
return ApplicationLanguage::SimplifiedChinese; return ApplicationLanguage::SimplifiedChinese;
case Set::LanguageCode::PT_BR: case Set::LanguageCode::PT_BR:
return ApplicationLanguage::BrazilianPortuguese; return ApplicationLanguage::BrazilianPortuguese;
case Set::LanguageCode::TH:
return ApplicationLanguage::Thai;
case Set::LanguageCode::PL:
return ApplicationLanguage::Polish;
default: default:
return std::nullopt; return std::nullopt;
} }
@ -411,6 +489,10 @@ std::optional<Set::LanguageCode> ConvertToLanguageCode(const ApplicationLanguage
return Set::LanguageCode::ZH_HANS; return Set::LanguageCode::ZH_HANS;
case ApplicationLanguage::BrazilianPortuguese: case ApplicationLanguage::BrazilianPortuguese:
return Set::LanguageCode::PT_BR; return Set::LanguageCode::PT_BR;
case ApplicationLanguage::Thai:
return Set::LanguageCode::TH;
case ApplicationLanguage::Polish:
return Set::LanguageCode::PL;
default: default:
return std::nullopt; return std::nullopt;
} }

5
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-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -26,6 +29,8 @@ enum class ApplicationLanguage : u8 {
TraditionalChinese, TraditionalChinese,
SimplifiedChinese, SimplifiedChinese,
BrazilianPortuguese, BrazilianPortuguese,
Polish,
Thai,
Count Count
}; };
using ApplicationLanguagePriorityList = using ApplicationLanguagePriorityList =

15
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-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
@ -169,6 +172,8 @@ enum class Language : u32 {
SimplifiedCHhinese, SimplifiedCHhinese,
TraditionalChinese, TraditionalChinese,
BrazilianPortuguese, BrazilianPortuguese,
Polish,
Thai
}; };
/// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64. /// 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_HANS = 0x00736E61482D687A,
ZH_HANT = 0x00746E61482D687A, ZH_HANT = 0x00746E61482D687A,
PT_BR = 0x00000052422D7470, PT_BR = 0x00000052422D7470,
PL = 0x000000000000706C,
TH = 0x0000000000006874,
}; };
/// This is nn::settings::system::NotificationVolume /// This is nn::settings::system::NotificationVolume
@ -248,7 +255,7 @@ enum class PlatformRegion : s32 {
Terra = 2, Terra = 2,
}; };
constexpr std::array<LanguageCode, 18> available_language_codes = {{
constexpr std::array<LanguageCode, 20> available_language_codes = {{
LanguageCode::JA, LanguageCode::JA,
LanguageCode::EN_US, LanguageCode::EN_US,
LanguageCode::FR, LanguageCode::FR,
@ -267,9 +274,11 @@ constexpr std::array<LanguageCode, 18> available_language_codes = {{
LanguageCode::ZH_HANS, LanguageCode::ZH_HANS,
LanguageCode::ZH_HANT, LanguageCode::ZH_HANT,
LanguageCode::PT_BR, 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::JA, KeyboardLayout::Japanese},
{LanguageCode::EN_US, KeyboardLayout::EnglishUs}, {LanguageCode::EN_US, KeyboardLayout::EnglishUs},
{LanguageCode::FR, KeyboardLayout::French}, {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_HANS, KeyboardLayout::ChineseSimplified},
{LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional}, {LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional},
{LanguageCode::PT_BR, KeyboardLayout::Portuguese}, {LanguageCode::PT_BR, KeyboardLayout::Portuguese},
{LanguageCode::PL, KeyboardLayout::EnglishUsInternational},
{LanguageCode::TH, KeyboardLayout::EnglishUsInternational}
}}; }};
/// This is nn::settings::system::AccountNotificationFlag /// This is nn::settings::system::AccountNotificationFlag

3
src/qt_common/config/shared_translation.cpp

@ -651,7 +651,8 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent)
PAIR(Language, ChineseSimplified, tr("Simplified Chinese")), PAIR(Language, ChineseSimplified, tr("Simplified Chinese")),
PAIR(Language, ChineseTraditional, tr("Traditional Chinese (正體中文)")), PAIR(Language, ChineseTraditional, tr("Traditional Chinese (正體中文)")),
PAIR(Language, PortugueseBrazilian, tr("Brazilian Portuguese (português do Brasil)")), 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(), translations->insert({Settings::EnumMetadata<Settings::Region>::Index(),
{ {

Loading…
Cancel
Save