i18n: Added translatable strings, new languages, and extended localization features.
- Added sub-keys to better manage long strings, allowing either the sub-key value or the original text to be used. - Multi-line values are now supported in language.json to prevent overly long single lines. - Added word-order adjustment for certain Asian languages such as Japanese and Korean. - Added separate support for Simplified and Traditional Chinese.
This commit is contained in:
@@ -5,10 +5,21 @@
|
|||||||
|
|
||||||
namespace sphaira::i18n {
|
namespace sphaira::i18n {
|
||||||
|
|
||||||
|
enum class WordOrder {
|
||||||
|
PhraseName, // default: SVO (English, French, German, etc.)
|
||||||
|
NamePhrase // SOV (Japanese, Korean)
|
||||||
|
};
|
||||||
|
|
||||||
bool init(long index);
|
bool init(long index);
|
||||||
void exit();
|
void exit();
|
||||||
|
|
||||||
std::string get(std::string_view str);
|
std::string get(std::string_view str);
|
||||||
|
std::string get(std::string_view str, std::string_view fallback);
|
||||||
|
|
||||||
|
WordOrder GetWordOrder();
|
||||||
|
bool WordOrderLocale();
|
||||||
|
|
||||||
|
std::string Reorder(std::string_view phrase, std::string_view name);
|
||||||
|
|
||||||
} // namespace sphaira::i18n
|
} // namespace sphaira::i18n
|
||||||
|
|
||||||
|
|||||||
@@ -839,9 +839,10 @@ void App::SetReplaceHbmenuEnable(bool enable) {
|
|||||||
NacpStruct actual_hbmenu_nacp;
|
NacpStruct actual_hbmenu_nacp;
|
||||||
if (R_FAILED(nro_get_nacp("/switch/hbmenu.nro", actual_hbmenu_nacp))) {
|
if (R_FAILED(nro_get_nacp("/switch/hbmenu.nro", actual_hbmenu_nacp))) {
|
||||||
App::Push<ui::OptionBox>(
|
App::Push<ui::OptionBox>(
|
||||||
"Failed to find /switch/hbmenu.nro\n"
|
i18n::get("missing_hbmenu_info",
|
||||||
"Use the Appstore to re-install hbmenu"_i18n,
|
"Failed to find /switch/hbmenu.nro\n"
|
||||||
"OK"_i18n
|
"Use the Appstore to re-install hbmenu"
|
||||||
|
), "OK"_i18n
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1960,18 +1961,23 @@ void App::DisplayThemeOptions(bool left_side) {
|
|||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>("Music"_i18n, App::GetThemeMusicEnable(), [](bool& enable){
|
options->Add<ui::SidebarEntryBool>("Music"_i18n, App::GetThemeMusicEnable(), [](bool& enable){
|
||||||
App::SetThemeMusicEnable(enable);
|
App::SetThemeMusicEnable(enable);
|
||||||
}, "Enable background music.\n"
|
}, i18n::get("bgm_enable_info",
|
||||||
"Each theme can have it's own music file. "
|
"Enable background music.\n"
|
||||||
"If a theme does not set a music file, the default music is loaded instead (if it exists)."_i18n);
|
"Each theme can have it's own music file. "
|
||||||
|
"If a theme does not set a music file, the default music is loaded instead (if it exists)."
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>("Show IP address"_i18n, App::GetApp()->m_show_ip_addr,
|
options->Add<ui::SidebarEntryBool>("Show IP address"_i18n, App::GetApp()->m_show_ip_addr,
|
||||||
"Shows the IP address in all menus, including the WiFi strength.\n\n"
|
i18n::get("display_ip_info",
|
||||||
"NOTE: The IP address will be hidden in applet mode due to the applet warning being displayed in it's place."_i18n
|
"Shows the IP address in all menus, including the WiFi strength.\n\n"
|
||||||
|
"NOTE: The IP address will be hidden in applet mode due to the applet warning being displayed in it's place."
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// todo: add file picker for music here.
|
// todo: add file picker for music here.
|
||||||
// todo: add array to audio which has the list of supported extensions.
|
// todo: add array to audio which has the list of supported extensions.
|
||||||
auto remove_music = options->Add<ui::SidebarEntryCallback>("Remove Background Music", [](){
|
auto remove_music = options->Add<ui::SidebarEntryCallback>("Remove Background Music"_i18n, [](){
|
||||||
g_app->m_default_music.Set("");
|
g_app->m_default_music.Set("");
|
||||||
audio::CloseSong(&g_app->m_background_music);
|
audio::CloseSong(&g_app->m_background_music);
|
||||||
}, "Removes the background music file"_i18n);
|
}, "Removes the background music file"_i18n);
|
||||||
@@ -2003,7 +2009,7 @@ void App::DisplayMenuOptions(bool left_side) {
|
|||||||
}, i18n::get(e.info));
|
}, i18n::get(e.info));
|
||||||
|
|
||||||
if (e.IsInstall()) {
|
if (e.IsInstall()) {
|
||||||
entry->Depends(App::GetInstallEnable, i18n::get(App::INSTALL_DEPENDS_STR), App::ShowEnableInstallPrompt);
|
entry->Depends(App::GetInstallEnable, i18n::get("enable_install_info", App::INSTALL_DEPENDS_STR), App::ShowEnableInstallPrompt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2033,8 +2039,10 @@ void App::DisplayMenuOptions(bool left_side) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
"Launch the built-in web browser.\n\n",
|
i18n::get("web_browser_info",
|
||||||
"NOTE: The browser is very limted, some websites will fail to load and there's a 30 minute timeout which closes the browser"_i18n);
|
"Launch the built-in web browser.\n\n"
|
||||||
|
"NOTE: The browser is very limted, some websites will fail to load and there's a 30 minute timeout which closes the browser"
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2064,18 +2072,21 @@ void App::DisplayAdvancedOptions(bool left_side) {
|
|||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>("Replace hbmenu on exit"_i18n, App::GetReplaceHbmenuEnable(), [](bool& enable){
|
options->Add<ui::SidebarEntryBool>("Replace hbmenu on exit"_i18n, App::GetReplaceHbmenuEnable(), [](bool& enable){
|
||||||
App::SetReplaceHbmenuEnable(enable);
|
App::SetReplaceHbmenuEnable(enable);
|
||||||
}, "When enabled, it replaces /hbmenu.nro with Sphaira, creating a backup of hbmenu to /switch/hbmenu.nro\n\n" \
|
}, i18n::get("hbmenu_replace_info",
|
||||||
"Disabling will give you the option to restore hbmenu."_i18n);
|
"When enabled, it replaces /hbmenu.nro with Sphaira, creating a backup of hbmenu to /switch/hbmenu.nro\n\n"
|
||||||
|
"Disabling will give you the option to restore hbmenu."));
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryCallback>("Add / modify mounts"_i18n, [](){
|
options->Add<ui::SidebarEntryCallback>("Add / modify mounts"_i18n, [](){
|
||||||
devoptab::DisplayDevoptabSideBar();
|
devoptab::DisplayDevoptabSideBar();
|
||||||
}, "Create, modify, delete network mounts (HTTP, FTP, SFTP, SMB, NFS).\n"
|
}, i18n::get("mount_options_info",
|
||||||
"Mount options only require a URL and Name be set, with other fields being optional, such as port, user, pass etc.\n\n"
|
"Create, modify, delete network mounts (HTTP, FTP, SFTP, SMB, NFS).\n"
|
||||||
"Any changes made will require restarting Sphaira to take effect."_i18n);
|
"Mount options only require a URL and Name be set, with other fields being optional, such as port, user, pass etc.\n\n"
|
||||||
|
"Any changes made will require restarting Sphaira to take effect."));
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>("Boost CPU during transfer"_i18n, App::GetApp()->m_progress_boost_mode,
|
options->Add<ui::SidebarEntryBool>("Boost CPU during transfer"_i18n, App::GetApp()->m_progress_boost_mode,
|
||||||
"Enables boost mode during transfers which can improve transfer speed. "
|
i18n::get("transfer_boost_info",
|
||||||
"This sets the CPU to 1785mhz and lowers the GPU 76mhz"_i18n);
|
"Enables boost mode during transfers which can improve transfer speed. "
|
||||||
|
"This sets the CPU to 1785mhz and lowers the GPU 76mhz"));
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryArray>("Text scroll speed"_i18n, text_scroll_speed_items, [](s64& index_out){
|
options->Add<ui::SidebarEntryArray>("Text scroll speed"_i18n, text_scroll_speed_items, [](s64& index_out){
|
||||||
App::SetTextScrollSpeed(index_out);
|
App::SetTextScrollSpeed(index_out);
|
||||||
@@ -2141,8 +2152,9 @@ void App::DisplayAdvancedOptions(bool left_side) {
|
|||||||
|
|
||||||
options->Add<ui::SidebarEntryCallback>("Install options"_i18n, [left_side](){
|
options->Add<ui::SidebarEntryCallback>("Install options"_i18n, [left_side](){
|
||||||
App::DisplayInstallOptions(left_side);
|
App::DisplayInstallOptions(left_side);
|
||||||
}, "Change the install options.\n"
|
}, i18n::get("install_options_info",
|
||||||
"You can enable installing from here."_i18n);
|
"Change the install options.\n"
|
||||||
|
"You can enable installing from here."));
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryCallback>("Export options"_i18n, [left_side](){
|
options->Add<ui::SidebarEntryCallback>("Export options"_i18n, [left_side](){
|
||||||
App::DisplayDumpOptions(left_side);
|
App::DisplayDumpOptions(left_side);
|
||||||
@@ -2194,46 +2206,54 @@ void App::DisplayInstallOptions(bool left_side) {
|
|||||||
"Skips installing tickets, not recommended."_i18n);
|
"Skips installing tickets, not recommended."_i18n);
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>("Skip NCA hash verify"_i18n, App::GetApp()->m_skip_nca_hash_verify,
|
options->Add<ui::SidebarEntryBool>("Skip NCA hash verify"_i18n, App::GetApp()->m_skip_nca_hash_verify,
|
||||||
"Enables the option to skip sha256 verification. This is a hash over the entire NCA. "
|
i18n::get("skip_nca_info",
|
||||||
"It is used to verify that the NCA is valid / not corrupted. "
|
"Enables the option to skip sha256 verification. This is a hash over the entire NCA. "
|
||||||
"You may have seen the option for \"checking for corrupted data\" when a corrupted game is installed. "
|
"It is used to verify that the NCA is valid / not corrupted. "
|
||||||
"That check performs various hash checks, including the hash over the NCA.\n\n"
|
"You may have seen the option for \"checking for corrupted data\" when a corrupted game is installed. "
|
||||||
"It is recommended to keep this disabled."_i18n);
|
"That check performs various hash checks, including the hash over the NCA.\n\n"
|
||||||
|
"It is recommended to keep this disabled."));
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>("Skip RSA header verify"_i18n, App::GetApp()->m_skip_rsa_header_fixed_key_verify,
|
options->Add<ui::SidebarEntryBool>("Skip RSA header verify"_i18n, App::GetApp()->m_skip_rsa_header_fixed_key_verify,
|
||||||
"Enables the option to skip RSA NCA fixed key verification. "
|
i18n::get("nca_verify_info",
|
||||||
"This is a hash over the NCA header. It is used to verify that the header has not been modified. "
|
"Enables the option to skip RSA NCA fixed key verification. "
|
||||||
"The header is signed by nintendo, thus it cannot be forged, and is reliable to detect modified NCA headers (such as NSP/XCI converts).\n\n"
|
"This is a hash over the NCA header. It is used to verify that the header has not been modified. "
|
||||||
"It is recommended to keep this disabled, unless you need to install nsp/xci converts."_i18n);
|
"The header is signed by nintendo, thus it cannot be forged, and is reliable to detect modified NCA headers (such as NSP/XCI converts).\n\n"
|
||||||
|
"It is recommended to keep this disabled, unless you need to install nsp/xci converts."));
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>("Skip RSA NPDM verify"_i18n, App::GetApp()->m_skip_rsa_npdm_fixed_key_verify,
|
options->Add<ui::SidebarEntryBool>("Skip RSA NPDM verify"_i18n, App::GetApp()->m_skip_rsa_npdm_fixed_key_verify,
|
||||||
"Enables the option to skip RSA NPDM fixed key verification.\n\n"
|
i18n::get("npdm_verify_info",
|
||||||
"Currently, this option is stubbed (not implemented)."_i18n);
|
"Enables the option to skip RSA NPDM fixed key verification.\n\n"
|
||||||
|
"Currently, this option is stubbed (not implemented)."));
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>("Ignore distribution bit"_i18n, App::GetApp()->m_ignore_distribution_bit,
|
options->Add<ui::SidebarEntryBool>("Ignore distribution bit"_i18n, App::GetApp()->m_ignore_distribution_bit,
|
||||||
"If set, it will ignore the distribution bit in the NCA header. "
|
i18n::get("nca_distbit_info",
|
||||||
"The distribution bit is used to signify whether a NCA is Eshop or GameCard. "
|
"If set, it will ignore the distribution bit in the NCA header. "
|
||||||
"You cannot (normally) launch install games that have the distruction bit set to GameCard.\n\n"
|
"The distribution bit is used to signify whether a NCA is Eshop or GameCard. "
|
||||||
"It is recommended to keep this disabled."_i18n);
|
"You cannot (normally) launch install games that have the distruction bit set to GameCard.\n\n"
|
||||||
|
"It is recommended to keep this disabled."));
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>("Convert to common ticket"_i18n, App::GetApp()->m_convert_to_common_ticket,
|
options->Add<ui::SidebarEntryBool>("Convert to common ticket"_i18n, App::GetApp()->m_convert_to_common_ticket,
|
||||||
"[Requires keys] Converts personalised tickets to common (fake) tickets.\n\n"
|
i18n::get("ticket_convert_info",
|
||||||
"It is recommended to keep this enabled."_i18n);
|
"[Requires keys] Converts personalised tickets to common (fake) tickets.\n\n"
|
||||||
|
"It is recommended to keep this enabled."));
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>("Convert to standard crypto"_i18n, App::GetApp()->m_convert_to_standard_crypto,
|
options->Add<ui::SidebarEntryBool>("Convert to standard crypto"_i18n, App::GetApp()->m_convert_to_standard_crypto,
|
||||||
"[Requires keys] Converts titlekey to standard crypto, also known as \"ticketless\".\n\n"
|
i18n::get("titlekey_crypto_info",
|
||||||
"It is recommended to keep this disabled."_i18n);
|
"[Requires keys] Converts titlekey to standard crypto, also known as \"ticketless\".\n\n"
|
||||||
|
"It is recommended to keep this disabled."));
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>("Lower master key"_i18n, App::GetApp()->m_lower_master_key,
|
options->Add<ui::SidebarEntryBool>("Lower master key"_i18n, App::GetApp()->m_lower_master_key,
|
||||||
"[Requires keys] Encrypts the keak (key area key) with master key 0, which allows the game to be launched on every fw. "
|
i18n::get("keyarea_crypto_info",
|
||||||
"Implicitly performs standard crypto.\n\n"
|
"[Requires keys] Encrypts the keak (key area key) with master key 0, which allows the game to be launched on every fw. "
|
||||||
"Do note that just because the game can be launched on any fw (as it can be decrypted), doesn't mean it will work. It is strongly recommened to update your firmware and Atmosphere version in order to play the game, rather than enabling this option.\n\n"
|
"Implicitly performs standard crypto.\n\n"
|
||||||
"It is recommended to keep this disabled."_i18n);
|
"Do note that just because the game can be launched on any fw (as it can be decrypted), doesn't mean it will work. It is strongly recommened to update your firmware and Atmosphere version in order to play the game, rather than enabling this option.\n\n"
|
||||||
|
"It is recommended to keep this disabled."));
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>("Lower system version"_i18n, App::GetApp()->m_lower_system_version,
|
options->Add<ui::SidebarEntryBool>("Lower system version"_i18n, App::GetApp()->m_lower_system_version,
|
||||||
"Sets the system_firmware field in the cnmt extended header to 0. "
|
i18n::get("cnmt_fw_info",
|
||||||
"Note: if the master key is higher than fw version, the game still won't launch as the fw won't have the key to decrypt keak (see above).\n\n"
|
"Sets the system_firmware field in the cnmt extended header to 0. "
|
||||||
"It is recommended to keep this disabled."_i18n);
|
"Note: if the master key is higher than fw version, the game still won't launch as the fw won't have the key to decrypt keak (see above).\n\n"
|
||||||
|
"It is recommended to keep this disabled."));
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::DisplayDumpOptions(bool left_side) {
|
void App::DisplayDumpOptions(bool left_side) {
|
||||||
@@ -2242,30 +2262,34 @@ void App::DisplayDumpOptions(bool left_side) {
|
|||||||
|
|
||||||
ui::SidebarEntryArray::Items nsz_level_items;
|
ui::SidebarEntryArray::Items nsz_level_items;
|
||||||
for (auto& e : NSZ_COMPRESS_LEVEL_OPTIONS) {
|
for (auto& e : NSZ_COMPRESS_LEVEL_OPTIONS) {
|
||||||
nsz_level_items.emplace_back(e.name);
|
nsz_level_items.emplace_back(i18n::get(e.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
ui::SidebarEntryArray::Items nsz_thread_items;
|
ui::SidebarEntryArray::Items nsz_thread_items;
|
||||||
for (auto& e : NSZ_COMPRESS_THREAD_OPTIONS) {
|
for (auto& e : NSZ_COMPRESS_THREAD_OPTIONS) {
|
||||||
nsz_thread_items.emplace_back(e.name);
|
nsz_thread_items.emplace_back(i18n::get(e.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
ui::SidebarEntryArray::Items nsz_block_items;
|
ui::SidebarEntryArray::Items nsz_block_items;
|
||||||
for (auto& e : NSZ_COMPRESS_BLOCK_OPTIONS) {
|
for (auto& e : NSZ_COMPRESS_BLOCK_OPTIONS) {
|
||||||
nsz_block_items.emplace_back(e.name);
|
nsz_block_items.emplace_back(i18n::get(e.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
"Created nested folder"_i18n, App::GetApp()->m_dump_app_folder,
|
"Created nested folder"_i18n, App::GetApp()->m_dump_app_folder,
|
||||||
"Creates a folder using the name of the game.\n"
|
i18n::get("game_folder_info",
|
||||||
"For example, /name/name.xci\n"
|
"Creates a folder using the name of the game.\n"
|
||||||
"Disabling this would use /name.xci"_i18n
|
"For example, /name/name.xci\n"
|
||||||
|
"Disabling this would use /name.xci"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
"Append folder with .xci"_i18n, App::GetApp()->m_dump_append_folder_with_xci,
|
"Append folder with .xci"_i18n, App::GetApp()->m_dump_append_folder_with_xci,
|
||||||
"XCI dumps will name the folder with the .xci extension.\n"
|
i18n::get("xci_folder_info",
|
||||||
"For example, /name.xci/name.xci\n\n"
|
"XCI dumps will name the folder with the .xci extension.\n"
|
||||||
"Some devices only function is the xci folder is named exactly the same as the xci."_i18n
|
"For example, /name.xci/name.xci\n\n"
|
||||||
|
"Some devices only function is the xci folder is named exactly the same as the xci."
|
||||||
|
)
|
||||||
);
|
);
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
"Trim XCI"_i18n, App::GetApp()->m_dump_trim_xci,
|
"Trim XCI"_i18n, App::GetApp()->m_dump_trim_xci,
|
||||||
@@ -2284,20 +2308,24 @@ void App::DisplayDumpOptions(bool left_side) {
|
|||||||
options->Add<ui::SidebarEntryArray>("NSZ level"_i18n, nsz_level_items, [](s64& index_out){
|
options->Add<ui::SidebarEntryArray>("NSZ level"_i18n, nsz_level_items, [](s64& index_out){
|
||||||
App::GetApp()->m_nsz_compress_level.Set(index_out);
|
App::GetApp()->m_nsz_compress_level.Set(index_out);
|
||||||
}, App::GetApp()->m_nsz_compress_level.Get(),
|
}, App::GetApp()->m_nsz_compress_level.Get(),
|
||||||
"Sets the compression level used when exporting to NSZ.\n\n"
|
i18n::get("compress_level_info",
|
||||||
"NOTE: The switch CPU is not very fast, and setting the value too high can "
|
"Sets the compression level used when exporting to NSZ.\n\n"
|
||||||
"result in exporting taking a very long time for very little gain in size.\n\n"
|
"NOTE: The switch CPU is not very fast, and setting the value too high can "
|
||||||
"It is recommended to set this value to 3."_i18n
|
"result in exporting taking a very long time for very little gain in size.\n\n"
|
||||||
|
"It is recommended to set this value to 3."
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryArray>("NSZ threads"_i18n, nsz_thread_items, [](s64& index_out){
|
options->Add<ui::SidebarEntryArray>("NSZ threads"_i18n, nsz_thread_items, [](s64& index_out){
|
||||||
App::GetApp()->m_nsz_compress_threads.Set(index_out);
|
App::GetApp()->m_nsz_compress_threads.Set(index_out);
|
||||||
}, App::GetApp()->m_nsz_compress_threads.Get(),
|
}, App::GetApp()->m_nsz_compress_threads.Get(),
|
||||||
"Sets the number of threads used when compression the NCA.\n\n"
|
i18n::get("compress_threads_info",
|
||||||
"A value less than 3 allows for another thread to run freely, such as read/write threads. "
|
"Sets the number of threads used when compression the NCA.\n\n"
|
||||||
"However in my testing, a value of 3 was usually the most performant.\n"
|
"A value less than 3 allows for another thread to run freely, such as read/write threads. "
|
||||||
"A value of 0 will use no threads and should only be used for testing as it is always slower.\n\n"
|
"However in my testing, a value of 3 was usually the most performant.\n"
|
||||||
"It is recommended to set this value between 1-3."_i18n
|
"A value of 0 will use no threads and should only be used for testing as it is always slower.\n\n"
|
||||||
|
"It is recommended to set this value between 1-3."
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
@@ -2307,9 +2335,11 @@ void App::DisplayDumpOptions(bool left_side) {
|
|||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
"NSZ block compression"_i18n, App::GetApp()->m_nsz_compress_block,
|
"NSZ block compression"_i18n, App::GetApp()->m_nsz_compress_block,
|
||||||
"Enables block compression, which compresses the NCA into blocks (at the cost of compression ratio) "
|
i18n::get("block_compress_info",
|
||||||
"which allows for random access, allowing the NCZ to be mounted as a file system.\n\n"
|
"Enables block compression, which compresses the NCA into blocks (at the cost of compression ratio) "
|
||||||
"NOTE: Sphaira does not yet support mounting NCZ as a file system, but it will be added evntually."_i18n
|
"which allows for random access, allowing the NCZ to be mounted as a file system.\n\n"
|
||||||
|
"NOTE: Sphaira does not yet support mounting NCZ as a file system, but it will be added evntually."
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
auto block_size_option = options->Add<ui::SidebarEntryArray>("NSZ block size"_i18n, nsz_block_items, [](s64& index_out){
|
auto block_size_option = options->Add<ui::SidebarEntryArray>("NSZ block size"_i18n, nsz_block_items, [](s64& index_out){
|
||||||
@@ -2338,7 +2368,7 @@ void App::DisplayFtpOptions(bool left_side) {
|
|||||||
}, "Enable FTP server to run in the background."_i18n);
|
}, "Enable FTP server to run in the background."_i18n);
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryTextInput>(
|
options->Add<ui::SidebarEntryTextInput>(
|
||||||
"Port", App::GetApp()->m_ftp_port.Get(), "", "", 1, 5,
|
"Port"_i18n, App::GetApp()->m_ftp_port.Get(), "", "", 1, 5,
|
||||||
"Opens the FTP server on this port."_i18n,
|
"Opens the FTP server on this port."_i18n,
|
||||||
[](auto* input){
|
[](auto* input){
|
||||||
App::GetApp()->m_ftp_port.Set(input->GetNumValue());
|
App::GetApp()->m_ftp_port.Set(input->GetNumValue());
|
||||||
@@ -2347,12 +2377,14 @@ void App::DisplayFtpOptions(bool left_side) {
|
|||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
"Anon"_i18n, App::GetApp()->m_ftp_anon,
|
"Anon"_i18n, App::GetApp()->m_ftp_anon,
|
||||||
"Allows you to login without setting a username and password.\n"
|
i18n::get("login_require_info",
|
||||||
"If disabled, you must set a user name and password below!"_i18n
|
"Allows you to login without setting a username and password.\n"
|
||||||
|
"If disabled, you must set a user name and password below!"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryTextInput>(
|
options->Add<ui::SidebarEntryTextInput>(
|
||||||
"User", App::GetApp()->m_ftp_user.Get(), "", "", -1, 64,
|
"User"_i18n, App::GetApp()->m_ftp_user.Get(), "", "", -1, 64,
|
||||||
"Sets the username, must be set if anon is disabled."_i18n,
|
"Sets the username, must be set if anon is disabled."_i18n,
|
||||||
[](auto* input){
|
[](auto* input){
|
||||||
App::GetApp()->m_ftp_user.Set(input->GetValue());
|
App::GetApp()->m_ftp_user.Set(input->GetValue());
|
||||||
@@ -2360,7 +2392,7 @@ void App::DisplayFtpOptions(bool left_side) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryTextInput>(
|
options->Add<ui::SidebarEntryTextInput>(
|
||||||
"Pass", App::GetApp()->m_ftp_pass.Get(), "", "", -1, 64,
|
"Pass"_i18n, App::GetApp()->m_ftp_pass.Get(), "", "", -1, 64,
|
||||||
"Sets the password, must be set if anon is disabled."_i18n,
|
"Sets the password, must be set if anon is disabled."_i18n,
|
||||||
[](auto* input){
|
[](auto* input){
|
||||||
App::GetApp()->m_ftp_pass.Set(input->GetValue());
|
App::GetApp()->m_ftp_pass.Set(input->GetValue());
|
||||||
@@ -2379,30 +2411,34 @@ void App::DisplayFtpOptions(bool left_side) {
|
|||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
"Show bis storage"_i18n, App::GetApp()->m_ftp_show_bis_storage,
|
"Show bis storage"_i18n, App::GetApp()->m_ftp_show_bis_storage,
|
||||||
"Shows the bis folder which contains the following:\n"
|
i18n::get("bis_contents_info",
|
||||||
"- BootPartition1Root.bin\n"
|
"Shows the bis folder which contains the following:\n"
|
||||||
"- BootPartition2Root.bin\n"
|
"- BootPartition1Root.bin\n"
|
||||||
"- UserDataRoot.bin\n"
|
"- BootPartition2Root.bin\n"
|
||||||
"- BootConfigAndPackage2Part1.bin\n"
|
"- UserDataRoot.bin\n"
|
||||||
"- BootConfigAndPackage2Part2.bin\n"
|
"- BootConfigAndPackage2Part1.bin\n"
|
||||||
"- BootConfigAndPackage2Part3.bin\n"
|
"- BootConfigAndPackage2Part2.bin\n"
|
||||||
"- BootConfigAndPackage2Part4.bin\n"
|
"- BootConfigAndPackage2Part3.bin\n"
|
||||||
"- BootConfigAndPackage2Part5.bin\n"
|
"- BootConfigAndPackage2Part4.bin\n"
|
||||||
"- BootConfigAndPackage2Part6.bin\n"
|
"- BootConfigAndPackage2Part5.bin\n"
|
||||||
"- CalibrationFile.bin\n"
|
"- BootConfigAndPackage2Part6.bin\n"
|
||||||
"- SafeMode.bin\n"
|
"- CalibrationFile.bin\n"
|
||||||
"- User.bin\n"
|
"- SafeMode.bin\n"
|
||||||
"- System.bin\n"
|
"- User.bin\n"
|
||||||
"- SystemProperEncryption.bin"_i18n
|
"- System.bin\n"
|
||||||
|
"- SystemProperEncryption.bin"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
"Show bis file systems"_i18n, App::GetApp()->m_ftp_show_bis_fs,
|
"Show bis file systems"_i18n, App::GetApp()->m_ftp_show_bis_fs,
|
||||||
"Shows the following bis file systems:\n"
|
i18n::get("bis_fs_info",
|
||||||
"- bis_calibration_file\n"
|
"Shows the following bis file systems:\n"
|
||||||
"- bis_safe_mode\n"
|
"- bis_calibration_file\n"
|
||||||
"- bis_user\n"
|
"- bis_safe_mode\n"
|
||||||
"- bis_system"_i18n
|
"- bis_user\n"
|
||||||
|
"- bis_system"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
@@ -2417,37 +2453,47 @@ void App::DisplayFtpOptions(bool left_side) {
|
|||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
"Show microSD contents"_i18n, App::GetApp()->m_ftp_show_content_sd,
|
"Show microSD contents"_i18n, App::GetApp()->m_ftp_show_content_sd,
|
||||||
"Shows the microSD contents folder.\n\n"
|
i18n::get("microsd_contents_info",
|
||||||
"NOTE: This is not the normal microSD card storage, it is instead "
|
"Shows the microSD contents folder.\n\n"
|
||||||
"the location where NCA's are stored. The normal microSD card is always mounted."_i18n
|
"NOTE: This is not the normal microSD card storage, it is instead "
|
||||||
|
"the location where NCA's are stored. The normal microSD card is always mounted."
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
"Show games"_i18n, App::GetApp()->m_ftp_show_games,
|
"Show games"_i18n, App::GetApp()->m_ftp_show_games,
|
||||||
"Shows the games folder.\n\n"
|
i18n::get("games_ftp_info",
|
||||||
"This folder contains all of your installed games, allowing you to create "
|
"Shows the games folder.\n\n"
|
||||||
"backups over FTP!\n\n"
|
"This folder contains all of your installed games, allowing you to create "
|
||||||
"NOTE: This folder is read-only. You cannot delete games over FTP."_i18n
|
"backups over FTP!\n\n"
|
||||||
|
"NOTE: This folder is read-only. You cannot delete games over FTP."
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
"Show install"_i18n, App::GetApp()->m_ftp_show_install,
|
"Show install"_i18n, App::GetApp()->m_ftp_show_install,
|
||||||
"Shows the install folder.\n\n"
|
i18n::get("install_ftp_info",
|
||||||
"This folder is used for installing games via FTP.\n\n"
|
"Shows the install folder.\n\n"
|
||||||
"NOTE: You must open the \"FTP Install\" menu when trying to install a game!"_i18n
|
"This folder is used for installing games via FTP.\n\n"
|
||||||
|
"NOTE: You must open the \"FTP Install\" menu when trying to install a game!"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
"Show mounts"_i18n, App::GetApp()->m_ftp_show_mounts,
|
"Show mounts"_i18n, App::GetApp()->m_ftp_show_mounts,
|
||||||
"Shows the mounts folder.\n\n"
|
i18n::get("mounts_ftp_info",
|
||||||
"This folder is contains all of the mounts added to Sphaira, allowing you to acces them over FTP!\n"
|
"Shows the mounts folder.\n\n"
|
||||||
"For example, you can access your SMB, WebDav or other FTP mounts over FTP."_i18n
|
"This folder is contains all of the mounts added to Sphaira, allowing you to acces them over FTP!\n"
|
||||||
|
"For example, you can access your SMB, WebDav or other FTP mounts over FTP."
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
"Show switch"_i18n, App::GetApp()->m_ftp_show_switch,
|
"Show switch"_i18n, App::GetApp()->m_ftp_show_switch,
|
||||||
"Shows the shortcut for the /switch folder."
|
i18n::get("homebrew_folder_info",
|
||||||
"This is the folder that contains all your homebrew (NRO's)."_i18n
|
"Shows the shortcut for the /switch folder."
|
||||||
|
"This is the folder that contains all your homebrew (NRO's)."
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2473,13 +2519,15 @@ void App::DisplayMtpOptions(bool left_side) {
|
|||||||
#if 0
|
#if 0
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
"Pre-allocate file"_i18n, App::GetApp()->m_mtp_allocate_file,
|
"Pre-allocate file"_i18n, App::GetApp()->m_mtp_allocate_file,
|
||||||
"Enables pre-allocating the file size before writing.\n"
|
i18n::get("prealloc_info",
|
||||||
"This speeds up file writes, however, this can cause timeouts if all these conditions are met:\n"
|
"Enables pre-allocating the file size before writing.\n"
|
||||||
"- using Windows\n"
|
"This speeds up file writes, however, this can cause timeouts if all these conditions are met:\n"
|
||||||
"- using emuMMC\n"
|
"- using Windows\n"
|
||||||
"- transferring a large file (>1GB)\n\n"
|
"- using emuMMC\n"
|
||||||
"This option should be left enabled, however if you use the above and experience timeouts, "
|
"- transferring a large file (>1GB)\n\n"
|
||||||
"then try again with this option disabled."_i18n
|
"This option should be left enabled, however if you use the above and experience timeouts, "
|
||||||
|
"then try again with this option disabled."
|
||||||
|
)
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -2490,9 +2538,11 @@ void App::DisplayMtpOptions(bool left_side) {
|
|||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
"Show microSD contents"_i18n, App::GetApp()->m_mtp_show_content_sd,
|
"Show microSD contents"_i18n, App::GetApp()->m_mtp_show_content_sd,
|
||||||
"Shows the microSD contents folder.\n\n"
|
i18n::get("microsd_contents_info",
|
||||||
"NOTE: This is not the normal microSD card storage, it is instead "
|
"Shows the microSD contents folder.\n\n"
|
||||||
"the location where NCA's are stored. The normal microSD card is always mounted."_i18n
|
"NOTE: This is not the normal microSD card storage, it is instead "
|
||||||
|
"the location where NCA's are stored. The normal microSD card is always mounted."
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
@@ -2507,31 +2557,39 @@ void App::DisplayMtpOptions(bool left_side) {
|
|||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
"Show games"_i18n, App::GetApp()->m_mtp_show_games,
|
"Show games"_i18n, App::GetApp()->m_mtp_show_games,
|
||||||
"Shows the games folder.\n\n"
|
i18n::get("games_mtp_info",
|
||||||
"This folder contains all of your installed games, allowing you to create "
|
"Shows the games folder.\n\n"
|
||||||
"backups over MTP!\n\n"
|
"This folder contains all of your installed games, allowing you to create "
|
||||||
"NOTE: This folder is read-only. You cannot delete games over MTP."_i18n
|
"backups over MTP!\n\n"
|
||||||
|
"NOTE: This folder is read-only. You cannot delete games over MTP."
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
"Show install"_i18n, App::GetApp()->m_mtp_show_install,
|
"Show install"_i18n, App::GetApp()->m_mtp_show_install,
|
||||||
"Shows the install folder.\n\n"
|
i18n::get("install_mtp_info",
|
||||||
"This folder is used for installing games via MTP.\n\n"
|
"Shows the install folder.\n\n"
|
||||||
"NOTE: You must open the \"MTP Install\" menu when trying to install a game!"_i18n
|
"This folder is used for installing games via MTP.\n\n"
|
||||||
|
"NOTE: You must open the \"MTP Install\" menu when trying to install a game!"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
"Show mounts"_i18n, App::GetApp()->m_mtp_show_mounts,
|
"Show mounts"_i18n, App::GetApp()->m_mtp_show_mounts,
|
||||||
"Shows the mounts folder.\n\n"
|
i18n::get("mounts_mtp_info",
|
||||||
"This folder is contains all of the mounts added to Sphaira, allowing you to acces them over MTP!\n"
|
"Shows the mounts folder.\n\n"
|
||||||
"For example, you can access your SMB, WebDav and FTP mounts over MTP."_i18n
|
"This folder is contains all of the mounts added to Sphaira, allowing you to acces them over MTP!\n"
|
||||||
|
"For example, you can access your SMB, WebDav and FTP mounts over MTP."
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>(
|
options->Add<ui::SidebarEntryBool>(
|
||||||
"Show DevNull"_i18n, App::GetApp()->m_mtp_show_speedtest,
|
"Show DevNull"_i18n, App::GetApp()->m_mtp_show_speedtest,
|
||||||
"Shows the DevNull (Speed Test) folder.\n\n"
|
i18n::get("usb_benchmark_info",
|
||||||
"This folder is used for benchmarking USB uploads. "
|
"Shows the DevNull (Speed Test) folder.\n\n"
|
||||||
"This ia virtual folder, nothing is actally written to disk."_i18n
|
"This folder is used for benchmarking USB uploads. "
|
||||||
|
"This ia virtual folder, nothing is actally written to disk."
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2541,8 +2599,10 @@ void App::DisplayHddOptions(bool left_side) {
|
|||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>("Enable"_i18n, App::GetHddEnable(), [](bool& enable){
|
options->Add<ui::SidebarEntryBool>("Enable"_i18n, App::GetHddEnable(), [](bool& enable){
|
||||||
App::SetHddEnable(enable);
|
App::SetHddEnable(enable);
|
||||||
}, "Enable mounting of connected USB/HDD devices. "
|
}, i18n::get("mount_hdd_info",
|
||||||
"Connected devices can be used in the FileBrowser, as well as a backup location when dumping games and saves."_i18n
|
"Enable mounting of connected USB/HDD devices. "
|
||||||
|
"Connected devices can be used in the FileBrowser, as well as a backup location when dumping games and saves."
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
options->Add<ui::SidebarEntryBool>("HDD write protect"_i18n, App::GetWriteProtect(), [](bool& enable){
|
options->Add<ui::SidebarEntryBool>("HDD write protect"_i18n, App::GetWriteProtect(), [](bool& enable){
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ Result DumpToUsb(ui::ProgressBox* pbox, BaseSource* source, std::span<const fs::
|
|||||||
const auto file_size = source->GetSize(path);
|
const auto file_size = source->GetSize(path);
|
||||||
pbox->SetImage(source->GetIcon(path));
|
pbox->SetImage(source->GetIcon(path));
|
||||||
pbox->SetTitle(source->GetName(path));
|
pbox->SetTitle(source->GetName(path));
|
||||||
pbox->NewTransfer("Waiting for USB connection...");
|
pbox->NewTransfer("Waiting for USB connection..."_i18n);
|
||||||
|
|
||||||
// wait until usb is ready.
|
// wait until usb is ready.
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|||||||
@@ -14,42 +14,86 @@ yyjson_val* root{};
|
|||||||
std::unordered_map<std::string, std::string> g_tr_cache{};
|
std::unordered_map<std::string, std::string> g_tr_cache{};
|
||||||
Mutex g_mutex{};
|
Mutex g_mutex{};
|
||||||
|
|
||||||
std::string get_internal(std::string_view str) {
|
static WordOrder g_word_order = WordOrder::PhraseName;
|
||||||
|
|
||||||
|
static WordOrder DetectWordOrder(const std::string& lang) {
|
||||||
|
// SOV Language.
|
||||||
|
if (lang == "ja" || lang == "ko")
|
||||||
|
return WordOrder::NamePhrase;
|
||||||
|
|
||||||
|
// Default: SVO Language.
|
||||||
|
return WordOrder::PhraseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string get_internal(std::string_view str, std::string_view fallback) {
|
||||||
SCOPED_MUTEX(&g_mutex);
|
SCOPED_MUTEX(&g_mutex);
|
||||||
|
|
||||||
const std::string kkey = {str.data(), str.length()};
|
const std::string kkey{str.data(), str.length()};
|
||||||
|
|
||||||
if (auto it = g_tr_cache.find(kkey); it != g_tr_cache.end()) {
|
if (auto it = g_tr_cache.find(kkey); it != g_tr_cache.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add default entry
|
// add default entry
|
||||||
const auto it = g_tr_cache.emplace(kkey, kkey).first;
|
const auto it = g_tr_cache.emplace(kkey, std::string{fallback}).first;
|
||||||
|
|
||||||
if (!json || !root) {
|
if (!json || !root) {
|
||||||
log_write("no json or root\n");
|
log_write("no json or root\n");
|
||||||
return kkey;
|
return std::string{fallback};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto key = yyjson_obj_getn(root, str.data(), str.length());
|
yyjson_val* node = yyjson_obj_getn(root, str.data(), str.length());
|
||||||
if (!key) {
|
if (!node && str != fallback) {
|
||||||
|
node = yyjson_obj_getn(root, fallback.data(), fallback.length());
|
||||||
|
if (node) {
|
||||||
|
log_write("\tfallback-key matched: [%s]\n", std::string(fallback).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
log_write("\tfailed to find key: [%s]\n", kkey.c_str());
|
log_write("\tfailed to find key: [%s]\n", kkey.c_str());
|
||||||
return kkey;
|
return std::string{fallback};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto val = yyjson_get_str(key);
|
std::string ret;
|
||||||
auto val_len = yyjson_get_len(key);
|
|
||||||
if (!val || !val_len) {
|
// key > string
|
||||||
|
if (const char* val = yyjson_get_str(node)) {
|
||||||
|
size_t len = yyjson_get_len(node);
|
||||||
|
if (len) {
|
||||||
|
ret.assign(val, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// key > array of strings (multi-line)
|
||||||
|
if (ret.empty() && yyjson_is_arr(node)) {
|
||||||
|
size_t idx, max;
|
||||||
|
yyjson_val* elem;
|
||||||
|
yyjson_arr_foreach(node, idx, max, elem) {
|
||||||
|
if (idx) ret.push_back('\n');
|
||||||
|
|
||||||
|
if (yyjson_is_str(elem)) {
|
||||||
|
const char* s = yyjson_get_str(elem);
|
||||||
|
size_t len = yyjson_get_len(elem);
|
||||||
|
if (s && len) ret.append(s, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret.empty()) {
|
||||||
log_write("\tfailed to get value: [%s]\n", kkey.c_str());
|
log_write("\tfailed to get value: [%s]\n", kkey.c_str());
|
||||||
return kkey;
|
ret = std::string{fallback};
|
||||||
}
|
}
|
||||||
|
|
||||||
// update entry in cache
|
// update entry in cache
|
||||||
const std::string ret = {val, val_len};
|
|
||||||
g_tr_cache.insert_or_assign(it, kkey, ret);
|
g_tr_cache.insert_or_assign(it, kkey, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string get_internal(std::string_view str) {
|
||||||
|
return get_internal(str, str);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool init(long index) {
|
bool init(long index) {
|
||||||
@@ -76,14 +120,15 @@ bool init(long index) {
|
|||||||
case 4: setLanguage = SetLanguage_DE; break; // "German"
|
case 4: setLanguage = SetLanguage_DE; break; // "German"
|
||||||
case 5: setLanguage = SetLanguage_IT; break; // "Italian"
|
case 5: setLanguage = SetLanguage_IT; break; // "Italian"
|
||||||
case 6: setLanguage = SetLanguage_ES; break; // "Spanish"
|
case 6: setLanguage = SetLanguage_ES; break; // "Spanish"
|
||||||
case 7: setLanguage = SetLanguage_ZHCN; break; // "Chinese"
|
case 7: setLanguage = SetLanguage_ZHCN; break; // "Chinese (Simplified)"
|
||||||
case 8: setLanguage = SetLanguage_KO; break; // "Korean"
|
case 8: setLanguage = SetLanguage_KO; break; // "Korean"
|
||||||
case 9: setLanguage = SetLanguage_NL; break; // "Dutch"
|
case 9: setLanguage = SetLanguage_NL; break; // "Dutch"
|
||||||
case 10: setLanguage = SetLanguage_PT; break; // "Portuguese"
|
case 10: setLanguage = SetLanguage_PT; break; // "Portuguese"
|
||||||
case 11: setLanguage = SetLanguage_RU; break; // "Russian"
|
case 11: setLanguage = SetLanguage_RU; break; // "Russian"
|
||||||
case 12: lang_name = "se"; break; // "Swedish"
|
case 12: setLanguage = SetLanguage_ZHTW; break; // "Chinese (Traditional)"
|
||||||
case 13: lang_name = "vi"; break; // "Vietnamese"
|
case 13: lang_name = "se"; break; // "Swedish"
|
||||||
case 14: lang_name = "uk"; break; // "Ukrainian"
|
case 14: lang_name = "vi"; break; // "Vietnamese"
|
||||||
|
case 15: lang_name = "uk"; break; // "Ukrainian"
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (setLanguage) {
|
switch (setLanguage) {
|
||||||
@@ -92,15 +137,17 @@ bool init(long index) {
|
|||||||
case SetLanguage_DE: lang_name = "de"; break;
|
case SetLanguage_DE: lang_name = "de"; break;
|
||||||
case SetLanguage_IT: lang_name = "it"; break;
|
case SetLanguage_IT: lang_name = "it"; break;
|
||||||
case SetLanguage_ES: lang_name = "es"; break;
|
case SetLanguage_ES: lang_name = "es"; break;
|
||||||
case SetLanguage_ZHCN: lang_name = "zh"; break;
|
case SetLanguage_ZHCN: lang_name = "zh-CN"; break;
|
||||||
case SetLanguage_KO: lang_name = "ko"; break;
|
case SetLanguage_KO: lang_name = "ko"; break;
|
||||||
case SetLanguage_NL: lang_name = "nl"; break;
|
case SetLanguage_NL: lang_name = "nl"; break;
|
||||||
case SetLanguage_PT: lang_name = "pt"; break;
|
case SetLanguage_PT: lang_name = "pt"; break;
|
||||||
case SetLanguage_RU: lang_name = "ru"; break;
|
case SetLanguage_RU: lang_name = "ru"; break;
|
||||||
case SetLanguage_ZHTW: lang_name = "zh"; break;
|
case SetLanguage_ZHTW: lang_name = "zh-TW"; break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_word_order = DetectWordOrder(lang_name);
|
||||||
|
|
||||||
const fs::FsPath sdmc_path = "/config/sphaira/i18n/" + lang_name + ".json";
|
const fs::FsPath sdmc_path = "/config/sphaira/i18n/" + lang_name + ".json";
|
||||||
const fs::FsPath romfs_path = "romfs:/i18n/" + lang_name + ".json";
|
const fs::FsPath romfs_path = "romfs:/i18n/" + lang_name + ".json";
|
||||||
fs::FsPath path = sdmc_path;
|
fs::FsPath path = sdmc_path;
|
||||||
@@ -138,6 +185,7 @@ void exit() {
|
|||||||
if (json) {
|
if (json) {
|
||||||
yyjson_doc_free(json);
|
yyjson_doc_free(json);
|
||||||
json = nullptr;
|
json = nullptr;
|
||||||
|
root = nullptr;
|
||||||
}
|
}
|
||||||
g_i18n_data.clear();
|
g_i18n_data.clear();
|
||||||
}
|
}
|
||||||
@@ -146,12 +194,40 @@ std::string get(std::string_view str) {
|
|||||||
return get_internal(str);
|
return get_internal(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string get(std::string_view str, std::string_view fallback) {
|
||||||
|
return get_internal(str, fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reorders sentence structure based on locale.
|
||||||
|
WordOrder GetWordOrder() {
|
||||||
|
return g_word_order;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WordOrderLocale() {
|
||||||
|
return g_word_order == WordOrder::NamePhrase;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Reorder(std::string_view phrase, std::string_view name) {
|
||||||
|
std::string p = i18n::get(phrase);
|
||||||
|
std::string out;
|
||||||
|
out.reserve(phrase.length() + name.length());
|
||||||
|
|
||||||
|
if (g_word_order == WordOrder::NamePhrase) {
|
||||||
|
out.append(name);
|
||||||
|
out.append(p);
|
||||||
|
} else {
|
||||||
|
out.append(p);
|
||||||
|
out.append(name);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace sphaira::i18n
|
} // namespace sphaira::i18n
|
||||||
|
|
||||||
namespace literals {
|
namespace literals {
|
||||||
|
|
||||||
std::string operator""_i18n(const char* str, size_t len) {
|
std::string operator""_i18n(const char* str, size_t len) {
|
||||||
return sphaira::i18n::get_internal({str, len});
|
return sphaira::i18n::get({str, len});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace literals
|
} // namespace literals
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "fs.hpp"
|
#include "fs.hpp"
|
||||||
#include "app.hpp"
|
#include "app.hpp"
|
||||||
#include "utils/devoptab.hpp"
|
#include "utils/devoptab.hpp"
|
||||||
|
#include "i18n.hpp"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ auto GetStdio(bool write) -> StdioEntries {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (e.flags & FsEntryFlag::FsEntryFlag_ReadOnly) {
|
if (e.flags & FsEntryFlag::FsEntryFlag_ReadOnly) {
|
||||||
e.name += " (Read Only)";
|
e.name += i18n::get(" (Read Only)");
|
||||||
}
|
}
|
||||||
|
|
||||||
out.emplace_back(e);
|
out.emplace_back(e);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "yati/nx/ncm.hpp"
|
#include "yati/nx/ncm.hpp"
|
||||||
|
|
||||||
#include "utils/thread.hpp"
|
#include "utils/thread.hpp"
|
||||||
|
#include "i18n.hpp"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
@@ -113,8 +114,8 @@ auto& GetNcmEntry(u8 storage_id) {
|
|||||||
void FakeNacpEntry(ThreadResultData* e) {
|
void FakeNacpEntry(ThreadResultData* e) {
|
||||||
e->status = NacpLoadStatus::Error;
|
e->status = NacpLoadStatus::Error;
|
||||||
// fake the nacp entry
|
// fake the nacp entry
|
||||||
std::strcpy(e->lang.name, "Corrupted");
|
std::strcpy(e->lang.name, "Corrupted"_i18n.c_str());
|
||||||
std::strcpy(e->lang.author, "Corrupted");
|
std::strcpy(e->lang.author, "Corrupted"_i18n.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
Result LoadControlManual(u64 id, NacpStruct& nacp, ThreadResultData* data) {
|
Result LoadControlManual(u64 id, NacpStruct& nacp, ThreadResultData* data) {
|
||||||
|
|||||||
@@ -354,7 +354,7 @@ auto UninstallApp(ProgressBox* pbox, const Entry& entry) -> Result {
|
|||||||
|
|
||||||
// remove directory, this will also delete manifest and info
|
// remove directory, this will also delete manifest and info
|
||||||
const auto dir = BuildPackageCachePath(entry);
|
const auto dir = BuildPackageCachePath(entry);
|
||||||
pbox->NewTransfer("Removing "_i18n + dir.toString());
|
pbox->NewTransfer(i18n::Reorder("Removing ", dir.toString()));
|
||||||
if (R_FAILED(fs.DeleteDirectoryRecursively(dir))) {
|
if (R_FAILED(fs.DeleteDirectoryRecursively(dir))) {
|
||||||
log_write("failed to delete folder: %s\n", dir.s);
|
log_write("failed to delete folder: %s\n", dir.s);
|
||||||
} else {
|
} else {
|
||||||
@@ -384,7 +384,7 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> Result {
|
|||||||
|
|
||||||
// 1. download the zip
|
// 1. download the zip
|
||||||
if (!pbox->ShouldExit()) {
|
if (!pbox->ShouldExit()) {
|
||||||
pbox->NewTransfer("Downloading "_i18n + entry.title);
|
pbox->NewTransfer(i18n::Reorder("Downloading ", entry.title));
|
||||||
log_write("starting download\n");
|
log_write("starting download\n");
|
||||||
|
|
||||||
const auto url = BuildZipUrl(entry);
|
const auto url = BuildZipUrl(entry);
|
||||||
@@ -739,7 +739,7 @@ void EntryMenu::Draw(NVGcontext* vg, Theme* theme) {
|
|||||||
text_start_y += text_inc_y;
|
text_start_y += text_inc_y;
|
||||||
gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "updated: %s"_i18n.c_str(), m_entry.updated.c_str());
|
gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "updated: %s"_i18n.c_str(), m_entry.updated.c_str());
|
||||||
text_start_y += text_inc_y;
|
text_start_y += text_inc_y;
|
||||||
gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "category: %s"_i18n.c_str(), m_entry.category.c_str());
|
gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "category: %s"_i18n.c_str(), i18n::get(m_entry.category).c_str());
|
||||||
text_start_y += text_inc_y;
|
text_start_y += text_inc_y;
|
||||||
gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "extracted: %s"_i18n.c_str(), utils::formatSizeStorage(m_entry.extracted).c_str());
|
gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "extracted: %s"_i18n.c_str(), utils::formatSizeStorage(m_entry.extracted).c_str());
|
||||||
text_start_y += text_inc_y;
|
text_start_y += text_inc_y;
|
||||||
@@ -806,7 +806,7 @@ void EntryMenu::UpdateOptions() {
|
|||||||
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
|
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
App::Notify("Downloaded "_i18n + m_entry.title);
|
App::Notify(i18n::Reorder("Downloaded ", m_entry.title));
|
||||||
m_entry.status = EntryStatus::Installed;
|
m_entry.status = EntryStatus::Installed;
|
||||||
m_menu.SetDirty();
|
m_menu.SetDirty();
|
||||||
UpdateOptions();
|
UpdateOptions();
|
||||||
@@ -822,7 +822,7 @@ void EntryMenu::UpdateOptions() {
|
|||||||
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
|
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
App::Notify("Removed "_i18n + m_entry.title);
|
App::Notify(i18n::Reorder("Removed ", m_entry.title));
|
||||||
m_entry.status = EntryStatus::Get;
|
m_entry.status = EntryStatus::Get;
|
||||||
m_menu.SetDirty();
|
m_menu.SetDirty();
|
||||||
UpdateOptions();
|
UpdateOptions();
|
||||||
@@ -833,7 +833,7 @@ void EntryMenu::UpdateOptions() {
|
|||||||
const Option install_option{"Install"_i18n, install};
|
const Option install_option{"Install"_i18n, install};
|
||||||
const Option update_option{"Update"_i18n, install};
|
const Option update_option{"Update"_i18n, install};
|
||||||
const Option launch_option{"Launch"_i18n, launch};
|
const Option launch_option{"Launch"_i18n, launch};
|
||||||
const Option remove_option{"Remove"_i18n, "Completely remove "_i18n + m_entry.title + '?', uninstall};
|
const Option remove_option{"Remove"_i18n, i18n::Reorder("Completely remove ", m_entry.title) + '?', uninstall};
|
||||||
|
|
||||||
m_options.clear();
|
m_options.clear();
|
||||||
switch (m_entry.status) {
|
switch (m_entry.status) {
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ constexpr FsEntry FS_ENTRIES[]{
|
|||||||
};
|
};
|
||||||
|
|
||||||
constexpr std::string_view AUDIO_EXTENSIONS[] = {
|
constexpr std::string_view AUDIO_EXTENSIONS[] = {
|
||||||
"mp3", "ogg", "flac", "wav", "aac" "ac3", "aif", "asf", "bfwav",
|
"mp3", "ogg", "flac", "wav", "aac", "ac3", "aif", "asf", "bfwav",
|
||||||
"bfsar", "bfstm", "bwav",
|
"bfsar", "bfstm", "bwav",
|
||||||
};
|
};
|
||||||
constexpr std::string_view VIDEO_EXTENSIONS[] = {
|
constexpr std::string_view VIDEO_EXTENSIONS[] = {
|
||||||
@@ -315,23 +315,23 @@ ForwarderForm::ForwarderForm(const FileAssocEntry& assoc, const RomDatabaseIndex
|
|||||||
const auto icon = m_assoc.path;
|
const auto icon = m_assoc.path;
|
||||||
|
|
||||||
m_name = this->Add<SidebarEntryTextInput>(
|
m_name = this->Add<SidebarEntryTextInput>(
|
||||||
"Name", name, "", "", -1, sizeof(NacpLanguageEntry::name) - 1,
|
"Name"_i18n, name, "", "", -1, sizeof(NacpLanguageEntry::name) - 1,
|
||||||
"Set the name of the application"_i18n
|
"Set the name of the application"_i18n
|
||||||
);
|
);
|
||||||
|
|
||||||
m_author = this->Add<SidebarEntryTextInput>(
|
m_author = this->Add<SidebarEntryTextInput>(
|
||||||
"Author", author, "", "", -1, sizeof(NacpLanguageEntry::author) - 1,
|
"Author"_i18n, author, "", "", -1, sizeof(NacpLanguageEntry::author) - 1,
|
||||||
"Set the author of the application"_i18n
|
"Set the author of the application"_i18n
|
||||||
);
|
);
|
||||||
|
|
||||||
m_version = this->Add<SidebarEntryTextInput>(
|
m_version = this->Add<SidebarEntryTextInput>(
|
||||||
"Version", version, "", "", -1, sizeof(NacpStruct::display_version) - 1,
|
"Version"_i18n, version, "", "", -1, sizeof(NacpStruct::display_version) - 1,
|
||||||
"Set the display version of the application"_i18n
|
"Set the display version of the application"_i18n
|
||||||
);
|
);
|
||||||
|
|
||||||
const std::vector<std::string> filters{"nro", "png", "jpg"};
|
const std::vector<std::string> filters{"nro", "png", "jpg"};
|
||||||
m_icon = this->Add<SidebarEntryFilePicker>(
|
m_icon = this->Add<SidebarEntryFilePicker>(
|
||||||
"Icon", icon, filters,
|
"Icon"_i18n, icon, filters,
|
||||||
"Set the path to the icon for the forwarder"_i18n
|
"Set the path to the icon for the forwarder"_i18n
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -362,7 +362,7 @@ ForwarderForm::ForwarderForm(const FileAssocEntry& assoc, const RomDatabaseIndex
|
|||||||
// try and read icon file into memory, bail if this fails.
|
// try and read icon file into memory, bail if this fails.
|
||||||
const auto rc = fs::FsStdio().read_entire_file(m_icon->GetValue(), config.icon);
|
const auto rc = fs::FsStdio().read_entire_file(m_icon->GetValue(), config.icon);
|
||||||
if (R_FAILED(rc)) {
|
if (R_FAILED(rc)) {
|
||||||
App::PushErrorBox(rc, "Failed to load icon");
|
App::PushErrorBox(rc, "Failed to load icon"_i18n);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -721,7 +721,7 @@ void FsView::OnClick() {
|
|||||||
} else {
|
} else {
|
||||||
// special case for nro
|
// special case for nro
|
||||||
if (IsSd() && IsSamePath(entry.GetExtension(), "nro")) {
|
if (IsSd() && IsSamePath(entry.GetExtension(), "nro")) {
|
||||||
App::Push<OptionBox>("Launch "_i18n + entry.GetName() + '?',
|
App::Push<OptionBox>(i18n::Reorder("Launch ", entry.GetName()) + '?',
|
||||||
"No"_i18n, "Launch"_i18n, 1, [this](auto op_index){
|
"No"_i18n, "Launch"_i18n, 1, [this](auto op_index){
|
||||||
if (op_index && *op_index) {
|
if (op_index && *op_index) {
|
||||||
nro_launch(GetNewPathCurrent());
|
nro_launch(GetNewPathCurrent());
|
||||||
@@ -872,7 +872,7 @@ void FsView::InstallFiles() {
|
|||||||
App::Push<ui::ProgressBox>(0, "Installing "_i18n, "", [this, targets](auto pbox) -> Result {
|
App::Push<ui::ProgressBox>(0, "Installing "_i18n, "", [this, targets](auto pbox) -> Result {
|
||||||
for (auto& e : targets) {
|
for (auto& e : targets) {
|
||||||
R_TRY(yati::InstallFromFile(pbox, m_fs.get(), GetNewPath(e)));
|
R_TRY(yati::InstallFromFile(pbox, m_fs.get(), GetNewPath(e)));
|
||||||
App::Notify("Installed "_i18n + e.GetName());
|
App::Notify(i18n::Reorder("Installed ", e.GetName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
@@ -1255,7 +1255,7 @@ void FsView::OnDeleteCallback() {
|
|||||||
|
|
||||||
const auto full_path = GetNewPath(selected.m_path, p.name);
|
const auto full_path = GetNewPath(selected.m_path, p.name);
|
||||||
if (p.IsDir()) {
|
if (p.IsDir()) {
|
||||||
pbox->NewTransfer("Scanning "_i18n + full_path);
|
pbox->NewTransfer(i18n::Reorder("Scanning ", full_path));
|
||||||
R_TRY(get_collections(src_fs, full_path, p.name, collections));
|
R_TRY(get_collections(src_fs, full_path, p.name, collections));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1298,7 +1298,7 @@ void FsView::OnPasteCallback() {
|
|||||||
const auto dst_path = GetNewPath(m_path, p.name);
|
const auto dst_path = GetNewPath(m_path, p.name);
|
||||||
|
|
||||||
pbox->SetTitle(p.name);
|
pbox->SetTitle(p.name);
|
||||||
pbox->NewTransfer("Pasting "_i18n + src_path);
|
pbox->NewTransfer(i18n::Reorder("Pasting ", src_path));
|
||||||
|
|
||||||
if (p.IsDir()) {
|
if (p.IsDir()) {
|
||||||
m_fs->RenameDirectory(src_path, dst_path);
|
m_fs->RenameDirectory(src_path, dst_path);
|
||||||
@@ -1333,7 +1333,7 @@ void FsView::OnPasteCallback() {
|
|||||||
|
|
||||||
const auto full_path = GetNewPath(selected.m_path, p.name);
|
const auto full_path = GetNewPath(selected.m_path, p.name);
|
||||||
if (p.IsDir()) {
|
if (p.IsDir()) {
|
||||||
pbox->NewTransfer("Scanning "_i18n + full_path);
|
pbox->NewTransfer(i18n::Reorder("Scanning ", full_path));
|
||||||
R_TRY(get_collections(src_fs, full_path, p.name, collections));
|
R_TRY(get_collections(src_fs, full_path, p.name, collections));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1347,11 +1347,11 @@ void FsView::OnPasteCallback() {
|
|||||||
|
|
||||||
if (p.IsDir()) {
|
if (p.IsDir()) {
|
||||||
pbox->SetTitle(p.name);
|
pbox->SetTitle(p.name);
|
||||||
pbox->NewTransfer("Creating "_i18n + dst_path);
|
pbox->NewTransfer(i18n::Reorder("Creating ", dst_path));
|
||||||
m_fs->CreateDirectory(dst_path);
|
m_fs->CreateDirectory(dst_path);
|
||||||
} else {
|
} else {
|
||||||
pbox->SetTitle(p.name);
|
pbox->SetTitle(p.name);
|
||||||
pbox->NewTransfer("Copying "_i18n + src_path);
|
pbox->NewTransfer(i18n::Reorder("Copying ", src_path));
|
||||||
R_TRY(pbox->CopyFile(src_fs, m_fs.get(), src_path, dst_path, is_same_fs));
|
R_TRY(pbox->CopyFile(src_fs, m_fs.get(), src_path, dst_path, is_same_fs));
|
||||||
R_TRY(on_paste_file(src_path, dst_path));
|
R_TRY(on_paste_file(src_path, dst_path));
|
||||||
}
|
}
|
||||||
@@ -1369,7 +1369,7 @@ void FsView::OnPasteCallback() {
|
|||||||
const auto dst_path = GetNewPath(base_dst_path, p.name);
|
const auto dst_path = GetNewPath(base_dst_path, p.name);
|
||||||
|
|
||||||
pbox->SetTitle(p.name);
|
pbox->SetTitle(p.name);
|
||||||
pbox->NewTransfer("Creating "_i18n + dst_path);
|
pbox->NewTransfer(i18n::Reorder("Creating ", dst_path));
|
||||||
m_fs->CreateDirectory(dst_path);
|
m_fs->CreateDirectory(dst_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1381,7 +1381,7 @@ void FsView::OnPasteCallback() {
|
|||||||
const auto dst_path = GetNewPath(base_dst_path, p.name);
|
const auto dst_path = GetNewPath(base_dst_path, p.name);
|
||||||
|
|
||||||
pbox->SetTitle(p.name);
|
pbox->SetTitle(p.name);
|
||||||
pbox->NewTransfer("Copying "_i18n + src_path);
|
pbox->NewTransfer(i18n::Reorder("Copying ", src_path));
|
||||||
R_TRY(pbox->CopyFile(src_fs, m_fs.get(), src_path, dst_path, is_same_fs));
|
R_TRY(pbox->CopyFile(src_fs, m_fs.get(), src_path, dst_path, is_same_fs));
|
||||||
R_TRY(on_paste_file(src_path, dst_path));
|
R_TRY(on_paste_file(src_path, dst_path));
|
||||||
}
|
}
|
||||||
@@ -1514,7 +1514,7 @@ Result FsView::DeleteAllCollections(ProgressBox* pbox, fs::Fs* fs, const FsDirCo
|
|||||||
|
|
||||||
const auto full_path = FsView::GetNewPath(c.path, p.name);
|
const auto full_path = FsView::GetNewPath(c.path, p.name);
|
||||||
pbox->SetTitle(p.name);
|
pbox->SetTitle(p.name);
|
||||||
pbox->NewTransfer("Deleting "_i18n + full_path.toString());
|
pbox->NewTransfer(i18n::Reorder("Deleting ", full_path.toString()));
|
||||||
if ((mode & FsDirOpenMode_ReadDirs) && p.type == FsDirEntryType_Dir) {
|
if ((mode & FsDirOpenMode_ReadDirs) && p.type == FsDirEntryType_Dir) {
|
||||||
log_write("deleting dir: %s\n", full_path.s);
|
log_write("deleting dir: %s\n", full_path.s);
|
||||||
R_TRY(fs->DeleteDirectory(full_path));
|
R_TRY(fs->DeleteDirectory(full_path));
|
||||||
@@ -1545,7 +1545,7 @@ static Result DeleteAllCollectionsWithSelected(ProgressBox* pbox, fs::Fs* fs, co
|
|||||||
|
|
||||||
const auto full_path = FsView::GetNewPath(selected.m_path, p.name);
|
const auto full_path = FsView::GetNewPath(selected.m_path, p.name);
|
||||||
pbox->SetTitle(p.name);
|
pbox->SetTitle(p.name);
|
||||||
pbox->NewTransfer("Deleting "_i18n + full_path.toString());
|
pbox->NewTransfer(i18n::Reorder("Deleting ", full_path.toString()));
|
||||||
|
|
||||||
if ((mode & FsDirOpenMode_ReadDirs) && p.type == FsDirEntryType_Dir) {
|
if ((mode & FsDirOpenMode_ReadDirs) && p.type == FsDirEntryType_Dir) {
|
||||||
log_write("deleting dir: %s\n", full_path.s);
|
log_write("deleting dir: %s\n", full_path.s);
|
||||||
@@ -1805,7 +1805,7 @@ void FsView::DisplayOptions() {
|
|||||||
|
|
||||||
options->Add<SidebarEntryCallback>("Extract to..."_i18n, [this](){
|
options->Add<SidebarEntryCallback>("Extract to..."_i18n, [this](){
|
||||||
std::string out;
|
std::string out;
|
||||||
if (R_SUCCEEDED(swkbd::ShowText(out, "Extract path", "Enter the path to the folder to extract into", fs::AppendPath(m_path, ""))) && !out.empty()) {
|
if (R_SUCCEEDED(swkbd::ShowText(out, "Extract path", "Enter the path to the folder to extract into"_i18n.c_str, fs::AppendPath(m_path, ""))) && !out.empty()) {
|
||||||
UnzipFiles(out);
|
UnzipFiles(out);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1823,7 +1823,7 @@ void FsView::DisplayOptions() {
|
|||||||
|
|
||||||
options->Add<SidebarEntryCallback>("Compress to..."_i18n, [this](){
|
options->Add<SidebarEntryCallback>("Compress to..."_i18n, [this](){
|
||||||
std::string out;
|
std::string out;
|
||||||
if (R_SUCCEEDED(swkbd::ShowText(out, "Compress path", "Enter the path to the folder to compress into", m_path)) && !out.empty()) {
|
if (R_SUCCEEDED(swkbd::ShowText(out, "Compress path", "Enter the path to the folder to compress into"_i18n.c_str, m_path)) && !out.empty()) {
|
||||||
ZipFiles(out);
|
ZipFiles(out);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ void FreeEntry(NVGcontext* vg, Entry& e) {
|
|||||||
|
|
||||||
void LaunchEntry(const Entry& e) {
|
void LaunchEntry(const Entry& e) {
|
||||||
const auto rc = appletRequestLaunchApplication(e.app_id, nullptr);
|
const auto rc = appletRequestLaunchApplication(e.app_id, nullptr);
|
||||||
Notify(rc, "Failed to launch application");
|
Notify(rc, "Failed to launch application"_i18n);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CreateSave(u64 app_id, AccountUid uid) {
|
Result CreateSave(u64 app_id, AccountUid uid) {
|
||||||
@@ -372,7 +372,7 @@ Menu::Menu(u32 flags) : grid::Menu{"Games"_i18n, flags} {
|
|||||||
LoadControlEntry(e, true);
|
LoadControlEntry(e, true);
|
||||||
|
|
||||||
App::Push<OptionBox>(
|
App::Push<OptionBox>(
|
||||||
"Launch "_i18n + e.GetName(),
|
i18n::Reorder("Launch ", e.GetName()) + '?',
|
||||||
"Back"_i18n, "Launch"_i18n, 1, [this, &e](auto op_index){
|
"Back"_i18n, "Launch"_i18n, 1, [this, &e](auto op_index){
|
||||||
if (op_index && *op_index) {
|
if (op_index && *op_index) {
|
||||||
LaunchEntry(e);
|
LaunchEntry(e);
|
||||||
@@ -397,7 +397,7 @@ Menu::Menu(u32 flags) : grid::Menu{"Games"_i18n, flags} {
|
|||||||
|
|
||||||
// completely deletes the application record and all data.
|
// completely deletes the application record and all data.
|
||||||
options->Add<SidebarEntryCallback>("Delete"_i18n, [this](){
|
options->Add<SidebarEntryCallback>("Delete"_i18n, [this](){
|
||||||
const auto buf = "Are you sure you want to delete "_i18n + m_entries[m_index].GetName() + "?";
|
const auto buf = i18n::Reorder("Are you sure you want to delete ", m_entries[m_index].GetName()) + "?";
|
||||||
App::Push<OptionBox>(
|
App::Push<OptionBox>(
|
||||||
buf,
|
buf,
|
||||||
"Back"_i18n, "Delete"_i18n, 0, [this](auto op_index){
|
"Back"_i18n, "Delete"_i18n, 0, [this](auto op_index){
|
||||||
@@ -839,7 +839,7 @@ void DeleteMetaEntries(u64 app_id, int image, const std::string& name, const tit
|
|||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}, [](Result rc){
|
}, [](Result rc){
|
||||||
App::PushErrorBox(rc, "Failed to delete meta entry");
|
App::PushErrorBox(rc, "Failed to delete meta entry"_i18n);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -181,23 +181,23 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) {
|
|||||||
char req_vers_buf[128];
|
char req_vers_buf[128];
|
||||||
const auto ver = e.content_meta.extened.application.required_system_version;
|
const auto ver = e.content_meta.extened.application.required_system_version;
|
||||||
switch (e.status.meta_type) {
|
switch (e.status.meta_type) {
|
||||||
case NcmContentMetaType_Application: std::snprintf(req_vers_buf, sizeof(req_vers_buf), "Required System Version: %u.%u.%u", SYSVER_MAJOR(ver), SYSVER_MINOR(ver), SYSVER_MICRO(ver)); break;
|
case NcmContentMetaType_Application: std::snprintf(req_vers_buf, sizeof(req_vers_buf), "Required System Version: %u.%u.%u"_i18n.c_str(), SYSVER_MAJOR(ver), SYSVER_MINOR(ver), SYSVER_MICRO(ver)); break;
|
||||||
case NcmContentMetaType_Patch: std::snprintf(req_vers_buf, sizeof(req_vers_buf), "Required System Version: %u.%u.%u", SYSVER_MAJOR(ver), SYSVER_MINOR(ver), SYSVER_MICRO(ver)); break;
|
case NcmContentMetaType_Patch: std::snprintf(req_vers_buf, sizeof(req_vers_buf), "Required System Version: %u.%u.%u"_i18n.c_str(), SYSVER_MAJOR(ver), SYSVER_MINOR(ver), SYSVER_MICRO(ver)); break;
|
||||||
case NcmContentMetaType_AddOnContent: std::snprintf(req_vers_buf, sizeof(req_vers_buf), "Required Application Version: v%u", ver >> 16); break;
|
case NcmContentMetaType_AddOnContent: std::snprintf(req_vers_buf, sizeof(req_vers_buf), "Required Application Version: v%u"_i18n.c_str(), ver >> 16); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.missing_count) {
|
if (e.missing_count) {
|
||||||
gfx::drawTextArgs(vg, 50, 415, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Content Count: %u (%u missing)", e.content_meta.header.content_count, e.missing_count);
|
gfx::drawTextArgs(vg, 50, 415, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Content Count: %u (%u missing)"_i18n.c_str(), e.content_meta.header.content_count, e.missing_count);
|
||||||
} else {
|
} else {
|
||||||
gfx::drawTextArgs(vg, 50, 415, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Content Count: %u", e.content_meta.header.content_count);
|
gfx::drawTextArgs(vg, 50, 415, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Content Count: %u"_i18n.c_str(), e.content_meta.header.content_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::drawTextArgs(vg, 50, 455, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Ticket: %s", TICKET_STR[e.ticket_type]);
|
gfx::drawTextArgs(vg, 50, 455, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Ticket: %s"_i18n.c_str(), i18n::get(TICKET_STR[e.ticket_type]).c_str());
|
||||||
gfx::drawTextArgs(vg, 50, 495, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Key Generation: %u (%s)", e.key_gen, nca::GetKeyGenStr(e.key_gen));
|
gfx::drawTextArgs(vg, 50, 495, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Key Generation: %u (%s)"_i18n.c_str(), e.key_gen, nca::GetKeyGenStr(e.key_gen));
|
||||||
gfx::drawTextArgs(vg, 50, 535, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "%s", req_vers_buf);
|
gfx::drawTextArgs(vg, 50, 535, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "%s", req_vers_buf);
|
||||||
|
|
||||||
if (e.status.meta_type == NcmContentMetaType_Application || e.status.meta_type == NcmContentMetaType_Patch) {
|
if (e.status.meta_type == NcmContentMetaType_Application || e.status.meta_type == NcmContentMetaType_Patch) {
|
||||||
gfx::drawTextArgs(vg, 50, 575, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Display Version: %s", e.nacp.display_version);
|
gfx::drawTextArgs(vg, 50, 575, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Display Version: %s"_i18n.c_str(), e.nacp.display_version);
|
||||||
}
|
}
|
||||||
nvgRestore(vg);
|
nvgRestore(vg);
|
||||||
|
|
||||||
@@ -224,7 +224,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::drawTextArgs(vg, x + text_xoffset, y + (h / 2.f), 20.f, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(text_id), "%s", ncm::GetReadableMetaTypeStr(e.status.meta_type));
|
gfx::drawTextArgs(vg, x + text_xoffset, y + (h / 2.f), 20.f, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(text_id), "%s", i18n::get(ncm::GetReadableMetaTypeStr(e.status.meta_type)).c_str());
|
||||||
gfx::drawTextArgs(vg, x + text_xoffset + 150, y + (h / 2.f), 20.f, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(text_id), "%016lX", e.status.application_id);
|
gfx::drawTextArgs(vg, x + text_xoffset + 150, y + (h / 2.f), 20.f, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(text_id), "%016lX", e.status.application_id);
|
||||||
gfx::drawTextArgs(vg, x + text_xoffset + 400, y + (h / 2.f), 20.f, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(text_id), "v%u (%u)", e.status.version >> 16, e.status.version);
|
gfx::drawTextArgs(vg, x + text_xoffset + 400, y + (h / 2.f), 20.f, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(text_id), "v%u (%u)", e.status.version >> 16, e.status.version);
|
||||||
|
|
||||||
@@ -233,7 +233,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) {
|
|||||||
GetNcmSizeOfMetaStatus(e);
|
GetNcmSizeOfMetaStatus(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) + 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT_INFO), "%s", ncm::GetReadableStorageIdStr(e.status.storageID));
|
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) + 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT_INFO), "%s", i18n::get(ncm::GetReadableStorageIdStr(e.status.storageID)).c_str());
|
||||||
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->GetColour(ThemeEntryID_TEXT_INFO), "%s", utils::formatSizeStorage(e.size).c_str());
|
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->GetColour(ThemeEntryID_TEXT_INFO), "%s", utils::formatSizeStorage(e.size).c_str());
|
||||||
|
|
||||||
if (e.selected) {
|
if (e.selected) {
|
||||||
|
|||||||
@@ -205,9 +205,10 @@ Menu::Menu(Entry& entry, const meta::MetaEntry& meta_entry)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, "Performs sha256 hash over the NCA to check if it's valid.\n\n"
|
}, i18n::get("nca_validate_info",
|
||||||
"NOTE: This only detects if the hash is missmatched, it does not validate if \
|
"Performs sha256 hash over the NCA to check if it's valid.\n\n"
|
||||||
the content has been modified at all."_i18n);
|
"NOTE: This only detects if the hash is missmatched, it does not validate if "
|
||||||
|
"the content has been modified at all."));
|
||||||
|
|
||||||
options->Add<SidebarEntryCallback>("Verify NCA fixed key"_i18n, [this](){
|
options->Add<SidebarEntryCallback>("Verify NCA fixed key"_i18n, [this](){
|
||||||
if (R_FAILED(nca::VerifyFixedKey(GetEntry().header))) {
|
if (R_FAILED(nca::VerifyFixedKey(GetEntry().header))) {
|
||||||
@@ -215,9 +216,10 @@ Menu::Menu(Entry& entry, const meta::MetaEntry& meta_entry)
|
|||||||
} else {
|
} else {
|
||||||
App::Push<OptionBox>("NCA fixed key is valid."_i18n, "OK"_i18n);
|
App::Push<OptionBox>("NCA fixed key is valid."_i18n, "OK"_i18n);
|
||||||
}
|
}
|
||||||
}, "Performs RSA NCA fixed key verification. "\
|
}, i18n::get("nca_fixedkey_info",
|
||||||
"This is a hash over the NCA header. It is used to verify that the header has not been modified. "\
|
"Performs RSA NCA fixed key verification. "
|
||||||
"The header is signed by nintendo, thus it cannot be forged, and is reliable to detect modified NCA headers (such as NSP/XCI converts)."_i18n);
|
"This is a hash over the NCA header. It is used to verify that the header has not been modified. "
|
||||||
|
"The header is signed by nintendo, thus it cannot be forged, and is reliable to detect modified NCA headers (such as NSP/XCI converts)."));
|
||||||
}
|
}
|
||||||
}})
|
}})
|
||||||
);
|
);
|
||||||
@@ -307,16 +309,16 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) {
|
|||||||
gfx::drawImage(vg, 90, 130, 256, 256, m_entry.image ? m_entry.image : App::GetDefaultImage());
|
gfx::drawImage(vg, 90, 130, 256, 256, m_entry.image ? m_entry.image : App::GetDefaultImage());
|
||||||
|
|
||||||
if (e.header.magic != NCA3_MAGIC) {
|
if (e.header.magic != NCA3_MAGIC) {
|
||||||
gfx::drawTextArgs(vg, 50, 415, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Failed to decrypt NCA");
|
gfx::drawTextArgs(vg, 50, 415, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Failed to decrypt NCA"_i18n.c_str());
|
||||||
} else {
|
} else {
|
||||||
nvgSave(vg);
|
nvgSave(vg);
|
||||||
nvgIntersectScissor(vg, 50, 90, 325, 555);
|
nvgIntersectScissor(vg, 50, 90, 325, 555);
|
||||||
gfx::drawTextArgs(vg, 50, 415, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Application Type: %s", ncm::GetReadableMetaTypeStr(m_meta_entry.status.meta_type));
|
gfx::drawTextArgs(vg, 50, 415, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Application Type: %s"_i18n.c_str(), i18n::get(ncm::GetReadableMetaTypeStr(m_meta_entry.status.meta_type)).c_str());
|
||||||
gfx::drawTextArgs(vg, 50, 455, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Content Type: %s", nca::GetContentTypeStr(e.header.content_type));
|
gfx::drawTextArgs(vg, 50, 455, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Content Type: %s"_i18n.c_str(), nca::GetContentTypeStr(e.header.content_type));
|
||||||
gfx::drawTextArgs(vg, 50, 495, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Distribution Type: %s", nca::GetDistributionTypeStr(e.header.distribution_type));
|
gfx::drawTextArgs(vg, 50, 495, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Distribution Type: %s"_i18n.c_str(), nca::GetDistributionTypeStr(e.header.distribution_type));
|
||||||
gfx::drawTextArgs(vg, 50, 535, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Program ID: %016lX", e.header.program_id);
|
gfx::drawTextArgs(vg, 50, 535, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Program ID: %016lX"_i18n.c_str(), e.header.program_id);
|
||||||
gfx::drawTextArgs(vg, 50, 575, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Key Generation: %u (%s)", e.header.GetKeyGeneration(), nca::GetKeyGenStr(e.header.GetKeyGeneration()));
|
gfx::drawTextArgs(vg, 50, 575, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Key Generation: %u (%s)"_i18n.c_str(), e.header.GetKeyGeneration(), nca::GetKeyGenStr(e.header.GetKeyGeneration()));
|
||||||
gfx::drawTextArgs(vg, 50, 615, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "SDK Version: %u.%u.%u.%u", e.header.sdk_major, e.header.sdk_minor, e.header.sdk_micro, e.header.sdk_revision);
|
gfx::drawTextArgs(vg, 50, 615, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "SDK Version: %u.%u.%u.%u"_i18n.c_str(), e.header.sdk_major, e.header.sdk_minor, e.header.sdk_micro, e.header.sdk_revision);
|
||||||
nvgRestore(vg);
|
nvgRestore(vg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -718,10 +718,10 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) {
|
|||||||
nvgIntersectScissor(vg, 50, 90, 325, 555);
|
nvgIntersectScissor(vg, 50, 90, 325, 555);
|
||||||
gfx::drawTextArgs(vg, 50, 415, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "%s", e.lang_entry.name);
|
gfx::drawTextArgs(vg, 50, 415, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "%s", e.lang_entry.name);
|
||||||
gfx::drawTextArgs(vg, 50, 455, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "%s", e.lang_entry.author);
|
gfx::drawTextArgs(vg, 50, 455, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "%s", e.lang_entry.author);
|
||||||
gfx::drawTextArgs(vg, 50, 495, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "App-ID: 0%lX", e.app_id);
|
gfx::drawTextArgs(vg, 50, 495, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "App-ID: 0%lX"_i18n.c_str(), e.app_id);
|
||||||
gfx::drawTextArgs(vg, 50, 535, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Key-Gen: %u (%s)", e.key_gen, nca::GetKeyGenStr(e.key_gen));
|
gfx::drawTextArgs(vg, 50, 535, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Key-Gen: %u (%s)"_i18n.c_str(), e.key_gen, nca::GetKeyGenStr(e.key_gen));
|
||||||
gfx::drawTextArgs(vg, 50, 575, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Size: %.2f GB", (double)size / 0x40000000);
|
gfx::drawTextArgs(vg, 50, 575, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Size: %.2f GB"_i18n.c_str(), (double)size / 0x40000000);
|
||||||
gfx::drawTextArgs(vg, 50, 615, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Base: %zu Patch: %zu Addon: %zu Data: %zu", e.application.size(), e.patch.size(), e.add_on.size(), e.data_patch.size());
|
gfx::drawTextArgs(vg, 50, 615, 18.f, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Base: %zu Patch: %zu Addon: %zu Data: %zu"_i18n.c_str(), e.application.size(), e.patch.size(), e.add_on.size(), e.data_patch.size());
|
||||||
nvgRestore(vg);
|
nvgRestore(vg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1098,7 +1098,7 @@ void Menu::OnChangeIndex(s64 new_index) {
|
|||||||
m_entry_index = new_index;
|
m_entry_index = new_index;
|
||||||
|
|
||||||
if (m_entries.empty()) {
|
if (m_entries.empty()) {
|
||||||
this->SetSubHeading("No GameCard inserted");
|
this->SetSubHeading("No GameCard inserted"_i18n);
|
||||||
} else {
|
} else {
|
||||||
const auto index = m_entries.empty() ? 0 : m_entry_index + 1;
|
const auto index = m_entries.empty() ? 0 : m_entry_index + 1;
|
||||||
this->SetSubHeading(std::to_string(index) + " / " + std::to_string(m_entries.size()));
|
this->SetSubHeading(std::to_string(index) + " / " + std::to_string(m_entries.size()));
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ auto DownloadApp(ProgressBox* pbox, const GhApiAsset& gh_asset, const AssetEntry
|
|||||||
|
|
||||||
// 2. download the asset
|
// 2. download the asset
|
||||||
if (!pbox->ShouldExit()) {
|
if (!pbox->ShouldExit()) {
|
||||||
pbox->NewTransfer("Downloading "_i18n + gh_asset.name);
|
pbox->NewTransfer(i18n::Reorder("Downloading ", gh_asset.name));
|
||||||
log_write("starting download: %s\n", gh_asset.browser_download_url.c_str());
|
log_write("starting download: %s\n", gh_asset.browser_download_url.c_str());
|
||||||
|
|
||||||
const auto result = curl::Api().ToFile(
|
const auto result = curl::Api().ToFile(
|
||||||
@@ -233,7 +233,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) {
|
|||||||
nvgRestore(vg);
|
nvgRestore(vg);
|
||||||
|
|
||||||
if (!e.tag.empty()) {
|
if (!e.tag.empty()) {
|
||||||
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f), 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_INFO), "version: %s", e.tag.c_str());
|
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f), 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_INFO), "version: %s"_i18n.c_str(), e.tag.c_str());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -427,7 +427,7 @@ void DownloadEntries(const Entry& entry) {
|
|||||||
App::PushErrorBox(rc, "Failed to download app!"_i18n);
|
App::PushErrorBox(rc, "Failed to download app!"_i18n);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
App::Notify("Downloaded "_i18n + entry.repo);
|
App::Notify(i18n::Reorder("Downloaded ", entry.repo));
|
||||||
auto post_install_message = entry.post_install_message;
|
auto post_install_message = entry.post_install_message;
|
||||||
if (ptr && !ptr->post_install_message.empty()) {
|
if (ptr && !ptr->post_install_message.empty()) {
|
||||||
post_install_message = ptr->post_install_message;
|
post_install_message = ptr->post_install_message;
|
||||||
|
|||||||
@@ -168,13 +168,13 @@ void Menu::SetIndex(s64 index) {
|
|||||||
if (fs::FsNativeSd().FileExists(star_path)) {
|
if (fs::FsNativeSd().FileExists(star_path)) {
|
||||||
SetAction(Button::R3, Action{"Unstar"_i18n, [this](){
|
SetAction(Button::R3, Action{"Unstar"_i18n, [this](){
|
||||||
fs::FsNativeSd().DeleteFile(GenerateStarPath(GetEntry().path));
|
fs::FsNativeSd().DeleteFile(GenerateStarPath(GetEntry().path));
|
||||||
App::Notify("Unstarred "_i18n + GetEntry().GetName());
|
App::Notify(i18n::Reorder("Unstarred ", GetEntry().GetName()));
|
||||||
SortAndFindLastFile();
|
SortAndFindLastFile();
|
||||||
}});
|
}});
|
||||||
} else {
|
} else {
|
||||||
SetAction(Button::R3, Action{"Star"_i18n, [this](){
|
SetAction(Button::R3, Action{"Star"_i18n, [this](){
|
||||||
fs::FsNativeSd().CreateFile(GenerateStarPath(GetEntry().path));
|
fs::FsNativeSd().CreateFile(GenerateStarPath(GetEntry().path));
|
||||||
App::Notify("Starred "_i18n + GetEntry().GetName());
|
App::Notify(i18n::Reorder("Starred ", GetEntry().GetName()));
|
||||||
SortAndFindLastFile();
|
SortAndFindLastFile();
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
@@ -469,7 +469,7 @@ void Menu::DisplayOptions() {
|
|||||||
|
|
||||||
// for testing stuff.
|
// for testing stuff.
|
||||||
#if 0
|
#if 0
|
||||||
options->Add<SidebarEntrySlider>("Test", 1, 0, 2, 10, [](auto& v_out){
|
options->Add<SidebarEntrySlider>("Test"_i18n, 1, 0, 2, 10, [](auto& v_out){
|
||||||
|
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
@@ -494,7 +494,7 @@ void Menu::DisplayOptions() {
|
|||||||
}, "Mounts the NRO FileSystem (icon, nacp and RomFS)."_i18n);
|
}, "Mounts the NRO FileSystem (icon, nacp and RomFS)."_i18n);
|
||||||
|
|
||||||
options->Add<SidebarEntryCallback>("Delete"_i18n, [this](){
|
options->Add<SidebarEntryCallback>("Delete"_i18n, [this](){
|
||||||
const auto buf = "Are you sure you want to delete "_i18n + GetEntry().path.toString() + "?";
|
const auto buf = i18n::Reorder("Are you sure you want to delete ", GetEntry().path.toString()) + "?";
|
||||||
App::Push<OptionBox>(
|
App::Push<OptionBox>(
|
||||||
buf,
|
buf,
|
||||||
"Back"_i18n, "Delete"_i18n, 1, [this](auto op_index){
|
"Back"_i18n, "Delete"_i18n, 1, [this](auto op_index){
|
||||||
@@ -510,9 +510,10 @@ void Menu::DisplayOptions() {
|
|||||||
}
|
}
|
||||||
}, GetEntry().image
|
}, GetEntry().image
|
||||||
);
|
);
|
||||||
}, "Perminately delete the selected homebrew.\n\n"
|
}, i18n::get("hb_remove_info",
|
||||||
"Files and folders created by the homebrew will still remain. "
|
"Perminately delete the selected homebrew.\n\n"
|
||||||
"Use the FileBrowser to delete them."_i18n);
|
"Files and folders created by the homebrew will still remain. "
|
||||||
|
"Use the FileBrowser to delete them."));
|
||||||
|
|
||||||
auto forwarder_entry = options->Add<SidebarEntryCallback>("Install Forwarder"_i18n, [this](){
|
auto forwarder_entry = options->Add<SidebarEntryCallback>("Install Forwarder"_i18n, [this](){
|
||||||
InstallHomebrew();
|
InstallHomebrew();
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ Menu::Menu(u32 flags) : MenuBase{"Irs"_i18n, flags} {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(IRS_MAX_CAMERAS >= 9, "max camaeras has gotten smaller!");
|
static_assert(IRS_MAX_CAMERAS >= 9, "max cameras has gotten smaller!");
|
||||||
|
|
||||||
// open all handles
|
// open all handles
|
||||||
irsGetIrCameraHandle(&m_entries[0].m_handle, HidNpadIdType_No1);
|
irsGetIrCameraHandle(&m_entries[0].m_handle, HidNpadIdType_No1);
|
||||||
@@ -534,7 +534,7 @@ void Menu::updateColourArray() {
|
|||||||
|
|
||||||
auto Menu::GetEntryName(s64 i) -> std::string {
|
auto Menu::GetEntryName(s64 i) -> std::string {
|
||||||
const auto& e = m_entries[i];
|
const auto& e = m_entries[i];
|
||||||
std::string text = "Pad "_i18n + (i == 8 ? "HandHeld"_i18n : std::to_string(i));
|
std::string text = i18n::Reorder("Pad "_i18n, (i == 8 ? "HandHeld" : std::to_string(i)));
|
||||||
switch (e.status) {
|
switch (e.status) {
|
||||||
case IrsIrCameraStatus_Available:
|
case IrsIrCameraStatus_Available:
|
||||||
text += " (Available)"_i18n;
|
text += " (Available)"_i18n;
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string v
|
|||||||
|
|
||||||
// 1. download the zip
|
// 1. download the zip
|
||||||
if (!pbox->ShouldExit()) {
|
if (!pbox->ShouldExit()) {
|
||||||
pbox->NewTransfer("Downloading "_i18n + version);
|
pbox->NewTransfer(i18n::Reorder("Downloading ", version));
|
||||||
log_write("starting download: %s\n", url.c_str());
|
log_write("starting download: %s\n", url.c_str());
|
||||||
|
|
||||||
const auto result = curl::Api().ToFile(
|
const auto result = curl::Api().ToFile(
|
||||||
@@ -317,11 +317,12 @@ MainMenu::MainMenu() {
|
|||||||
language_items.push_back("German"_i18n);
|
language_items.push_back("German"_i18n);
|
||||||
language_items.push_back("Italian"_i18n);
|
language_items.push_back("Italian"_i18n);
|
||||||
language_items.push_back("Spanish"_i18n);
|
language_items.push_back("Spanish"_i18n);
|
||||||
language_items.push_back("Chinese"_i18n);
|
language_items.push_back("Chinese (Simplified)"_i18n);
|
||||||
language_items.push_back("Korean"_i18n);
|
language_items.push_back("Korean"_i18n);
|
||||||
language_items.push_back("Dutch"_i18n);
|
language_items.push_back("Dutch"_i18n);
|
||||||
language_items.push_back("Portuguese"_i18n);
|
language_items.push_back("Portuguese"_i18n);
|
||||||
language_items.push_back("Russian"_i18n);
|
language_items.push_back("Russian"_i18n);
|
||||||
|
language_items.push_back("Chinese (Traditional)"_i18n);
|
||||||
language_items.push_back("Swedish"_i18n);
|
language_items.push_back("Swedish"_i18n);
|
||||||
language_items.push_back("Vietnamese"_i18n);
|
language_items.push_back("Vietnamese"_i18n);
|
||||||
language_items.push_back("Ukrainian"_i18n);
|
language_items.push_back("Ukrainian"_i18n);
|
||||||
@@ -356,7 +357,7 @@ MainMenu::MainMenu() {
|
|||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
m_update_state = UpdateState::None;
|
m_update_state = UpdateState::None;
|
||||||
App::Notify("Updated to "_i18n + m_update_version);
|
App::Notify(i18n::Reorder("Updated to ", m_update_version));
|
||||||
App::Push<OptionBox>(
|
App::Push<OptionBox>(
|
||||||
"Press OK to restart Sphaira"_i18n, "OK"_i18n, [](auto){
|
"Press OK to restart Sphaira"_i18n, "OK"_i18n, [](auto){
|
||||||
App::ExitRestart();
|
App::ExitRestart();
|
||||||
@@ -368,13 +369,15 @@ MainMenu::MainMenu() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
options->Add<SidebarEntryCallback>("FTP"_i18n, [](){ App::DisplayFtpOptions(); },
|
options->Add<SidebarEntryCallback>("FTP"_i18n, [](){ App::DisplayFtpOptions(); },
|
||||||
"Enable / modify the FTP server settings such as port, user/pass and the folders that are shown.\n\n"
|
i18n::get("ftp_settings_info",
|
||||||
"NOTE: Changing any of the options will automatically restart the FTP server when exiting the options menu."_i18n
|
"Enable / modify the FTP server settings such as port, user/pass and the folders that are shown.\n\n"
|
||||||
|
"NOTE: Changing any of the options will automatically restart the FTP server when exiting the options menu.")
|
||||||
);
|
);
|
||||||
|
|
||||||
options->Add<SidebarEntryCallback>("MTP"_i18n, [](){ App::DisplayMtpOptions(); },
|
options->Add<SidebarEntryCallback>("MTP"_i18n, [](){ App::DisplayMtpOptions(); },
|
||||||
"Enable / modify the MTP responder settings such as the folders that are shown.\n\n"
|
i18n::get("mtp_settings_info",
|
||||||
"NOTE: Changing any of the options will automatically restart the MTP server when exiting the options menu."_i18n
|
"Enable / modify the MTP responder settings such as the folders that are shown.\n\n"
|
||||||
|
"NOTE: Changing any of the options will automatically restart the MTP server when exiting the options menu.")
|
||||||
);
|
);
|
||||||
|
|
||||||
options->Add<SidebarEntryCallback>("HDD"_i18n, [](){
|
options->Add<SidebarEntryCallback>("HDD"_i18n, [](){
|
||||||
@@ -383,12 +386,14 @@ MainMenu::MainMenu() {
|
|||||||
|
|
||||||
options->Add<SidebarEntryBool>("NXlink"_i18n, App::GetNxlinkEnable(), [](bool& enable){
|
options->Add<SidebarEntryBool>("NXlink"_i18n, App::GetNxlinkEnable(), [](bool& enable){
|
||||||
App::SetNxlinkEnable(enable);
|
App::SetNxlinkEnable(enable);
|
||||||
}, "Enable NXlink server to run in the background. "
|
}, i18n::get("nxlink_enable_info",
|
||||||
"NXlink is used to send .nro's from PC to the switch\n\n"
|
"Enable NXlink server to run in the background. "
|
||||||
"If you are not a developer, you can disable this option."_i18n);
|
"NXlink is used to send .nro's from PC to the switch\n\n"
|
||||||
|
"If you are not a developer, you can disable this option."));
|
||||||
|
|
||||||
}, "Toggle FTP, MTP, HDD and NXlink\n\n"
|
}, i18n::get("nxlink_toggle_info",
|
||||||
"If Sphaira has a update available, you can download it from this menu"_i18n);
|
"Toggle FTP, MTP, HDD and NXlink\n\n"
|
||||||
|
"If Sphaira has a update available, you can download it from this menu"));
|
||||||
|
|
||||||
options->Add<SidebarEntryCallback>("Theme"_i18n, [](){
|
options->Add<SidebarEntryCallback>("Theme"_i18n, [](){
|
||||||
App::DisplayThemeOptions();
|
App::DisplayThemeOptions();
|
||||||
@@ -397,14 +402,16 @@ MainMenu::MainMenu() {
|
|||||||
options->Add<SidebarEntryArray>("Language"_i18n, language_items, [](s64& index_out){
|
options->Add<SidebarEntryArray>("Language"_i18n, language_items, [](s64& index_out){
|
||||||
App::SetLanguage(index_out);
|
App::SetLanguage(index_out);
|
||||||
}, (s64)App::GetLanguage(),
|
}, (s64)App::GetLanguage(),
|
||||||
"Change the language.\n\n"
|
i18n::get("translation_info",
|
||||||
"If your language isn't found, or translations are missing, please consider opening a PR at "
|
"Change the language.\n\n"
|
||||||
"github.com/ITotalJustice/sphaira"_i18n);
|
"If your language isn't found, or translations are missing, please consider opening a PR at "
|
||||||
|
"github.com/ITotalJustice/sphaira"));
|
||||||
|
|
||||||
options->Add<SidebarEntryCallback>("Advanced Options"_i18n, [](){
|
options->Add<SidebarEntryCallback>("Advanced Options"_i18n, [](){
|
||||||
App::DisplayAdvancedOptions();
|
App::DisplayAdvancedOptions();
|
||||||
}, "Change the advanced options. "
|
}, i18n::get("advanced_options_info",
|
||||||
"Please view the info boxes to better understand each option."_i18n);
|
"Change the advanced options. "
|
||||||
|
"Please view the info boxes to better understand each option."));
|
||||||
}}
|
}}
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ void Menu::Update(Controller* controller, TouchInfo* touch) {
|
|||||||
usbDsGetSpeed(&speed);
|
usbDsGetSpeed(&speed);
|
||||||
|
|
||||||
char buf[128];
|
char buf[128];
|
||||||
std::snprintf(buf, sizeof(buf), "State: %s | Speed: %s", i18n::get(GetUsbDsStateStr(state)).c_str(), i18n::get(GetUsbDsSpeedStr(speed)).c_str());
|
std::snprintf(buf, sizeof(buf), "State: %s | Speed: %s"_i18n.c_str(), i18n::get(GetUsbDsStateStr(state)).c_str(), i18n::get(GetUsbDsSpeedStr(speed)).c_str());
|
||||||
SetSubHeading(buf);
|
SetSubHeading(buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -404,7 +404,7 @@ void Menu::Update(Controller* controller, TouchInfo* touch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_dirty) {
|
if (m_dirty) {
|
||||||
App::Notify("Updating application record list");
|
App::Notify("Updating application record list"_i18n);
|
||||||
SortAndFindLastFile(true);
|
SortAndFindLastFile(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -718,9 +718,11 @@ void Menu::DisplayOptions() {
|
|||||||
options->Add<SidebarEntryCallback>("Restore"_i18n, [this](){
|
options->Add<SidebarEntryCallback>("Restore"_i18n, [this](){
|
||||||
RestoreSave();
|
RestoreSave();
|
||||||
}, true,
|
}, true,
|
||||||
"Restore the save for the current title.\n"
|
i18n::get("save_backuprestore_info",
|
||||||
"if \"Auto backup\" is enabled, the save will first be backed up and then restored. "
|
"Restore the save for the current title.\n"
|
||||||
"Saves that are auto backed up will have \"Auto\" in their name."_i18n
|
"if \"Auto backup\" is enabled, the save will first be backed up and then restored. "
|
||||||
|
"Saves that are auto backed up will have \"Auto\" in their name."
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -735,10 +737,13 @@ void Menu::DisplayOptions() {
|
|||||||
|
|
||||||
options->Add<SidebarEntryBool>("Compress backup"_i18n, m_compress_save_backup.Get(), [this](bool& v_out){
|
options->Add<SidebarEntryBool>("Compress backup"_i18n, m_compress_save_backup.Get(), [this](bool& v_out){
|
||||||
m_compress_save_backup.Set(v_out);
|
m_compress_save_backup.Set(v_out);
|
||||||
}, "If enabled, backups will be compressed to a zip file.\n\n"
|
}, i18n::get("save_backup_compress_info",
|
||||||
"NOTE: Disabling this option does not disable the zip file, it only disables compressing "
|
"If enabled, backups will be compressed to a zip file.\n\n"
|
||||||
"the files stored in the zip.\n"
|
"NOTE: Disabling this option does not disable the zip file, it only disables compressing "
|
||||||
"Disabling will result in a much faster backup, at the cost of the file size."_i18n);
|
"the files stored in the zip.\n"
|
||||||
|
"Disabling will result in a much faster backup, at the cost of the file size."
|
||||||
|
)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -797,7 +802,7 @@ void Menu::RestoreSave() {
|
|||||||
|
|
||||||
if (paths.empty()) {
|
if (paths.empty()) {
|
||||||
App::Push<ui::OptionBox>(
|
App::Push<ui::OptionBox>(
|
||||||
"No saves found in "_i18n + fs::AppendPath(mount, BuildSaveBasePath(m_entries[m_index])).toString(),
|
i18n::Reorder("No saves found in ", fs::AppendPath(mount, BuildSaveBasePath(m_entries[m_index])).toString()),
|
||||||
"OK"_i18n
|
"OK"_i18n
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@@ -814,7 +819,7 @@ void Menu::RestoreSave() {
|
|||||||
const auto file_path = paths[*op_index];
|
const auto file_path = paths[*op_index];
|
||||||
|
|
||||||
App::Push<OptionBox>(
|
App::Push<OptionBox>(
|
||||||
"Are you sure you want to restore "_i18n + file_name + "?",
|
i18n::Reorder("Are you sure you want to restore ", file_name) + "?",
|
||||||
"Back"_i18n, "Restore"_i18n, 0, [this, file_path, location](auto op_index){
|
"Back"_i18n, "Restore"_i18n, 0, [this, file_path, location](auto op_index){
|
||||||
if (op_index && *op_index) {
|
if (op_index && *op_index) {
|
||||||
App::Push<ProgressBox>(0, "Restore"_i18n, "", [this, file_path, location](auto pbox) -> Result {
|
App::Push<ProgressBox>(0, "Restore"_i18n, "", [this, file_path, location](auto pbox) -> Result {
|
||||||
@@ -871,7 +876,7 @@ auto Menu::BuildSavePath(const Entry& e, u32 flags) const -> fs::FsPath {
|
|||||||
if (flags & BackupFlag_SetName) {
|
if (flags & BackupFlag_SetName) {
|
||||||
std::string out;
|
std::string out;
|
||||||
while (out.empty()) {
|
while (out.empty()) {
|
||||||
const auto header = "Set name for "_i18n + e.GetName();
|
const auto header = i18n::Reorder("Set name for ", e.GetName());
|
||||||
if (R_FAILED(swkbd::ShowText(out, header.c_str(), "Set backup name", name, 1, 128))) {
|
if (R_FAILED(swkbd::ShowText(out, header.c_str(), "Set backup name", name, 1, 128))) {
|
||||||
out.clear();
|
out.clear();
|
||||||
}
|
}
|
||||||
@@ -1138,7 +1143,7 @@ Result Menu::BackupSaveInternal(ProgressBox* pbox, const dump::DumpLocation& loc
|
|||||||
|
|
||||||
// if we dumped the save to ram, flush the data to file.
|
// if we dumped the save to ram, flush the data to file.
|
||||||
if (!file_download) {
|
if (!file_download) {
|
||||||
pbox->NewTransfer("Flushing zip to file");
|
pbox->NewTransfer("Flushing zip to file"_i18n);
|
||||||
R_TRY(writer->SetSize(mz_mem.buf.size()));
|
R_TRY(writer->SetSize(mz_mem.buf.size()));
|
||||||
|
|
||||||
R_TRY(thread::Transfer(pbox, mz_mem.buf.size(),
|
R_TRY(thread::Transfer(pbox, mz_mem.buf.size(),
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> Result {
|
|||||||
|
|
||||||
// 1. download the zip
|
// 1. download the zip
|
||||||
if (!pbox->ShouldExit()) {
|
if (!pbox->ShouldExit()) {
|
||||||
pbox->NewTransfer("Downloading "_i18n + entry.details.name);
|
pbox->NewTransfer(i18n::Reorder("Downloading ", entry.details.name));
|
||||||
log_write("starting download\n");
|
log_write("starting download\n");
|
||||||
|
|
||||||
const auto url = apiBuildUrlDownloadPack(entry);
|
const auto url = apiBuildUrlDownloadPack(entry);
|
||||||
@@ -272,7 +272,7 @@ auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> Result {
|
|||||||
|
|
||||||
// 2. download the zip
|
// 2. download the zip
|
||||||
if (!pbox->ShouldExit()) {
|
if (!pbox->ShouldExit()) {
|
||||||
pbox->NewTransfer("Downloading "_i18n + entry.details.name);
|
pbox->NewTransfer(i18n::Reorder("Downloading ", entry.details.name));
|
||||||
log_write("starting download: %s\n", download_pack.url.c_str());
|
log_write("starting download: %s\n", download_pack.url.c_str());
|
||||||
|
|
||||||
const auto result = curl::Api().ToFile(
|
const auto result = curl::Api().ToFile(
|
||||||
@@ -383,13 +383,13 @@ Menu::Menu(u32 flags) : MenuBase{"Themezer"_i18n, flags} {
|
|||||||
const auto& entry = page.m_packList[m_index];
|
const auto& entry = page.m_packList[m_index];
|
||||||
const auto url = apiBuildUrlDownloadPack(entry);
|
const auto url = apiBuildUrlDownloadPack(entry);
|
||||||
|
|
||||||
App::Push<ProgressBox>(entry.themes[0].preview.lazy_image.image, "Downloading "_i18n, entry.details.name, [this, &entry](auto pbox) -> Result {
|
App::Push<ProgressBox>(entry.themes[0].preview.lazy_image.image, i18n::Reorder("Downloading ", entry.details.name), [this, &entry](auto pbox) -> Result {
|
||||||
return InstallTheme(pbox, entry);
|
return InstallTheme(pbox, entry);
|
||||||
}, [this, &entry](Result rc){
|
}, [this, &entry](Result rc){
|
||||||
App::PushErrorBox(rc, "Failed to download theme"_i18n);
|
App::PushErrorBox(rc, "Failed to download theme"_i18n);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
App::Notify("Downloaded "_i18n + entry.details.name);
|
App::Notify(i18n::Reorder("Downloaded ", entry.details.name));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ void Menu::Update(Controller* controller, TouchInfo* touch) {
|
|||||||
usbDsGetSpeed(&speed);
|
usbDsGetSpeed(&speed);
|
||||||
|
|
||||||
char buf[128];
|
char buf[128];
|
||||||
std::snprintf(buf, sizeof(buf), "State: %s | Speed: %s", i18n::get(GetUsbDsStateStr(state)).c_str(), i18n::get(GetUsbDsSpeedStr(speed)).c_str());
|
std::snprintf(buf, sizeof(buf), "State: %s | Speed: %s"_i18n.c_str(), i18n::get(GetUsbDsStateStr(state)).c_str(), i18n::get(GetUsbDsSpeedStr(speed)).c_str());
|
||||||
SetSubHeading(buf);
|
SetSubHeading(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,11 +90,11 @@ Menu::Menu(fs::Fs* fs, const fs::FsPath& path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_meta.artist.empty()) {
|
if (m_meta.artist.empty()) {
|
||||||
m_meta.artist = "Artist: Unknown";
|
m_meta.artist = "Artist: Unknown"_i18n;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_meta.album.empty()) {
|
if (m_meta.album.empty()) {
|
||||||
m_meta.album = "Album: Unknown";
|
m_meta.album = "Album: Unknown"_i18n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -121,13 +121,13 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
DevoptabForm::DevoptabForm(DevoptabType type, const MountConfig& config)
|
DevoptabForm::DevoptabForm(DevoptabType type, const MountConfig& config)
|
||||||
: FormSidebar{"Mount Creator"}
|
: FormSidebar{"Mount Creator"_i18n}
|
||||||
, m_type{type}
|
, m_type{type}
|
||||||
, m_config{config} {
|
, m_config{config} {
|
||||||
SetupButtons(false);
|
SetupButtons(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
DevoptabForm::DevoptabForm() : FormSidebar{"Mount Creator"} {
|
DevoptabForm::DevoptabForm() : FormSidebar{"Mount Creator"_i18n} {
|
||||||
SetupButtons(true);
|
SetupButtons(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +157,7 @@ void DevoptabForm::SetupButtons(bool type_change) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this->Add<SidebarEntryArray>(
|
this->Add<SidebarEntryArray>(
|
||||||
"Type", items, [this](s64& index) {
|
"Type"_i18n, items, [this](s64& index) {
|
||||||
m_type = TYPE_ENTRIES[index].type;
|
m_type = TYPE_ENTRIES[index].type;
|
||||||
UpdateSchemeURL();
|
UpdateSchemeURL();
|
||||||
},
|
},
|
||||||
@@ -167,67 +167,70 @@ void DevoptabForm::SetupButtons(bool type_change) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_name = this->Add<SidebarEntryTextInput>(
|
m_name = this->Add<SidebarEntryTextInput>(
|
||||||
"Name", m_config.name, "", "", -1, 32,
|
"Name"_i18n, m_config.name, "", "", -1, 32,
|
||||||
"Set the name of the application"_i18n
|
"Set the name of the application"_i18n
|
||||||
);
|
);
|
||||||
|
|
||||||
m_url = this->Add<SidebarEntryTextInput>(
|
m_url = this->Add<SidebarEntryTextInput>(
|
||||||
"URL", m_config.url, "", "", -1, PATH_MAX,
|
"URL"_i18n, m_config.url, "", "", -1, PATH_MAX,
|
||||||
"Set the URL of the application"_i18n
|
"Set the URL of the application"_i18n
|
||||||
);
|
);
|
||||||
|
|
||||||
m_port = this->Add<SidebarEntryTextInput>(
|
m_port = this->Add<SidebarEntryTextInput>(
|
||||||
"Port", m_config.port, "", "", 1, 5,
|
"Port"_i18n, m_config.port, "", "", 1, 5,
|
||||||
"Optional: Set the port of the server. If left empty, the default port for the protocol will be used."_i18n
|
"Optional: Set the port of the server. If left empty, the default port for the protocol will be used."_i18n
|
||||||
);
|
);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
m_timeout = this->Add<SidebarEntryTextInput>(
|
m_timeout = this->Add<SidebarEntryTextInput>(
|
||||||
"Timeout", m_config.timeout, "Timeout in milliseconds", 1, 5,
|
"Timeout"_i18n, m_config.timeout, "Timeout in milliseconds", 1, 5,
|
||||||
"Optional: Set the timeout in seconds."_i18n
|
"Optional: Set the timeout in seconds."_i18n
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_user = this->Add<SidebarEntryTextInput>(
|
m_user = this->Add<SidebarEntryTextInput>(
|
||||||
"User", m_config.user, "", "", -1, PATH_MAX,
|
"User"_i18n, m_config.user, "", "", -1, PATH_MAX,
|
||||||
"Optional: Set the username of the application"_i18n
|
"Optional: Set the username of the application"_i18n
|
||||||
);
|
);
|
||||||
|
|
||||||
m_pass = this->Add<SidebarEntryTextInput>(
|
m_pass = this->Add<SidebarEntryTextInput>(
|
||||||
"Pass", m_config.pass, "", "", -1, PATH_MAX,
|
"Pass"_i18n, m_config.pass, "", "", -1, PATH_MAX,
|
||||||
"Optional: Set the password of the application"_i18n
|
"Optional: Set the password of the application"_i18n
|
||||||
);
|
);
|
||||||
|
|
||||||
m_dump_path = this->Add<SidebarEntryTextInput>(
|
m_dump_path = this->Add<SidebarEntryTextInput>(
|
||||||
"Dump path", m_config.dump_path, "", "", -1, PATH_MAX,
|
"Dump path"_i18n, m_config.dump_path, "", "", -1, PATH_MAX,
|
||||||
"Optional: Set the dump path used when exporting games and saves."_i18n
|
"Optional: Set the dump path used when exporting games and saves."_i18n
|
||||||
);
|
);
|
||||||
|
|
||||||
this->Add<SidebarEntryBool>(
|
this->Add<SidebarEntryBool>(
|
||||||
"Read only", m_config.read_only,
|
"Read only"_i18n, m_config.read_only,
|
||||||
"Mount the filesystem as read only.\n\n"
|
i18n::get("mount_readonly_info",
|
||||||
"Setting this option also hidens the mount from being show as an export option."_i18n
|
"Mount the filesystem as read only.\n\n"
|
||||||
|
"Setting this option also hidens the mount from being show as an export option.")
|
||||||
);
|
);
|
||||||
|
|
||||||
this->Add<SidebarEntryBool>(
|
this->Add<SidebarEntryBool>(
|
||||||
"No stat file", m_config.no_stat_file,
|
"No stat file"_i18n, m_config.no_stat_file,
|
||||||
"Enabling stops the file browser from checking the file size and timestamp of each file. "
|
i18n::get("filecheck_disable_info",
|
||||||
"This improves browsing performance."_i18n
|
"Enabling stops the file browser from checking the file size and timestamp of each file. "
|
||||||
|
"This improves browsing performance.")
|
||||||
);
|
);
|
||||||
|
|
||||||
this->Add<SidebarEntryBool>(
|
this->Add<SidebarEntryBool>(
|
||||||
"No stat dir", m_config.no_stat_dir,
|
"No stat dir"_i18n, m_config.no_stat_dir,
|
||||||
"Enabling stops the file browser from checking how many files and folders are in a folder. "
|
i18n::get("dircheck_disable_info",
|
||||||
"This improves browsing performance, especially for servers that has slow directory listing."_i18n
|
"Enabling stops the file browser from checking how many files and folders are in a folder. "
|
||||||
|
"This improves browsing performance, especially for servers that has slow directory listing.")
|
||||||
);
|
);
|
||||||
|
|
||||||
this->Add<SidebarEntryBool>(
|
this->Add<SidebarEntryBool>(
|
||||||
"FS hidden", m_config.fs_hidden,
|
"FS hidden"_i18n, m_config.fs_hidden,
|
||||||
"Hide the mount from being visible in the file browser."_i18n
|
"Hide the mount from being visible in the file browser."_i18n
|
||||||
);
|
);
|
||||||
|
|
||||||
this->Add<SidebarEntryBool>(
|
this->Add<SidebarEntryBool>(
|
||||||
"Export hidden", m_config.dump_hidden,
|
"Export hidden"_i18n, m_config.dump_hidden,
|
||||||
"Hide the mount from being visible as a export option for games and saves."_i18n
|
"Hide the mount from being visible as a export option for games and saves."_i18n
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -236,7 +239,7 @@ void DevoptabForm::SetupButtons(bool type_change) {
|
|||||||
UpdateSchemeURL();
|
UpdateSchemeURL();
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto callback = this->Add<SidebarEntryCallback>("Save", [this](){
|
const auto callback = this->Add<SidebarEntryCallback>("Save"_i18n, [this](){
|
||||||
m_config.name = m_name->GetValue();
|
m_config.name = m_name->GetValue();
|
||||||
m_config.url = m_url->GetValue();
|
m_config.url = m_url->GetValue();
|
||||||
m_config.user = m_user->GetValue();
|
m_config.user = m_user->GetValue();
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ Result NszExport(ui::ProgressBox* pbox, const NcaReaderCreator& nca_creator, s64
|
|||||||
const auto section_number = std::distance(ncz_sections.begin(), section);
|
const auto section_number = std::distance(ncz_sections.begin(), section);
|
||||||
const auto rsize = section->size - (nca_off - section->offset);
|
const auto rsize = section->size - (nca_off - section->offset);
|
||||||
|
|
||||||
pbox->NewTransfer("Section #" + std::to_string(section_number) + " - " + collection.name);
|
pbox->NewTransfer("Section #"_i18n + std::to_string(section_number) + " - " + collection.name);
|
||||||
ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
|
ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
|
||||||
|
|
||||||
R_TRY(thread::Transfer(pbox, rsize,
|
R_TRY(thread::Transfer(pbox, rsize,
|
||||||
|
|||||||
Reference in New Issue
Block a user