From 8303440c19a4e6afe52e40b067a74b4b3b13a1fc Mon Sep 17 00:00:00 2001 From: Pk11 Date: Thu, 13 Oct 2022 21:58:12 -0500 Subject: [PATCH] Add loading translations from TRF Reduce pointer magic use Both translations and fonts --- arm9/source/common/ui.c | 112 +-- arm9/source/common/ui.h | 4 +- arm9/source/filesys/filetype.c | 2 + arm9/source/filesys/filetype.h | 4 +- arm9/source/godmode.c | 35 +- arm9/source/language.c | 136 ++- arm9/source/language.h | 9 +- arm9/source/{language.en.inl => language.inl} | 7 + arm9/source/language.ja.inl | 80 -- crowdin.yml | 7 + resources/gm9/languages/en.trf | Bin 0 -> 72 bytes resources/languages/en.json | 3 + resources/languages/source.json | 805 ++++++++++++++++++ utils/transriff.py | 66 ++ 14 files changed, 1130 insertions(+), 140 deletions(-) rename arm9/source/{language.en.inl => language.inl} (99%) delete mode 100644 arm9/source/language.ja.inl create mode 100644 crowdin.yml create mode 100644 resources/gm9/languages/en.trf create mode 100644 resources/languages/en.json create mode 100644 resources/languages/source.json create mode 100755 utils/transriff.py diff --git a/arm9/source/common/ui.c b/arm9/source/common/ui.c index 0f5f570..ee1a198 100644 --- a/arm9/source/common/ui.c +++ b/arm9/source/common/ui.c @@ -22,6 +22,17 @@ #define FONT_MAX_HEIGHT 10 #define PROGRESS_REFRESH_RATE 30 // the progress bar is only allowed to draw to screen every X milliseconds +typedef struct { + char chunk_id[4]; // NOT null terminated + u32 size; +} RiffChunkHeader; + +typedef struct { + u8 width; + u8 height; + u16 count; +} FontMeta; + static u32 font_width = 0; static u32 font_height = 0; static u32 font_count = 0; @@ -130,8 +141,8 @@ u32 GetCharacter(const char** str) return c; } -u8* GetFontFromPbm(const void* pbm, const u32 pbm_size, u32* w, u32* h) { - char* hdr = (char*) pbm; +const u8* GetFontFromPbm(const void* pbm, const u32 pbm_size, u32* w, u32* h) { + const char* hdr = (const char*) pbm; u32 hdr_max_size = min(512, pbm_size); u32 pbm_w = 0; u32 pbm_h = 0; @@ -192,40 +203,43 @@ u8* GetFontFromPbm(const void* pbm, const u32 pbm_size, u32* w, u32* h) { return (u8*) pbm + p; } -u8* GetFontFromRiff(const void* riff, const u32 riff_size, u32* w, u32* h, u16* count) { - u8 *ptr = (u8*) riff; - u8 riff_w = 0; - u8 riff_h = 0; - u16 riff_count = 0; +const u8* GetFontFromRiff(const void* riff, const u32 riff_size, u32* w, u32* h, u16* count) { + const void* ptr = riff; + const RiffChunkHeader* riff_header; + const RiffChunkHeader* chunk_header; - // check header magic, then skip over - if (memcmp(ptr, "RIFF", 4) != 0) return NULL; + // check header magic and load size + if (!ptr) return NULL; + riff_header = ptr; + if (memcmp(riff_header->chunk_id, "RIFF", 4) != 0) return NULL; // ensure enough space is allocated - u32 data_size; - memcpy(&data_size, ptr + 4, sizeof(u32)); - if (data_size > riff_size) return NULL; + if (riff_header->size > riff_size) return NULL; - ptr += 8; + ptr += sizeof(RiffChunkHeader); - // check for and load META section - if (memcmp(ptr, "META", 4) == 0) { - riff_w = ptr[8]; - riff_h = ptr[9]; - memcpy(&riff_count, ptr + 10, sizeof(u16)); + while ((u32)(ptr - riff) < riff_header->size + sizeof(RiffChunkHeader)) { + chunk_header = ptr; - u32 section_size; - memcpy(§ion_size, ptr + 4, sizeof(u32)); - ptr += 8 + section_size; + // check for and load META section + if (memcmp(chunk_header->chunk_id, "META", 4) == 0) { - if (riff_w > FONT_MAX_WIDTH || riff_h > FONT_MAX_HEIGHT) return NULL; - } else return NULL; + if (chunk_header->size != 4) return NULL; - // all good - if (w) *w = riff_w; - if (h) *h = riff_h; - if (count) *count = riff_count; - return ptr; + const FontMeta *meta = ptr + sizeof(RiffChunkHeader); + if (meta->width > FONT_MAX_WIDTH || meta->height > FONT_MAX_HEIGHT) return NULL; + + // all good + if (w) *w = meta->width; + if (h) *h = meta->height; + if (count) *count = meta->count; + return ptr; + } + + ptr += sizeof(RiffChunkHeader) + chunk_header->size; + } + + return NULL; } // sets the font from a given RIFF or PBM @@ -233,7 +247,7 @@ u8* GetFontFromRiff(const void* riff, const u32 riff_size, u32* w, u32* h, u16* bool SetFont(const void* font, u32 font_size) { u32 w, h; u16 count; - u8* ptr = NULL; + const u8* ptr = NULL; if (!font) { u64 font_size64 = 0; @@ -249,33 +263,31 @@ bool SetFont(const void* font, u32 font_size) { font_height = h; font_count = count; - // character data - if (memcmp(ptr, "CDAT", 4) == 0) { - u32 section_size; - memcpy(§ion_size, ptr + 4, sizeof(u32)); + const RiffChunkHeader* riff_header; + const RiffChunkHeader* chunk_header; - if (font_bin) free(font_bin); - font_bin = malloc(font_height * font_count); - if (!font_bin) return NULL; + // load total size + riff_header = font; - memcpy(font_bin, ptr + 8, font_height * font_count); + while (((u32)ptr - (u32)font) < riff_header->size + sizeof(RiffChunkHeader)) { + chunk_header = (const void *)ptr; - ptr += 8 + section_size; - } else return NULL; + if (memcmp(chunk_header->chunk_id, "CDAT", 4) == 0) { // character data + if (font_bin) free(font_bin); + font_bin = malloc(font_height * font_count); + if (!font_bin) return NULL; - // character map - if (memcmp(ptr, "CMAP", 4) == 0) { - u32 section_size; - memcpy(§ion_size, ptr + 4, sizeof(u32)); + memcpy(font_bin, ptr + sizeof(RiffChunkHeader), font_height * font_count); + } else if (memcmp(chunk_header->chunk_id, "CMAP", 4) == 0) { // character map + if (font_map) free(font_map); + font_map = malloc(sizeof(u16) * font_count); + if (!font_map) return NULL; - if (font_map) free(font_map); - font_map = malloc(sizeof(u16) * font_count); - if (!font_map) return NULL; + memcpy(font_map, ptr + sizeof(RiffChunkHeader), sizeof(u16) * font_count); + } - memcpy(font_map, ptr + 8, sizeof(u16) * font_count); - - ptr += 8 + section_size; - } else return NULL; + ptr += sizeof(RiffChunkHeader) + chunk_header->size; + } } else if ((ptr = GetFontFromPbm(font, font_size, &w, &h))) { font_count = 0x100; diff --git a/arm9/source/common/ui.h b/arm9/source/common/ui.h index ee20da8..4f51c0b 100644 --- a/arm9/source/common/ui.h +++ b/arm9/source/common/ui.h @@ -50,8 +50,8 @@ bool PRINTF_ARGS(2) ShowUnlockSequence(u32 seqlvl, const char *format, ...); #define ShowUnlockSequence ShowPrompt #endif -u8* GetFontFromPbm(const void* pbm, const u32 riff_size, u32* w, u32* h); -u8* GetFontFromRiff(const void* riff, const u32 riff_size, u32* w, u32* h, u16* count); +const u8* GetFontFromPbm(const void* pbm, const u32 riff_size, u32* w, u32* h); +const u8* GetFontFromRiff(const void* riff, const u32 riff_size, u32* w, u32* h, u16* count); bool SetFont(const void* font, const u32 font_size); u16 GetColor(const u16 *screen, int x, int y); diff --git a/arm9/source/filesys/filetype.c b/arm9/source/filesys/filetype.c index baa090e..a083e81 100644 --- a/arm9/source/filesys/filetype.c +++ b/arm9/source/filesys/filetype.c @@ -129,6 +129,8 @@ u64 IdentifyFileType(const char* path) { return FONT_PBM; } else if (GetFontFromRiff(data, fsize, NULL, NULL, NULL)) { return FONT_RIFF; + } else if (GetLanguage(data, fsize, NULL, NULL, NULL)) { + return TRANSLATION; } else if ((fsize > sizeof(AgbHeader)) && (ValidateAgbHeader((AgbHeader*) data) == 0)) { return GAME_GBA; diff --git a/arm9/source/filesys/filetype.h b/arm9/source/filesys/filetype.h index de963af..b750e1e 100644 --- a/arm9/source/filesys/filetype.h +++ b/arm9/source/filesys/filetype.h @@ -39,6 +39,7 @@ #define FONT_RIFF (1ULL<<34) #define NOIMG_NAND (1ULL<<35) #define HDR_NAND (1ULL<<36) +#define TRANSLATION (1ULL<<37) #define TYPE_BASE 0xFFFFFFFFFFULL // 40 bit reserved for base types // #define FLAG_FIRM (1ULL<<58) // <--- for CXIs containing FIRMs @@ -77,8 +78,9 @@ #define FTYPE_KEYINSTALL(tp) (tp&(BIN_KEYDB)) #define FTYPE_SCRIPT(tp) (tp&(TXT_SCRIPT)) #define FTYPE_FONT(tp) (tp&(FONT_PBM|FONT_RIFF)) +#define FTYPE_TRANSLATION(tp) (tp&(TRANSLATION)) #define FTYPE_GFX(tp) (tp&(GFX_PNG)) -#define FTYPE_SETABLE(tp) (tp&(FONT_PBM|FONT_RIFF)) +#define FTYPE_SETABLE(tp) (tp&(FONT_PBM|FONT_RIFF|TRANSLATION)) #define FTYPE_BOOTABLE(tp) (tp&(SYS_FIRM)) #define FTYPE_INSTALLABLE(tp) (tp&(SYS_FIRM)) #define FTYPE_AGBSAVE(tp) (tp&(SYS_AGBSAVE)) diff --git a/arm9/source/godmode.c b/arm9/source/godmode.c index 4cadea0..e914415 100644 --- a/arm9/source/godmode.c +++ b/arm9/source/godmode.c @@ -1185,6 +1185,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan bool keyinstallable = (FTYPE_KEYINSTALL(filetype)) && !((drvtype & DRV_VIRTUAL) && (drvtype & DRV_SYSNAND)); bool scriptable = (FTYPE_SCRIPT(filetype)); bool fontable = (FTYPE_FONT(filetype)); + bool translationable = (FTYPE_TRANSLATION(filetype)); bool viewable = (FTYPE_GFX(filetype)); bool setable = (FTYPE_SETABLE(filetype)); bool bootable = (FTYPE_BOOTABLE(filetype)); @@ -1205,8 +1206,8 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan mountable || verificable || decryptable || encryptable || cia_buildable || cia_buildable_legit || cxi_dumpable || tik_buildable || key_buildable || titleinfo || renamable || trimable || transferable || hsinjectable || restorable || xorpadable || ebackupable || ncsdfixable || extrcodeable || keyinitable || - keyinstallable || bootable || scriptable || fontable || viewable || installable || agbexportable || - agbimportable || cia_installable || tik_installable || tik_dumpable || cif_installable; + keyinstallable || bootable || scriptable || fontable || translationable || viewable || installable || + agbexportable || agbimportable || cia_installable || tik_installable || tik_dumpable || cif_installable; char pathstr[UTF_BUFFER_BYTESIZE(32)]; TruncateString(pathstr, file_path, 32, 8); @@ -1290,6 +1291,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan (filetype & BIN_NCCHNFO)? STR_NCCHINFO_OPTIONS : (filetype & TXT_SCRIPT) ? STR_EXECUTE_GM9_SCRIPT : (FTYPE_FONT(filetype)) ? STR_FONT_OPTIONS : + (filetype & TRANSLATION)? STR_LANGUAGE_OPTIONS : (filetype & GFX_PNG) ? STR_VIEW_PNG_FILE : (filetype & HDR_NAND) ? STR_REBUILD_NCSD_HEADER : (filetype & NOIMG_NAND) ? STR_REBUILD_NCSD_HEADER : "???"; @@ -1452,6 +1454,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan int boot = (bootable) ? ++n_opt : -1; int script = (scriptable) ? ++n_opt : -1; int font = (fontable) ? ++n_opt : -1; + int translation = (translationable) ? ++n_opt : -1; int view = (viewable) ? ++n_opt : -1; int agbexport = (agbexportable) ? ++n_opt : -1; int agbimport = (agbimportable) ? ++n_opt : -1; @@ -1489,6 +1492,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan if (script > 0) optionstr[script-1] = STR_EXECUTE_GM9_SCRIPT; if (view > 0) optionstr[view-1] = STR_VIEW_PNG_FILE; if (font > 0) optionstr[font-1] = STR_SET_AS_ACTIVE_FONT; + if (translation > 0) optionstr[translation-1] = STR_SET_AS_ACTIVE_LANGUAGE; if (agbexport > 0) optionstr[agbexport-1] = STR_DUMP_BA_VC_SAVE; if (agbimport > 0) optionstr[agbimport-1] = STR_INJECT_GBA_VC_SAVE; if (setup > 0) optionstr[setup-1] = STR_SET_AS_DEFAULT; @@ -2143,6 +2147,15 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan free(font); return 0; } + else if (user_select == translation) { // set translation + u8* translation = (u8*) malloc(0x20000); // arbitrary, should be enough by far + if (!translation) return 1; + u32 translation_size = FileGetData(file_path, translation, 0x20000, 0); + if (translation_size) SetLanguage(translation, translation_size); + ClearScreenF(true, true, COLOR_STD_BG); + free(translation); + return 0; + } else if (user_select == view) { // view gfx if (FileGraphicsViewer(file_path) != 0) ShowPrompt(false, "%s\n%s", pathstr, STR_ERROR_CANNOT_VIEW_FILE); @@ -2171,6 +2184,9 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan } else if (filetype & FONT_PBM) { if (SetAsSupportFile("font.pbm", file_path)) ShowPrompt(false, "%s\n%s", pathstr, STR_FONT_WILL_BE_ACTIVE_ON_NEXT_BOOT); + } else if (filetype & TRANSLATION) { + if (SetAsSupportFile("language.trf", file_path)) + ShowPrompt(false, "%s\n%s", pathstr, STR_LANGUAGE_WILL_BE_ACTIVE_ON_NEXT_BOOT); } return 0; } @@ -2417,6 +2433,21 @@ u32 GodMode(int entrypoint) { } } + // language handling + bool language_loaded = false; + if (CheckSupportFile("language.trf")) { + char* translation = (char*) malloc(0x20000); // arbitrary, should be enough by far + if (translation) { + u32 translation_size = LoadSupportFile("language.trf", translation, 0x20000); + if (translation_size) language_loaded = SetLanguage(translation, translation_size); + free(translation); + } + } + + if (!language_loaded) { + SetLanguage(NULL, 0); + } + // check for embedded essential backup if (((entrypoint == ENTRY_NANDBOOT) || (entrypoint == ENTRY_B9S)) && !PathExist("S:/essential.exefs") && CheckGenuineNandNcsd() && diff --git a/arm9/source/language.c b/arm9/source/language.c index 3756cb6..f0a1259 100644 --- a/arm9/source/language.c +++ b/arm9/source/language.c @@ -1,5 +1,135 @@ -#define STRING(what, def) const char *STR_##what = def; -#include "language.en.inl" +#include "language.h" + +#define STRING(what, def) const char* STR_##what = NULL; +#include "language.inl" #undef STRING -// TODO read from file +static const char** translation_ptrs[] = { + #define STRING(what, def) &STR_##what, + #include "language.inl" + #undef STRING +}; + +static const char* translation_fallbacks[] = { + #define STRING(what, def) def, + #include "language.inl" + #undef STRING +}; + +static char* translation_data = NULL; + +typedef struct { + char name[32]; + char path[256]; +} Language; + +typedef struct { + char chunk_id[4]; // NOT null terminated + u32 size; +} RiffChunkHeader; + +typedef struct { + u32 version; + u32 count; + char languageName[32]; +} LanguageMeta; +STATIC_ASSERT(sizeof(LanguageMeta) == 40); + +bool SetLanguage(const void* translation, u32 translation_size) { + u32 str_count; + const void* ptr = translation; + const RiffChunkHeader* riff_header; + const RiffChunkHeader* chunk_header; + + // Free old translation data + if (translation_data) { + free(translation_data); + translation_data = NULL; + } + + if ((ptr = GetLanguage(translation, translation_size, NULL, &str_count, NULL))) { + // load total size + riff_header = translation; + + while ((u32)(ptr - translation) < riff_header->size + sizeof(RiffChunkHeader)) { + chunk_header = ptr; + + if (memcmp(chunk_header->chunk_id, "SDAT", 4) == 0) { // string data + if (chunk_header->size > 0) { + translation_data = malloc(chunk_header->size); + if (!translation_data) goto fallback; + + memcpy(translation_data, ptr + sizeof(RiffChunkHeader), chunk_header->size); + } + } else if (memcmp(chunk_header->chunk_id, "SMAP", 4) == 0) { // string map + // string data must come before the map + if (!translation_data && str_count > 0) goto fallback; + + u16* string_map = (u16*)(ptr + sizeof(RiffChunkHeader)); + + // Load all the strings + for (u32 i = 0; i < countof(translation_ptrs); i++) { + if (i < str_count) { + *translation_ptrs[i] = (translation_data + string_map[i]); + } else { + *translation_ptrs[i] = translation_fallbacks[i]; + } + } + } + + ptr += sizeof(RiffChunkHeader) + chunk_header->size; + } + + return true; + } + +fallback: + if (translation_data) { + free(translation_data); + translation_data = NULL; + } + + for (u32 i = 0; i < countof(translation_ptrs); i++) { + *translation_ptrs[i] = translation_fallbacks[i]; + } + + return false; +} + +const void* GetLanguage(const void* riff, const u32 riff_size, u32* version, u32* count, char* language_name) { + const void* ptr = riff; + const RiffChunkHeader* riff_header; + const RiffChunkHeader* chunk_header; + + // check header magic and load size + if (!ptr) return NULL; + riff_header = ptr; + if (memcmp(riff_header->chunk_id, "RIFF", 4) != 0) return NULL; + + // ensure enough space is allocated + if (riff_header->size > riff_size) return NULL; + + ptr += sizeof(RiffChunkHeader); + + while ((u32)(ptr - riff) < riff_header->size + sizeof(RiffChunkHeader)) { + chunk_header = ptr; + + // check for and load META section + if (memcmp(chunk_header->chunk_id, "META", 4) == 0) { + if (chunk_header->size != sizeof(LanguageMeta)) return NULL; + + const LanguageMeta *meta = ptr + sizeof(RiffChunkHeader); + if (meta->version != TRANSLATION_VER || meta->count > countof(translation_ptrs)) return NULL; + + // all good + if (version) *version = meta->version; + if (count) *count = meta->count; + if (language_name) strcpy(language_name, meta->languageName); + return ptr; + } + + ptr += sizeof(RiffChunkHeader) + chunk_header->size; + } + + return NULL; +} diff --git a/arm9/source/language.h b/arm9/source/language.h index 9b8088d..a548322 100644 --- a/arm9/source/language.h +++ b/arm9/source/language.h @@ -1,5 +1,10 @@ #pragma once -#define STRING(what, def) extern const char *STR_##what; -#include "language.en.inl" +#include "common.h" + +#define STRING(what, def) extern const char* STR_##what; +#include "language.inl" #undef STRING + +bool SetLanguage(const void* translation, u32 translation_size); +const void* GetLanguage(const void* riff, u32 riff_size, u32* version, u32* count, char* language_name); diff --git a/arm9/source/language.en.inl b/arm9/source/language.inl similarity index 99% rename from arm9/source/language.en.inl rename to arm9/source/language.inl index ae0078e..8a5f0a7 100644 --- a/arm9/source/language.en.inl +++ b/arm9/source/language.inl @@ -1,3 +1,7 @@ +// This is to be incremented every time the order changes +// New strings added to the end will not cause issues +#define TRANSLATION_VER 1 + STRING(DATE_TIME_FORMAT, "%1$s%2$02lX-%3$02lX-%4$02lX %5$02lX:%6$02lX") STRING(DECIMAL_SEPARATOR, ".") STRING(THOUSAND_SEPARATOR, ",") @@ -180,6 +184,7 @@ STRING(BUILD_X, "Build %s") STRING(NCCHINFO_OPTIONS, "NCCHinfo options...") STRING(EXECUTE_GM9_SCRIPT, "Execute GM9 script") STRING(FONT_OPTIONS, "Font options...") +STRING(LANGUAGE_OPTIONS, "Language options...") STRING(VIEW_PNG_FILE, "View PNG file") STRING(REBUILD_NCSD_HEADER, "Rebuild NCSD header") STRING(SHOW_IN_HEXEDITOR, "Show in Hexeditor") @@ -234,6 +239,7 @@ STRING(INSTALL_X, "Install %s") STRING(INSTALL_FIRM, "Install FIRM") STRING(BOOT_FIRM, "Boot FIRM") STRING(SET_AS_ACTIVE_FONT, "Set as active font") +STRING(SET_AS_ACTIVE_LANGUAGE, "Set as active language") STRING(DUMP_BA_VC_SAVE, "Dump GBA VC save") STRING(INJECT_GBA_VC_SAVE, "Inject GBA VC save") STRING(SET_AS_DEFAULT, "Set as default") @@ -367,6 +373,7 @@ STRING(GBA_SAVEGAME_MUST_BE_IN_CLIPBOARD, "GBA VC savegame has to\nbe in the cli STRING(SAVEGAME_INJECT_SUCCESS, "Savegame inject success.") STRING(SAVEGAME_INJECT_FAILED, "Savegame inject failed!") STRING(FONT_WILL_BE_ACTIVE_ON_NEXT_BOOT, "Font will be active on next boot") +STRING(LANGUAGE_WILL_BE_ACTIVE_ON_NEXT_BOOT, "Language will be active on next boot") STRING(HOME_MORE_MENU_SELECT_ACTION, "HOME more... menu.\nSelect action:") STRING(SD_FORMAT_MENU, "SD format menu") STRING(BONUS_DRIVE_MENU, "Bonus drive setup") diff --git a/arm9/source/language.ja.inl b/arm9/source/language.ja.inl deleted file mode 100644 index e2d701c..0000000 --- a/arm9/source/language.ja.inl +++ /dev/null @@ -1,80 +0,0 @@ -STRING(PATH_FIRM_TOO_BIG, "%s\nFIRMは大きすぎる。 起動できません。") -STRING(PATH_DO_NOT_BOOT_UNTRUSTED, "%s (%dkB)\n注意: 信頼できないソースから\nFIRMを起動しないでください。\n \nFIRMを起動?") -STRING(NOT_BOOTABLE_FIRM, "%s\n起動できるFIRMではない。") -STRING(PATH_FIRM_ENCRYPTED, "%s\nFIRMは暗号化されている。\n \n起動前に復号化しますか?") -STRING(MAKE_COPY_AT_OUT_TEMP_FIRM, "%s/temp.firmにコピーを作成しますか?") -STRING(TRY_BOOT_ANYWAYS, "とにかく起動してみる") -STRING(PATH_WARNING_BOOT_UNSUPPORTED_LOCATION, "%s\n注意: サポートされていない場所から起動を試みています。") -STRING(ROOT, "[ルート]") -STRING(LOADING, "ロード中……") -STRING(PANE_N, "ペイン第%luつ") -STRING(CURRENT, "現在") -STRING(DIR, "(dir)") -STRING(SD_FAT, "(SD FAT)") -STRING(RAMDRIVE_FAT, "(RAMドライブFAT)") -STRING(GAME_VIRTUAL, "(ゲームバーチャル)") -STRING(SYSNAND_FAT, "(システムNAND FAT)") -STRING(SYSNAND_VIRTUAL, "(システムNANDバーチャル)") -STRING(EMUNAND_FAT, "(エミュNAND FAT)") -STRING(EMUNAND_VIRTUAL, "(エミュNANDバーチャル)") -STRING(IMAGE_FAT, "(イメージFAT)") -STRING(XORPAD_VIRTUAL, "(XORパッドバーチャル)") -STRING(MEMORY_VIRTUAL, "(メモリバーチャル)") -STRING(ALIAS_FAT, "(エイリアスFAT)") -STRING(GAMECART_VIRTUAL, "(ゲームカートバーチャル)") -STRING(VRAM_VIRTUAL, "(VRAMバーチャル)") -STRING(SEARCH, "(検索))") -STRING(TITLEMANAGER_VIRTUAL, "(タイトルマネージャーバーチャル)") -STRING(N_BYTE, "%sバイト") -STRING(CLIPBOARD, "[クリップボード]") -STRING(PLUS_N_MORE, "+ と%lu個") -STRING(MARK_DELETE_COPY, "L - ファイルをマーク(↑↓→←と使用)\nX - ファイルを削除 / [+R] 名前を変更\nY - ファイルをコピー / [+R] エントリを作成\n") -STRING(MARK_DELETE_PASTE, "L - ファイルをマーク(↑↓→←と使用)\nX - ファイルを削除 / [+R] 名前を変更\nY - ファイルを貼り付ける / [+R] エントリを作成\n") -STRING(RELOCK_WRITE_PERMISSION, "R+Y - 書き込みの許可を再ロック\n") -STRING(UNMOUNT_IMAGE, "R+X - イメージをマウント解除\n") -STRING(UNMOUNT_SD, "R+B - SDカードをマウント解除\n") -STRING(REMOUNT_SD, "R+B - SDカードを再マウント\n") -STRING(DIRECTORY_OPTIONS, "R+A - ディレクトリオプション\n") -STRING(DRIVE_OPTIONS, "R+A - ドライブオプション\n") -STRING(MAKE_SCREENSHOT, "R+L - スクリーンショットを作成\n") -STRING(PREV_NEXT_PANE, "R+←→ - 前・次のペインに切り替える\n") -STRING(CLEAR_CLIPBOARD, "SELECT - クリップポードの消去\n") -STRING(RESTORE_CLIPBOARD, "SELECT - クリップボードの復元\n") -STRING(REBOOT_POWEROFF_HOME, "START - 再起動 / [+R] 電源オフ\nHOMEボタンでHOMEメニュー") -STRING(NO_EMUNAND, "EmuNANDなし") -STRING(REDNAND_SIZE_MIN, "RedNANDサイズ(最低)") -STRING(GW_EMUNAND_SIZE_FULL, "GWエミュNANDサイズ(フル)") -STRING(MULTINAND_SIZE_2X, "マルチNANDサイズ(2x)") -STRING(MULTINAND_SIZE_3X, "マルチNANDサイズ(3x)") -STRING(MULTINAND_SIZE_4X, "マルチNANDサイズ(4x)") -STRING(USER_INPUT, "ユーザー入力……") -STRING(AUTO, "自動") -STRING(16KB_CLUSTERS, "16KBクラスター") -STRING(32KB_CLUSTERS, "32KBクラスター") -STRING(64KB_CLUSTERS, "64KBクラスター") -STRING(SD_NOT_DETECTED, "エラー: SDカードを検出されない") -STRING(FORMAT_SD_CHOOSE_EMUNAND, "SDカード(%lluMB)をフォーマットしますか?\nエミュNANDサイズを選択さてください。") -STRING(SD_SIZE_IS_ENTER_EMUNAND_SIZE, "SDカードサイズは%lluMB。\nエミュNANDサイズ(MB)をいかに入力してください。") -STRING(FORMAT_SD_CHOOSE_CLUSTER, "SDカード(%lluMB)をフォーマットしますか?\nクラスターサイズを選択してください。") -STRING(FORMAT_SD_ENTER_LABEL, "SDカード(%lluMB)をフォーマットしますか?\nラベルを入力してください。") -STRING(FORMAT_SD_FAILED, "SDのフォーマット:失敗!") -STRING(REDNAND_TYPE, "RedNANDタイプ") -STRING(REDNAND_TYPE_MULTI, "RedNANDタイプ(マルチ)") -STRING(REDNAND_TYPE_SINGLE, "RedNAND type (シングル))") -STRING(GW_EMUNAND_TYPE, "GWエミュNANDタイプ") -STRING(DONT_SET_UP, "設定しない") -STRING(CHOOSE_EMUNAND_TYPE, "設定されるエミュNANDタイプを選択してください。") -STRING(CLONE_SYSNAND_TO_REDNAND, "RedNANDにSysNANDをコピーしますか?") -STRING(CLONING_SYSNAND_TO_EMUNAND_FAILED, "エミュNANDにSysNANDをコピー: 失敗!") -STRING(PRESS_A_TO_CONTINUE, "を押して続ける") -STRING(HEXEDITOR_CONTROLS, "16進エディターのコントロール:\n \n↑↓→←(+R) - スクロール\nR+Y - 表示を切り替える\nX - 検索・移動……\nA - 編集モードにする\nA+↑↓→← - 値を編集\nB - 終了\n") -STRING(NOT_FOUND, "見つけない!") -STRING(GO_TO_OFFSET, "オフセットへ移動") -STRING(SEARCH_FOR_STRING, "文字列で検索") -STRING(SEARCH_FOR_DATA, "データで検索") -STRING(CURRENT_OFFSET_SELECT_ACTION, "現在のオフセット: %08lX\nアクションを選択:") -STRING(CURRENT_OFFSET_ENTER_NEW, "現在のオフセット: %08lX\n以下に新しいオフセットを入力してください。") -STRING(ENTER_SEARCH_REPEAT_SEARCH, "以下に検索する文字列を入力してください。\n(R+Xで検索を繰り返します)") -STRING(MADE_EDITS_SAVE_CHANGES, "%i個の場所で変更されました。\n変更をファイルに書き込みますか?") -STRING(FAILED_WRITING_TO_FILE, "ファイルに書き込みに失敗しました!") -STRING(CALCULATING_SHA_FAILED, "SHA-%sを計算する: 失敗!") diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 0000000..863c759 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,7 @@ +project_id_env: GM9_CROWDIN_ID +api_token_env: CROWDIN_TOKEN +preserve_hierarchy: true + +files: + - source: /resources/languages/source.json + translation: /resources/languages/%two_letters_code%.json diff --git a/resources/gm9/languages/en.trf b/resources/gm9/languages/en.trf new file mode 100644 index 0000000000000000000000000000000000000000..e3888ff43e84167eae575c0d16e9474db72613c5 GIT binary patch literal 72 vcmWIYbaQiHU|{fd4RO=}(u_b10 to continue", + "HEXEDITOR_CONTROLS": "Hexeditor Controls:\n \n↑↓→←(+R) - Scroll\nR+Y - Switch view\nX - Search / goto...\nA - Enter edit mode\nA+↑↓→← - Edit value\nB - Exit\n", + "NOT_FOUND": "Not found!", + "GO_TO_OFFSET": "Go to offset", + "SEARCH_FOR_STRING": "Search for string", + "SEARCH_FOR_DATA": "Search for data", + "CURRENT_OFFSET_SELECT_ACTION": "Current offset: %08lX\nSelect action:", + "CURRENT_OFFSET_ENTER_NEW": "Current offset: %08lX\nEnter new offset below.", + "ENTER_SEARCH_REPEAT_SEARCH": "Enter search string below.\n(R+X to repeat search)", + "MADE_EDITS_SAVE_CHANGES": "You made edits in %lu place(s).\nWrite changes to file?", + "FAILED_WRITING_TO_FILE": "Failed writing to file!", + "CALCULATING_SHA_FAILED": "Calculating SHA-%s: failed!", + "SHA_VERIFICATION_PASSED": "\nSHA verification: passed!", + "SHA_VERIFICATION_FAILED": "\nSHA verification: failed", + "IDENTICAL_WITH_PREVIOUS": "\n \nIdentical with previous file:\n", + "WRITE_SHA_FILE": "\n \nWrite .SHA file?", + "WRITE_SHA1_FILE": "\n \nWrite .SHA1 file?", + "CALCULATING_CMAC_FAILED": "Calculating CMAC: failed!", + "CMAC_VERIFICATION_PASSED": "CMAC verification: passed!", + "CMAC_VERIFICATION_FAILED": "CMAC verification: failed!", + "FIX_CMAC_IN_FILE": "\n \nFix CMAC in file?", + "FIXING_CMAC_FAILED": "Fixing CMAC: failed!", + "COPY_ALL_SELECTED_ITEMS": "Copy all %lu selected items?", + "FAILED_COPYING_ITEM": "Failed copying item", + "ITEMS_COPIED_TO_OUT": "%lu items copied to %s", + "PATH_COPIED_TO_OUT": "%s\nCopied to %s", + "CART_INIT_FAILED": "Cart init failed!", + "CART_DETECTED_SIZE_INPUT_BELOW": "Cart: %s\nDetected size: %s\n \nInput dump size below.", + "NDS_CART_DECRYPT_SECURE_AREA": "Cart: %s\nNDS cart detected\nDecrypt the secure area?", + "FAILED_DUMPING_CART": "%s\nFailed dumping cart", + "PATH_DUMPED_TO_OUT": "%s\nDumped to %s", + "CREATED": "created", + "MODIFIED": "modified", + "ANALYZING_DRIVE": "Analyzing drive, please wait...", + "ANALYZING_DIR": "Analyzing dir, please wait...", + "N_FILES_N_SUBDIRS_TOTAL_SIZE_FREE_USED_TOTAL": "%lu files & %lu subdirs\n%s total size\n \nspace free: %s\nspace used: %s\nspace total: %s", + "N_FILES_N_SUBDIRS_TOTAL_SIZE": "%lu files & %lu subdirs\n%s total size", + "FILESIZE_X": "filesize: %s", + "READONLY_HIDDEN_SYSTEM_ARCHIVE_VIRTUAL": " \n[%c] %sread-only [%c] %shidden\n[%c] %ssystem [%c] %sarchive\n[%c] %svirtual\n%s", + "UDRL_CHANGE_ATTRIBUTES": " \n(↑↓→← to change attributes)\n", + "A_TO_CONTINUE": "( to continue)", + "A_APPLY_B_CANCEL": "( to apply, to cancel)", + "A_YES_B_NO": "( yes, no)", + "A_SELECT_B_CANCEL": "( select, cancel)", + "HOLD_B_TO_CANCEL": "(hold B to cancel)", + "FAILED_TO_SET_ATTRIBUTES": "Failed to set attributes!", + "NAND_IMAGE_OPTIONS": "NAND image options...", + "CTRNAND_OPTIONS": "CTRNAND options...", + "MOUNT_FAT_IMAGE": "Mount as FAT image", + "CIA_IMAGE_OPTIONS": "CIA image options...", + "NCSD_IMAGE_OPTIONS": "NCSD image options...", + "NCCH_IMAGE_OPTIONS": "NCCH image options...", + "MOUNT_AS_EXEFS_IMAGE": "Mount as EXEFS image", + "MOUNT_AS_ROMFS_IMAGE": "Mount as ROMFS image", + "TMD_FILE_OPTIONS": "TMD file options...", + "TMD_CDN_OPTIONS": "TMD/CDN options...", + "TMD_TWL_OPTIONS": "TMD/TWL options...", + "MANAGE_TITLE": "Manage Title...", + "BOSS_FILE_OPTIONS": "BOSS file options...", + "DECRYPT_NUS_CDN_FILE": "Decrypt NUS/CDN file", + "SHOW_SMDH_TITLE_INFO": "Show SMDH title info", + "NDS_IMAGE_OPTIONS": "NDS image options...", + "GBA_IMAGE_OPTIONS": "GBA image options...", + "TICKET_OPTIONS": "Ticket options...", + "TAD_IMAGE_OPTIONS": "TAD image options...", + "SHOW_3DSX_TITLE_INFO": "Show 3DSX title info", + "FIRM_IMAGE_OPTIONS": "FIRM image options...", + "AGBSAVE_OPTIONS": "AGBSAVE options...", + "DUMP_GBA_VC_SAVE": "Dump GBA VC save", + "TICKET_DB_OPTIONS": "Ticket.db options...", + "MOUNT_AS_DIFF_IMAGE": "Mount as DIFF image", + "MOUNT_AS_DISA_IAMGE": "Mount as DISA image", + "INSTALL_CIFINISH_BIN": "Install cifinish.bin", + "TITLEKEY_OPTIONS": "Titlekey options...", + "AESKEYDB_OPTIONS": "AESkeydb options...", + "BUILD_X": "Build %s", + "NCCHINFO_OPTIONS": "NCCHinfo options...", + "EXECUTE_GM9_SCRIPT": "Execute GM9 script", + "FONT_OPTIONS": "Font options...", + "LANGUAGE_OPTIONS": "Language options...", + "VIEW_PNG_FILE": "View PNG file", + "REBUILD_NCSD_HEADER": "Rebuild NCSD header", + "SHOW_IN_HEXEDITOR": "Show in Hexeditor", + "CALCULATE_SHA256": "Calculate SHA-256", + "CALCULATE_SHA1": "Calculate SHA-1", + "SHOW_FILE_INFO": "Show file info", + "SHOW_IN_TEXTVIEWER": "Show in Textviewer", + "CALCULATE_CMAC": "Calculate CMAC", + "COPY_TO_OUT": "Copy to %s", + "DUMP_TO_OUT": "Dump to %s", + "INJECT_DATA_AT_OFFSET": "Inject data @offset", + "OPEN_THIS_FOLDER": "Open this folder", + "OPEN_CONTAINING_FOLDER": "Open containing folder", + "OPEN_TITLE_FOLDER": "Open title folder", + "PATH_N_FILES_SELECTED": "%s\n(%lu files selected)", + "CHECK_CURRENT_CMAC_ONLY": "Check current CMAC only", + "VERIFY_CMAC_FOR_ALL": "Verify CMAC for all", + "FIX_CMAC_FOR_ALL": "Fix CMAC for all", + "N_N_N_FILES_OK_FIXED_TOTAL_N_OF_N_HAVE_NO_CMAC": "%lu/%lu/%lu files ok/fixed/total\n%lu/%lu have no CMAC", + "N_OF_N_FILES_VERIFIED_N_OF_N_FILES_FIXED": "%lu/%lu files verified ok\n%lu/%lu files fixed", + "N_OF_N_FILES_VERIFIED_N_OF_N_HAVE_NO_CMAC": "%lu/%lu files verified ok\n%lu/%lu have no CMAC", + "N_OF_N_FILES_VERIFIED": "%lu/%lu files verified ok", + "INJECT_DATA_FROM_SPECIFY_OFFSET_BELOW": "Inject data from %s?\nSpecify offset below.", + "FAILED_INJECTING_PATH": "Failed injecting %s", + "MOUNT_CXI_NDS_TO_DRIVE": "Mount CXI/NDS to drive", + "MOUNT_IMAGE_TO_DRIVE": "Mount image to drive", + "RESTORE_SYSNAND_SAFE": "Restore SysNAND (safe)", + "UPDATE_EMBEDDED_BACKUP": "Update embedded backup", + "SHOW_TITLE_INFO": "Show title info", + "DECRYPT_FILE": "Decrypt file (...)", + "DECRYPT_FILE_OUT": "Decrypt file (%s)", + "ENCRYPT_FILE": "Encrypt file (...)", + "ENCRYPT_FILE_OUT": "Encrypt file (%s)", + "BUILD_CIA_FROM_FILE": "Build CIA from file", + "BUILD_CIA_STANDARD": "Build CIA (standard)", + "BUILD_CIA_LEGIT": "Build CIA (legit)", + "DUMP_CXI_NDS_FILE": "Dump CXI/NDS file", + "INSTALL_GAME_IMAGE": "Install game image", + "INSTALL_TICKET": "Install ticket", + "DUMP_TICKET_FILE": "Dump ticket file", + "UNINSTALL_TITLE": "Uninstall title", + "VERIFY_FILE": "Verify file", + "TRANSFER_IMAGE_TO_CTRNAND": "Transfer image to CTRNAND", + "INJECT_TO_H_AND_S": "Inject to H&S", + "TRIM_FILE": "Trim file", + "RENAME_FILE": "Rename file", + "BUILD_XORPADS_SD": "Build XORpads (SD output)", + "BUILD_XORPADS_INPLACE": "Build XORpads (inplace)", + "EXTRACT_X": "Extract %s", + "INIT_X": "Init %s", + "INSTALL_X": "Install %s", + "INSTALL_FIRM": "Install FIRM", + "BOOT_FIRM": "Boot FIRM", + "SET_AS_ACTIVE_FONT": "Set as active font", + "SET_AS_ACTIVE_LANGUAGE": "Set as active language", + "DUMP_BA_VC_SAVE": "Dump GBA VC save", + "INJECT_GBA_VC_SAVE": "Inject GBA VC save", + "SET_AS_DEFAULT": "Set as default", + "MOUNTING_IMAGE_FAILED": "Mounting image: failed", + "PATH_MOUNTED_AS_DRIVE_ENTER_PATH_NOW": "%s\nMounted as drive %s\nEnter path now?", + "DECRYPT_TO_OUT": "Decrypt to %s", + "DECRYPT_INPLACE": "Decrypt inplace", + "TRY_TO_DECRYPT_ALL_N_SELECTED_FILES": "Try to decrypt all %lu selected files?", + "TRYING_TO_DECRYPT_N_FILES": "Trying to decrypt %lu files...", + "DECRYPTION_FAILED_CONTINUE": "Decryption failed\n \nContinue?", + "N_OF_N_FILES_DECRYPTED_N_OF_N_NOT_ENCRYPTED_N_OF_N_NOT_SAME_TYPE": "%lu/%lu files decrypted ok\n%lu/%lu not encrypted\n%lu/%lu not of same type", + "N_OF_N_FILES_DECRYPTED": "%lu/%lu files decrypted ok", + "N_FILES_WRITTEN_TO_OUT": "%lu files written to %s", + "FILE_NOT_ENCRYPTED": "File is not encrypted", + "DECRYPTION_SUCCESS": "Decryption success", + "DECRYPTION_FAILED": "Decryption failed", + "PATH_DECRYPTED_TO_OUT": "%s\nDecrypted to %s", + "ENCRYPT_TO_OUT": "Encrypt to %s", + "ENCRYPT_INPLACE": "Encrypt inplace", + "TRY_TO_ENCRYPT_N_SELECTED_FILES": "Try to encrypt all %lu selected files?", + "TRYING_TO_ENCRYPT_N_FILES": "Trying to encrypt %lu files...", + "ENCRYPTION_FAILED_CONTINUE": "Encryption failed\n \nContinue?", + "N_OF_N_FILES_ENCRYPTED_N_OF_N_NOT_SAME_TYPE": "%lu/%lu files encrypted ok\n%lu/%lu not of same type", + "N_OF_N_FILES_ENCRYPTED": "%lu/%lu files encrypted ok", + "ENCRYPTION_SUCCESS": "Encryption success", + "ENCRYPTION_FAILED": "Encryption failed", + "PATH_ENCRYPTED_TO_OUT": "%s\nEncrypted to %s", + "TRY_TO_PROCESS_N_SELECTED_FILES": "Try to process all %lu selected files?", + "PATH_BUILD_TYPE_FAILED_CONTINUE": "%s\nBuild %s failed\n \nContinue?", + "N_OF_N_TYPES_BUILT_N_OF_N_NOT_SAME_TYPE": "%lu/%lu %ss built ok\n%lu/%lu not of same type", + "N_OF_N_TYPES_BUILT": "%lu/%lu %ss built ok", + "N_FILES_FAILED_CONVERTION_VERIFICATION_RECOMMENDED": "%lu file(s) failed conversion.\nVerification is recommended.", + "PATH_TYPE_BUILT_TO_OUT": "%s\n%s built to %s", + "PATH_TYPE_BUILD_FAILED": "%s\n%s build failed", + "FILE_FAILED_CONVERSION_VERIFY_NOW": "file failed conversion.\n \nVerify now?", + "VERIFICATION_SUCCESS": "Verification success", + "VERIFICATION_FAILED": "Verification failed", + "CONTENT_IS_MISSING": "Content is missing", + "INSTALL_TO_SYSNAND": "Install to SysNAND", + "INSTALL_TO_EMUNAND": "Install to EmuNAND", + "TRY_TO_INSTALL_N_SELECTED_FILES": "Try to install all %lu selected files?", + "TRYING_TO_INSTALL_N_FILES": "Trying to install %lu files...", + "INSTALL_FAILED_CONTINUE": "Install failed\n \nContinue?", + "N_OF_N_FILES_INSTALLED_N_OF_N_NOT_SAME_TYPE": "%lu/%lu files installed ok\n%lu/%lu not of same type", + "N_OF_N_FILES_INSTALLED": "%lu/%lu files installed ok", + "INSTALL_SUCCESS": "Install success", + "INSTALL_FAILED": "Install failed", + "FILE_FAILED_INSTALL_VERIFY_NOW": "file failed install.\n \nVerify now?", + "KEEP_TICKET_AND_SAVEGAME": "Keep ticket & savegame", + "UNINSTALL_EVERYTHING": "Uninstall everything", + "ABORT_UNINSTALL": "Abort uninstall", + "UNINSTALL_N_SELECTED_TITLES": "Uninstall %lu selected titles?", + "UNINSTALL_SELECTED_TITLE": "Uninstall selected title?", + "N_OF_N_TITLES_UNINSTALLED": "%lu/%lu titles uninstalled", + "UNINSTALLING_PLEASE_WAIT": "Uninstalling, please wait...", + "UNINSTALL_FAILED": "Uninstall failed!", + "TRY_TO_VERIFY_N_SELECTED_FILES": "Try to verify all %lu selected files?", + "VERIFICATION_FAILED_CONTINUE": "Verification failed\n \nContinue?", + "N_OF_N_FILES_VERIFIED_N_OF_N_NOT_SAME_TYPE": "%lu/%lu files verified ok\n%lu/%lu not of same type", + "VERIFYING_FILE_PLEASE_WAIT": "Verifying file, please wait...", + "NAND_VALIDATION_SUCCESS": "NAND validation success", + "NAND_VALIDATION_FAILED": "NAND validation failed", + "DUMP_FOR_N_SELECTED_FILES": "Dump for all %lu selected files?", + "N_OF_N_LEGIT_TICKETS_DUMPED_ATTEMPT_DUMP_ALL": "%lu/%lu legit tickets dumped.\n \nAttempt to dump all tickets?", + "N_OF_N_TICKETS_DUMPED_TO_OUT": "%lu/%lu tickets dumped to %s", + "PATH_TICKET_DUMPED_TO_OUT": "%s\nTicket dumped to %s", + "LEGIT_TICKET_NOT_FOUND_DUMP_ANYWAYS": "%s\nLegit ticket not found.\n \nDump anyways?", + "DUMP_TICKET_FAILED": "Dump ticket failed!", + "BUILDING_X": "Building %s...", + "BUILDING_X_SYSNAND": "Building %s (SysNAND)...", + "BUILDING_X_EMUNAND": "Building %s (EmuNAND)...", + "PATH_N_OF_N_FILES_PROCESSED_N_OF_N_FILES_IGNORED": "%s\n%lu/%lu files processed\n%lu/%lu files ignored", + "PATH_N_OF_N_FILES_PROCESSED": "%s\n%lu/%lu files processed", + "BUILD_DATABASE_SUCCESS": "Build database success.", + "BUILD_DATABASE_FAILED": "Build database failed.", + "TRY_TO_TRIM_N_SELECTED_FILES": "Try to trim all %lu selected files?", + "TRIMMING_FAILED_CONTINUE": "Trimming failed\n \nContinue?", + "N_OF_N_FILES_TRIMMED_N_OF_N_NOT_OF_SAME_TYPE_X_SAVED": "%lu/%lu files trimmed ok\n%lu/%lu not of same type\n%s saved", + "N_OF_N_FILES_TRIMMED_X_SAVED": "%lu/%lu files trimmed ok\n%s saved", + "FILE_CANT_BE_TRIMMED": "File can't be trimmed.", + "FILE_ALREADY_TRIMMED": "File is already trimmed.", + "PATH_CURRENT_SIZE_TRIMMED_SIZE_DIFFERENCE_TRIM_FILE": "%s\nCurrent size: %s\nTrimmed size: %s\nDifference: %s\n \nTrim this file?", + "TRIMMING_FAILED": "Trimming failed.", + "PATH_TRIMMED_BY_X": "%s\nTrimmed by %s.", + "TRY_TO_RENAME_N_SELECTED_FILES": "Try to rename all %lu selected files?", + "N_OF_N_RENAMED": "%lu/%lu renamed ok", + "COULD_NOT_RENAME_TO_GOOD_NAME": "Could not rename to good name", + "SYSNAND_H_AND_S_INJECT": "SysNAND H&S inject", + "EMUNAND_H_AND_S_INJECT": "EmuNAND H&S inject", + "H_AND_S_INJECT_SUCCESS": "H&S inject success", + "H_AND_S_INJECT_FAILURE": "H&S inject failure", + "TRY_EXTRACT_ALL_N_SELECTED_FILES": "Try to extract all %lu selected files?", + "N_OF_N_FILES_EXTRACTED_N_OF_N_NOT_SAME_TYPE": "%lu/%lu files extracted ok\n%lu/%lu not of same type", + "N_OF_N_FILES_EXTRACTED": "%lu/%lu files extracted ok", + "EXTRACTING_DOT_CODE": "Extracting .code, please wait...", + "PATH_EXT_EXTRACTED_TO_OUT": "%s\n%s extracted to %s", + "DOT_CODE_EXTRACT_FAILED": ".code extract failed", + "TRANSFER_TO_SYSNAND": "Transfer to SysNAND", + "TRANSFER_TO_EMUNAND": "Transfer to EmuNAND", + "CTRNAND_TRANSFER_SUCCESS": "CTRNAND transfer success", + "CTRNAND_TRANSFER_FAILED": "CTRNAND transfer failed", + "NO_VALID_DESTINATION_FOUND": "No valid destination found", + "NAND_RESTORE_SUCCESS": "NAND restore success", + "NAND_RESTORE_FAILED": "NAND restore failed", + "REBUILD_NCSD_SUCCESS": "Rebuild NCSD success", + "REBUILD_NCSD_FAILED": "Rebuild NCSD failed", + "PATH_NCCHINFO_PADGEN_SUCCESS": "%s\nNCCHinfo padgen success%cOutput dir: %s", + "PATH_NCCHINFO_PADGEN_FAILED": "%s\nNCCHinfo padgen failed%c%0.0s", + "UPDATING_EMBEDDED_BACKUP": "Updating embedded backup...", + "BACKUP_UPDATE_NOT_REQUIRED": "Backup update: not required", + "BACKUP_UPDATE_COMPLETED": "Backup update: completed", + "BACKUP_UPDATE_FAILED": "Backup update: failed!", + "WARNING_KEYS_NOT_VERIFIED_CONTINUE_AT_YOUR_OWN_RISK": "Warning: Keys are not verified.\nContinue on your own risk?", + "AESKEYDB_INIT_SUCCESS": "AESkeydb init success", + "AESKEYDB_INIT_FAILED": "AESkeydb init failed", + "AESKEYDB_INSTALL_SUCCESS": "AESkeydb install success", + "AESKEYDB_INSTALL_FAILED": "AESkeydb install failed", + "INSTALL_TO_FIRM0": "Install to FIRM0", + "INSTALL_TO_FIRM1": "Install to FIRM1", + "INSTALL_TO_BOTH": "Install to both", + "PATH_N_KB_INSTALL_TO_SYSNAND": "%s (%dkB)\nInstall to SysNAND?", + "PATH_N_KB_INSTALL_SUCCESS": "%s (%dkB)\nInstall success", + "PATH_N_KB_INSTALL_FAILED": "%s (%dkB)\nInstall failed", + "WARNING_DO_NOT_RUN_UNTRUSTED_SCRIPTS": "Warning: Do not run scripts\nfrom untrusted sources.\n \nExecute script?", + "SCRIPT_EXECUTE_SUCCESS": "Script execute success", + "SCRIPT_EXECUTE_FAILURE": "Script execute failure", + "ERROR_CANNOT_VIEW_FILE": "Error: Cannot view file\n(Hint: maybe it's too big)", + "SAVEGAME_DUMPED_TO_OUT": "Savegame dumped to %s.", + "SAVEGAME_DUMP_FAILED": "Savegame dump failed!", + "GBA_SAVEGAME_MUST_BE_IN_CLIPBOARD": "GBA VC savegame has to\nbe in the clipboard.", + "SAVEGAME_INJECT_SUCCESS": "Savegame inject success.", + "SAVEGAME_INJECT_FAILED": "Savegame inject failed!", + "FONT_WILL_BE_ACTIVE_ON_NEXT_BOOT": "Font will be active on next boot", + "LANGUAGE_WILL_BE_ACTIVE_ON_NEXT_BOOT": "Language will be active on next boot", + "HOME_MORE_MENU_SELECT_ACTION": "HOME more... menu.\nSelect action:", + "SD_FORMAT_MENU": "SD format menu", + "BONUS_DRIVE_MENU": "Bonus drive setup", + "SWITCH_EMUNAND": "Switch EmuNAND", + "BUILD_SUPPORT_FILES": "Build support files", + "RESTORE_H_AND_S": "Restore H&S", + "SET_RTC_DATE_TIME": "Set RTC date&time", + "CONFGURE_BRIGHTNESS": "Configure brightness", + "CALIBRATE_TOUCHSCREEN": "Calibrate touchscreen", + "SYSTEM_INFO": "System info", + "SHOW_README": "Show ReadMe", + "INITIALIZING_SD_FAILED_RETRY": "Initializing SD card failed! Retry?", + "SETUP_FAILED": "Setup failed!", + "CURRENT_EMUNAND_OFFSET_IS_N_SWITCH_TO_NEXT": "Current EmuNAND offset is %06lX.\nSwitch to next offset?", + "BUILT_IN_OUT_STATUSES": "Built in %s:\n \n%-18.18s %s\n%-18.18s %s\n%-18.18s %s", + "OK_SYS_EMU": "OK (Sys&Emu)", + "OK_SYS": "OK (Sys)", + "FAILED": "Failed", + "RESTORE_H_AND_S_EMUNAND": "Restore H&S (EmuNAND)", + "RESTORE_H_AND_S_SYSNAND": "Restore H&S (SysNAND)", + "TITLE_SET_RTC_DATE_TIME": "Set RTC date&time:", + "NEW_RTC_DATE_TIME_IS_TIME": "New RTC date&time is:\n%s\n \nHint: HOMEMENU time needs\nmanual adjustment after\nsetting the RTC.", + "TOUCHSCREEN_CALIBRATION_SUCCESS": "Touchscreen calibration success!", + "TOUCHSCREEN_CALIBRATION_FAILED": "Touchscreen calibration failed!", + "GODMODE9_README_TOC": "GodMode9 ReadMe Table of Contents", + "ESSENTIAL_BACKUP_NOT_FOUND_CREATE_NOW": "Essential files backup not found.\nCreate one now?", + "BACKUP_EMBEDDED_WRITTEN_TO_OUT": "Backup embedded in SysNAND\nand written to %s.", + "RTC_DATE_TIME_SEEMS_TO_BE_WRONG_SET_NOW": "RTC date&time seems to be\nwrong. Set it now?", + "RESUME_GODMODE9": "Resume GodMode9", + "RESUME_BOOTLOADER": "Resume bootloader", + "SELECT_PAYLOAD": "Select payload...", + "SELECT_SCRIPT": "Select script...", + "POWEROFF_SYSTEM": "Poweroff system", + "REBOOT_SYSTEM": "Reboot system", + "FLAVOR_BOOTLOADER_SELECT_OPTION": "%s bootloader menu.\nSelect action:", + "BOOTLOADER_PAYLOADS_MENU_SELECT_PAYLOAD": "Bootloader payloads menu.\nSelect payload:", + "BOOTLOADER_SCRIPTS_MENU_SELECT_SCRIPT": "Bootloader scripts menu.\nSelect script:", + "NO_BOOTABLE_FIRM_FOUND_RESUMING_GODMODE9": "No bootable FIRM found.\nNow resuming GodMode9...", + "OUT_OF_MEMORY": "Out of memory.", + "INVALID_DIRECTORY_OBJECT": "Invalid directory object", + "INVALID_ROOT_DIRECTORY": "Invalid root directory.", + "WRITE_PERMISSIONS_WERE_CHANGED_RELOCK": "Write permissions were changed.\nRelock them?", + "OPEN_TITLE_MANAGER": "Open title manager", + "SEARCH_FOR_FILES": "Search for files...", + "FIX_CMACS_FOR_DRIVE": "Fix CMACs for drive", + "SHOW_DIRECTORY_INFO": "Show directory info", + "SHOW_DRIVE_INFO": "Show drive info", + "FAILED_SETTING_UP_TITLE_MANAGER": "Failed setting up title manager!", + "SEARCH_FILE_ENTER_SEARCH_BELOW": "Search %s?\nEnter search below.", + "FOUND_N_RESULTS": "Found %lu results.", + "FIX_CMACS_FOR_DRIVE_FINISHED": "Fix CMACs for drive finished.", + "FAILED_TO_ANALYZE_DRIVE": "Failed to analyze drive\n", + "FAILED_TO_ANALYZE_DIR": "Failed to analyze dir\n", + "NOT_ALLOWED_IN_VIRTUAL_PATH": "Not allowed in virtual path", + "DELETE_N_PATHS": "Delete %lu path(s)?", + "DELETING_FILES_PLEASE_WAIT": "Deleting files, please wait...", + "FAILED_DELETING_N_OF_N_PATHS": "Failed deleting %lu/%lu path(s)", + "DELETE_FILE": "Delete \"%s\"?", + "FAILED_DELETING_PATH": "Failed deleting:\n%s", + "NOT_ALLOWED_IN_SEARCH_DRIVE": "Not allowed in search drive", + "NOT_ALLOWED_IN_VIRTUAL_GAME_PATH": "Not allowed in virtual game path", + "NOT_ALLOWED_IN_XORPAD_DRIVE": "Not allowed in XORpad drive", + "NOT_ALLOWED_IN_GAMECART_DRIVE": "Not allowed in gamecart drive", + "NOT_ALLOWED_IN_ALIAS_PATH": "Not allowed in alias path", + "COPY_PATHS": "Copy path(s)", + "MOVE_PATHS": "Move path(s)", + "PASTE_FILE_HERE": "Paste \"%s\" here?", + "PASTE_N_PATHS_HERE": "Paste %lu paths here?", + "FAILED_COPYING_PATH_PROCESS_REMAINING": "Failed copying path:\n%s\nProcess remaining?", + "FAILED_COPYING_PATH": "Failed copying path:\n%s", + "FAILED_MOVING_PATH_PROCESS_REMAINING": "Failed moving path:\n%s\nProcess remaining?", + "FAILED_MOVING_PATH": "Failed moving path:\n%s", + "RENAME_FILE_ENTER_NEW_NAME_BELOW": "Rename %s?\nEnter new name below.", + "FAILED_RENAMING_PATH": "Failed renaming path:\n%s", + "CREATE_A_NEW_ENTRY_HERE_SELECT_TYPE": "Create a new entry here?\nSelect type.", + "CREATE_A_FOLDER": "Create a folder", + "CREATE_A_DUMMY_FILE": "Create a dummy file", + "CREATE_NEW_FOLDER_HERE_ENTER_NAME_BELOW": "Create a new folder here?\nEnter name below.", + "CREATE_NEW_FILE_HERE_ENTER_NAME_BELOW": "Create a new file here?\nEnter name below.", + "CREATE_NEW_FILE_HERE_ENTER_SIZE_BELOW": "Create a new %s here?\nEnter file size below.", + "FAILED_CREATING_FOLDER_PATH": "Failed creating folder:\n%s", + "FAILED_CREATING_FILE_PATH": "Failed creating file:\n%s", + "TITLE_MANAGER": "Title manager", + "BRICK_MY_3DS": "Brick my 3DS", + "SCRIPTS": "Scripts...", + "PAYLOADS": "Payloads...", + "MORE": "More...", + "BRACKET_MORE": "[more...]", + "HOME_BUTTON_PRESSED_SELECT_ACTION": "HOME button pressed.\nSelect action:", + "POWER_BUTTON_PRESSED_SELECT_ACTION": "POWER button pressed.\nSelect action:", + "1_DRIVE_NAND_TWL": "[1:] NAND / TWL", + "4_DRIVE_NAND_TWL": "[4:] NAND / TWL", + "A_DRIVE_SD_CARD": "[A:] SD CARD", + "B_DRIVE_SD_CARD": "[B:] SD CARD", + "TITLE_MANAGER_MENU_SELECT_TITLES_SOURCE": "Title manager menu.\nSelect titles source:", + "SCRIPTS_DIRECTORY_NOT_FOUND": "Scripts directory not found.\n(default path: 0:/gm9/%s)", + "HOME_SCRIPTS_MENU_SELECT_SCRIPT": "HOME scripts... menu.\nSelect script:", + "PAYLOADS_DIRECTORY_NOT_FOUND": "Payloads directory not found.\n(default path: 0:/gm9/%s)", + "HOME_PAYLOADS_MENU_SELECT_PAYLOAD": "HOME payloads... menu.\nSelect payload:", + "UNEXPECTED_SD_CARD_REMOVAL_TO_PREVENT_DATA_LOSS_UNMOUNT_BEFORE_EJECT": "!Unexpected SD card removal!\n \nTo prevent data loss, unmount\nbefore ejecting the SD card.", + "FLAVOR_SCRIPTS_MENU_SELECT_SCRIPT": "%s scripts menu.\nSelect script:", + "COMPILED_AS_SCRIPT_AUTORUNNER_BUT_NO_SCRIPT_DERP": "Compiled as script autorunner\nbut no script provided.\n \nDerp!", + "KEYBOARD_CONTROLS_DETAILS": "Keyboard Controls:\n \n←/→ - Move cursor\nR - Caps / Capslock\nX - Delete char\nY - Insert char\nA - Submit\nB - Cancel\n \nSELECT switches to\nclassic prompt", + "TOUCH_CROSSHAIRS_TO_CALIBRATE_TOUCHSCREEN_USE_STYLUS": "Touch the red crosshairs to\ncalibrate your touchscreen.\n \nUse the stylus for best\nresults!", + "INVALID": "INVALID", + "TO_PROCEED_ENTER_THIS": "To proceed, enter this:", + "TO_PROCEED_HOLD_X": "To proceed, hold :", + "N_MORE": " [%d more]", + "CANCEL": "cancel", + "R_FAST_SCROLL_L_CLEAR_DATA": "R - (↑↓) fast scroll\nL - clear data", + "X_REMOVE_CHAR_Y_INSERT_CHAR": "X - remove char\nY - insert char", + "ETA_N_MIN_N_SEC": "ETA %02llum%02llus", + "BRIGHTNESS_CONTROLS": "[←] Decrease brightness\n[→] Increase brightness\n \n[X] Use volume slider control\n[A] Set current brightness\n[B] Cancel", + "SEARCHING_PLEASE_WAIT": "Searching, please wait...", + "RENAME_TO_GOOD_NAME": "Rename to good name?", + "SD_WRITE_PROTECTED_CANT_CONTINUE": "SD card is write protected!\nCan't continue.", + "SYSNAND_LVL_N": "SysNAND (lvl%lu)", + "EMUNAND_LVL_N": "EmuNAND (lvl%lu)", + "GAME_IMAGES": "game images", + "GAMECART_SAVES": "gamecart saves", + "IMAGES": "images", + "MEMORY_AREAS": "memory areas", + "SD_SYSTEM_DATA": "SD system data", + "SD_CARD": "SD card", + "RAM_DRIVE": "RAM drive", + "WRITING_TO_DRIVE_IS_LOCKED_UNLOCK_NOW": "Writing to %s is locked!\nUnlock it now?", + "UNLOCK_WRITE_FOR_DRIVE_NOT_ALLOWED": "Unlock write permission for\n%s is not allowed.", + "ENABLE_BASE_WRITE": "You want to enable base\nwriting permissions.", + "ENABLE_SD_WRITE": "You want to enable SD card\nwriting permissions.", + "ENABLE_IMAGE_WRITE": "You want to enable image\nwriting permissions.", + "ENABLE_RAM_DRIVE_WRITE": "You want to enable RAM drive\nwriting permissions.", + "ENABLE_EMUNAND_0_WRITE": "You want to enable EmuNAND\nlvl0 writing permissions.", + "ENABLE_SYSNAND_0_WRITE": "You want to enable SysNAND\nlvl0 writing permissions.", + "ENABLE_EMUNAND_1_WRITE": "You want to enable EmuNAND\nlvl1 writing permissions.\n \nThis enables you to modify\nrecoverable system data,\nuser data & savegames.", + "ENABLE_SYSNAND_1_WRITE": "You want to enable SysNAND\nlvl1 writing permissions.\n \nThis enables you to modify\nsystem data, installations,\nuser data & savegames.", + "ENABLE_GAMECART_SAVE_WRITE": "You want to enable gamecart\nsave writing permissions.", + "ENABLE_SYSNAND_2_WRITE": "!Better be careful!\n \nYou want to enable SysNAND\nlvl2 writing permissions.\n \nThis enables you to modify\nirrecoverable system data!", + "ENABLE_MEMORY_WRITE": "!Better be careful!\n \nYou want to enable memory\nwriting permissions.\n \nWriting to certain areas may\nlead to unexpected results.", + "ENABLE_SD_DATA_WRITE": "!THIS IS NOT RECOMMENDED!\n \nYou want to enable SD data\nwriting permissions.\n \nEverything here is encrypted.\nIt is recommended to use the\nA:/B: drives for modification\nof installations, user data &\nsavegames instead.", + "ENABLE_SYSNAND_3_WRITE": "!THIS IS YOUR ONLY WARNING!\n \nYou want to enable SysNAND\nlvl3 writing permissions.\n \nThis enables you to OVERWRITE\nyour bootloader installation,\nessential system files and/or\nBRICK your console!", + "UNLOCK_WRITE_NOT_ALLOWED": "Unlock write permission is not allowed.", + "CANT_UNLOCK_WRITE_TRY_GODMODE9": "Can't unlock write permission.\nTry GodMode9 instead!", + "ERROR_SD_TOO_SMALL": "Error: SD card is too small", + "WARNING_PROCEEDING_WILL_FORMAT_SD_DELETE_ALL_DATA": "!WARNING!\n \nProceeding will format this SD.\nThis will irreversibly delete\nALL data on it.", + "FORMAT_BONUS_DRIVE_DELETE_ALL_DATA": "Format the bonus drive?\nThis will irreversibly delete\nALL data on it.", + "FORMATTING_SD_PLEASE_WAIT": "Formatting SD, please wait...", + "FORMATTING_DRIVE_PLEASE_WAIT": "Formatting drive, please wait...", + "ERROR_SD_CARD_IO_FAILURE": "Error: SD card i/o failure", + "FILE_IS_MOUNTED_UNMOUNT_TO_UNLOCK": "File is currently mounted.\nUnmount to unlock?", + "ERROR_CANT_INJECT_FILE_INTO_ITSELF": "Error: Can't inject file into itself", + "OPERATION_WOULD_WRITE_BEYOND_EOF": "Operation would write beyond end of file", + "NOT_ENOUGH_DATA_IN_FILE": "Not enough data in file", + "CANCEL_IS_NOT_ALLOWED_HERE": "Cancel is not allowed here", + "B_DETECTED_CANCEL": "B button detected. Cancel?", + "ERROR_CANNOT_APPEND_FOLDER": "Error: Cannot append a folder", + "ERROR_OVERWRITING_FILE_WITH_DIR": "Error: Overwriting file with dir", + "ERROR_OVERWRITING_DIR_WITH_FILE": "Error: Overwriting dir with file", + "ERROR_CANNOT_OPEN_DESTINATION_FILE": "Error: Cannot open destination file", + "ERROR_NOT_ENOUGH_SPACE_AVAILABLE": "Error: Not enough space available", + "ERROR_ONLY_FAT_FILES_CAN_BE_MOVED": "Error: Only FAT files can be moved", + "ERROR_DESTINATION_IS_PART_OF_ORIGIN": "Error: Destination is part of origin", + "ERROR_DESTINATION_EQUALS_ORIGIN_CHOOSE_ANOTHER_NAME": "Destination equals origin\nChoose another name?", + "CHOOSE_NEW_NAME": "Choose new name", + "OVERWRITE_FILES": "Overwrite file(s)", + "SKIP_FILES": "Skip file(s)", + "OVERWRITE_ALL": "Overwrite all", + "SKIP_ALL": "Skip all", + "DESTINATION_ALREADY_EXISTS": "Destination already exists:\n%s", + "CHOOSE_NEW_DESTINATION_NAME": "Choose new destination name", + "COPY_OPERATION_IS_NOT_ALLOWED": "Copy operation is not allowed", + "DESTINATION_EQUALS_ORIGIN": "Destination equals origin", + "ENTRY_NOT_FOUND_PATH_INJECT_INTO_PATH_INSTEAD": "Entry not found: %s\nInject into %s instead?", + "FILE_SMALLER_THAN_SPACE_SIZES_CONTINUE": "File smaller than available space:\n%s (%s)\n%s (%s)\nContinue?", + "NO_USABLE_ENTRIES_FOUND": "No usable entries found.", + "BEAT_NO_ERROR": "No error", + "BEAT_END_OF_ACTION_LIST": "End of action list", + "BEAT_ABORTED_BY_USER": "Aborted by user", + "BEAT_FAILED_TO_READ_WRITE_FILE": "Failed to read/write file", + "BEAT_ATTEMPTED_TO_WRITE_BEYOND_EOF": "Attempted to write beyond end of file", + "BEAT_INVALID_PATCH_FILE": "Invalid patch file", + "BEAT_INVALID_INPUT_FILE": "Invalid input file", + "BEAT_OUTPUT_FILE_CHECKSUM_MISMATCH": "Output file checksum mismatch", + "BEAT_FILE_CHECKSUM_FAILED": "File checksum failed", + "BEAT_EXPECTED_MORE_PATCH_DATA": "Expected more patch data", + "BEAT_OUT_OF_MEMORY": "Out of memory", + "BEAT_UNKNOWN_ERROR": "Unknown error", + "FAILED_TO_INITIALIZE_BPM_FILE": "Failed to initialize BPM file:\n%s", + "FAILED_TO_INITIALIZE_BPS_FILE": "Failed to initialize BPS file:\n%s", + "PATCH_SUCCESSFULLY_APPLIED": "Patch successfully applied", + "PATCHING_ABORTED_BY_USER": "Patching aborted by user", + "FAILED_TO_RUN_PATCH": "Failed to run patch:\n%s", + "DECOMPRESSING_DOT_CODE": "Decompressing .code...", + "DECOMPRESSING_DOT_CODE_B_DETECTED_CANCEL": "Decompressing .code...\nB button detected. Cancel?", + "COMPRESSING_DOT_CODE": "Compressing .code...", + "COMPRESSING_DOT_CODE_B_DETECTED_CANCEL": "Compressing .code...\nB button detected. Cancel?", + "PATCH_MOST_LIKELY_NOT_FOR_THIS_FILE": "The patch is most likely not intended for this file.", + "YOU_MOST_LIKELY_APPLIED_PATCH_ON_OUTPUT": "You most likely applied the patch on the output file.", + "PATCH_TECHNICALLY_VALID_BUT_SEEMS_SCRAMBLED": "The patch is technically valid,\nbut seems scrambled or malformed.", + "PATCH_IS_INVALID": "The patch is invalid.", + "FILES_BIGGER_THAN_16MB_IPS_DOESNT_SUPPORT_THAT": "One or both files are bigger than 16MB.\nThe IPS format doesn't support that.", + "REQUESTED_FILE_PATH_WAS_INVALID": "The requested file path was invalid.", + "PATCHING_CANCELED": "Patching canceled.", + "NOT_ENOUGH_MEMORY": "Not enough memory.", + "REGION_AMERICAS": "Americas", + "REGION_AUSTRALIA": "Australia", + "REGION_BRAZIL": "Brazil", + "REGION_CHINA": "China", + "REGION_EUROPE": "Europe", + "REGION_FRANCE": "France", + "REGION_GERMANY": "Germany", + "REGION_ITALY": "Italy", + "REGION_JAPAN": "Japan", + "REGION_KOREA": "Korea", + "REGION_SPAIN": "Spain", + "REGION_TAIWAN": "Taiwan", + "REGION_UNKNOWN": "Unknown", + "REGION_UNITED_KINGDOM": "United Kingdom", + "REGION_MIDDLE_EAST": "Middle East", + "GENERATING_QR_CODE": "Generating QR code...", + "REINITIALIZING_SD_CARD": "Reinitializing SD card...", + "DUMPING_STATE_TO_SD_CARD": "Dumping state to SD card...", + "PRESS_POWER_TO_TURN_OFF": "Press POWER to turn off", + "CLEANING_UP_TITLES_PLEASE_WAIT": "Cleaning up titles, please wait...", + "ERROR_NOT_NCCH_FILE": "Error: Not an NCCH file", + "ERROR_FILE_IS_TOO_SMALL": "Error: File is too small", + "ATTEMPT_FIX_THIS_TIME": "Attempt fix this time", + "ATTEMPT_FIX_ALWAYS": "Attempt fix always", + "ABORT_VERIFICATION": "Abort verification", + "ERROR_BAD_CRYPTO_FLAGS": "Error: Bad crypto flags", + "ERROR_BAD_EXEFS_HEADER": "Error: Bad ExeFS header", + "ERROR_MISSING_EXTHEADER": "Error: Missing ExtHeader", + "ERROR_CRYPTO_NOT_SET_UP": "Error: Crypto not set up", + "PATH_NCCH_VERIFICATION_FAILED_INFO": "%s\nNCCH verification failed:\nExtHdr/ExeFS/RomFS: %s/%s/%s", + "OK": "ok", + "FAIL": "fail", + "ERROR_NOT_NCSD_FILE": "Error: Not an NCSD file", + "PATH_CONTENT_N_SIZE_AT_OFFSET_VERIFICATION_FAILED": "%s\nContent%lu (%08lX@%08lX):\nVerification failed", + "ERROR_PROBABLY_NOT_CIA_FILE": "Error: Probably not a CIA file", + "ERROR_TMD_PROBABLY_CORRUPTED": "Error: TMD probably corrupted", + "PATH_ID_N_SIZE_AT_OFFSET_VERIFICATION_FAILED": "%s\nID %08lX (%08llX@%08llX)\nVerification failed", + "ERROR_CDN_TITLEKEY_NOT_FOUND": "Error: CDN titlekey not found", + "DLC_CONTENT_IS_MISSING_IGNORE_ALL_AND_CONTINUE": "DLC content is missing\n \nIgnore all and continue?", + "PATH_SECTION_N_HASH_MISMATCH": "%s\nSection %lu hash mismatch", + "ARM9_ENTRYPOINT_IS_MISSING": "ARM9 entrypoint is missing", + "WARNING_ARM11_ENTRYPOINT_IS_MISSING": "Warning: ARM11 entrypoint is missing", + "ERROR_NOT_A_BOSS_FILE": "Error: Not a BOSS file", + "BOSS_PAYLOAD_HASH_MISMATCH_TRY_TO_FIX_IT": "BOSS payload hash mismatch.\n \nTry to fix it?", + "GENERIC_TICKET_PIRATE_LEGIT": "Generic ticket (\"pirate legit\")", + "PERSONALIZED_TICKET_LEGIT": "Personalized ticket (legit)", + "ID_N_LEGIT_TICKET_IS_PERSONALIZED_USING_THIS_NOT_RECOMMENDED_CHOOSE_DEFAULT_ACTION": "ID %016llX\nLegit ticket is personalized.\nUsing this is not recommended.\nChoose default action:", + "ID_N_TITLEKEY_NOT_FOUND": "ID %016llX\nTitlekey not found.", + "ID_N_TMD_IN_TAD_NOT_LEGIT": "ID %016llX\nTMD in TAD is not legit.", + "ID_N_TMD_NOT_LEGIT": "ID %016llX\nTMD is not legit.", + "ID_N_DOT_N_STATUS": "ID %016llX.%08lX\n%s", + "CONTENT_IS_CORRUPT": "Content is corrupt", + "INSERT_CONTENT_FAILED": "Insert content failed", + "INSTALL_CONTENT_FAILED": "Install content failed", + "INSTALL_ERROR_THIS_SYSTEM_IS_MISSING_DB_FILES_MAYBE_SD_MISSING_OR_UNINITIALIZED": "Install error:\nThis system is missing one or\nmore .db files.\n \nMaybe the SD card is missing\nor uninitialized?", + "INSTALL_ERROR_THIS_SYSTEM_IS_MISSING_TICKET_DB": "Install error:\nThis system is missing the\nticket.db file.", + "SKIPPED_TITLE_0004008C000CBD00_NEEDS_SPECIAL_COMPILE_FLAGS": "Skipped title:\nTitle with id 0004008C000CBD00\nneeds special compiler flags.", + "ERROR_FAKE_SIGNED_TICKET_ONLY_VALID_SIGNED_TICKETS_CAN_BE_INSTALLED": "Error: Fake-signed ticket\n \nOnly valid signed tickets can\nbe installed to the system.", + "PATH_ERROR_UNKNOWN_CID_N_THIS_TICKET_DOES_NOT_BELONG_TO_THIS_3DS": "%s\nError: Unknown cid %08lX\n \nThis ticket does not belong to\nthis 3DS console.", + "INSTALLING_TICKET": "Installing ticket...", + "POSSIBLY_BROKEN": "Possibly Broken", + "PERSONAL_LEGIT": "Personal Legit", + "PERSONAL_LEGIT_DLC": "Personal Legit DLC", + "PERSONAL_PIRATE_LEGIT": "Personal Pirate Legit", + "PERSONAL_PIRATE_LEGIT_DLC": "Personal Pirate Legit DLC", + "PERSONAL_CUSTOM": "Personal Custom", + "PERSONAL_CUSTOM_DLC": "Personal Custom DLC", + "UNIVERSAL_LEGIT": "Universal Legit", + "UNIVERSAL_LEGIT_DLC": "Universal Legit DLC", + "UNIVERSAL_PIRATE_LEGIT": "Universal Pirate Legit", + "UNIVERSAL_PIRATE_LEGIT_DLC": "Universal Pirate Legit DLC", + "UNIVERSAL_CUSTOM": "Universal Custom", + "UNIVERSAL_CUSTOM_DLC": "Universal Custom DLC", + "CONTENTS_IN_CIA_FOUND_TOTAL": "Contents in CIA: %lu/%lu", + "CONTENTS_IN_CIA_TOTAL": "Contents in TMD: %lu", + "CONSOLE_ID_N": "Console ID: %08lX\n", + "SHOW_GAME_INFO_DETAILS": "%s\n%s %s Title\n \nTitle ID: %016llX\nTitle version: %lu.%lu.%lu\nContents size: %s\n%s\n%s \nTicket/TMD: %s/%s\nVerification: %s", + "STATE_LEGIT": "legit", + "STATE_ILLEGIT": "illegit", + "STATE_UNKNOWN": "unknown", + "STATE_INVALID": "invalid", + "STATE_PENDING_PROCEED_WITH_VERIFICATION": "pending\n \nProceed with verification?", + "STATE_PASSED": "passed", + "STATE_FAILED": "failed", + "OUTPUT_FILE_ALREADY_EXISTS_UPDATE_THIS": "Output file already exists.\nUpdate this?", + "DSI_ENHANCED": "DSi Enhanced", + "DSI_EXCLUSIVE": "DSi Exclusive", + "FIXING_CMACS_PLEASE_WAIT": "Fixing CMACs, please wait...", + "NCSD_HEADER_IS_NOT_VALID": "NCSD header is not valid", + "NAND_DUMP_MISSING_DATA": "NAND dump missing data", + "ERROR_CTR_MBR_IS_CORRUPT": "Error: CTR MBR is corrupt", + "ERROR_TWL_MBR_IS_CORRUPT": "Error: TWL MBR is corrupt", + "PATH_ERROR_CTR_PARTITION_N_IS_CORRUPT": "%s\nError: CTR partition%lu is corrupt", + "PATH_ERROR_TWL_PARTITION_N_IS_CORRUPT": "%s\nError: TWL partition%lu is corrupt", + "NO_VALID_FIRM_FOUND": "No valid FIRM found", + "ERROR_NAND_DUMP_IS_CORRUPT_STILL_CONTINUE": "Error: NAND dump is corrupt.\nStill continue?", + "ERROR_SYSTEM_IS_LOCKED": "Error: System is locked.", + "ESSENTIAL_FILES_BACKUP_IS_REQUIRED_CREATE_ONE_NOW": "Essential files backup is required.\nCreate one now?", + "WARNING_PROCEEDING_WILL_OVERWRITE_SYSNAND_WITH_DUMP": "!WARNING!\n \nProceeding will overwrite the\nSysNAND with the provided dump.\n \n(B9S/A9LH will be left intact.)", + "IMAGE_NCSD_CORRUPT_OR_CUSTOMIZED_SAFE_RESTORE_NOT_POSSIBLE": "Image NCSD corrupt or customized,\nsafe restore is not possible!", + "WARNING_NCSD_DIFFERS_BETWEEN_IMAGE_AND_LOCAL_ELEVATED_WRITE_PERMISSIONS_REQUIRED": "!WARNING!\n \nNCSD differs between image and local,\nelevated write permissions required\n \nProceed on your own risk?", + "NOT_AN_INSTALLABLE_FIRM": "Not a installable FIRM.", + "FIRM_LOAD_VERIFY_ERROR": "FIRM load/verify error.", + "PATH_FIRM_N_NOT_FOUND_OR_TOO_SMALL": "%s\nFIRM%lu not found or too small.", + "SECTOR_0X96_CRYPTO_FAIL": "Sector 0x96 crypto fail.", + "SECTOR_0X96_CORRUPTED_PROVIDE_SECRET_SECTOR_BIN_TO_FIX": "Sector 0x96 is corrupted.\n \nProvide \"secret_sector.bin\"\nto fix sector 0x96.", + "SECTOR_0X96_CORRUPTED_FIX_DURING_INSTALLATION": "Sector 0x96 is corrupted.\n \nFix sector 0x96 during\nthe installation?", + "WARNING_PROCEEDING_WILL_INSTALL_FIRM_TO_SYSNAND_AND_INJECT_SIGHAX_UNSUPPORTED_FIRM_WILL_BRICK": "!WARNING!\n \nProceeding will install the\nprovided FIRM to the SysNAND\nand inject sighax.\n \nInstalling an unsupported FIRM\nwill BRICK your console!", + "INSTALLING_FIRM_PLEASE_WAIT": "Installing FIRM, please wait...", + "THIS_IS_BAD_FAILED_WRITING_SECTOR_0X96_TRY_FIX_BEFORE_REBOOT": "!THIS IS BAD!\n \nFailed writing sector 0x96.\nTry to fix before reboot!", + "THIS_IS_BAD_FAILED_WRITING_FIRM_N_TRY_FIX_BEFORE_REBOOT": "!THIS IS BAD!\n \nFailed writing FIRM%lu.\nTry to fix before reboot!", + "CHECKING_INSTALLATION_PLEASE_WAIT": "Checking installation, please wait...", + "THIS_IS_BAD_FAILED_VERIFYING_SECTOR_0X96_TRY_FIX_BEFORE_REBOOT": "!THIS IS BAD!\n \nFailed verifying sector 0x96.\nTry to fix before reboot!", + "THIS_IS_BAD_FAILED_VERIFYING_FIRM_N_TRY_FIX_BEFORE_REBOOT": "!THIS IS BAD!\n \nFailed verifying FIRM%lu.\nTry to fix before reboot!", + "PERFECT_KEYDB_IS_ALREADY_INSTALLED": "Perfect %s is already installed!", + "PATH_NOT_PERFECT_KEYDB_IMAGE_CANNOT_INSTALL_TO_NAND": "%s\nNot a perfect %s image.\nCannot install to NAND!", + "PATH_FAILED_WRITING_KEYDB_TO_NAND": "%s\nFailed writing %s to NAND!", + "USE_L_R_TO_SAVE": "(use L+R to save)", + "EASTER_NOT_FOUND": "(%s not found)", + "BUILDING_TO_OUT_ARG": "Building to %s:\n%s ...", + "EJECT_SD_CARD": "Eject SD card...", + "INSERT_SD_CARD": "Insert SD card...", + "SCRIPTERR_UNKNOWN_CMD": "unknown cmd", + "SCRIPTERR_BAD_NUMBER_OF_ARGS": "bad # of args", + "SCRIPTERR_UNRECOGNIZED_FLAGS": "unrecognized flags", + "SCRIPTERR_ILLEGAL_FLAG": "illegal flag", + "SCRIPTERR_UNRESOLVED_QUOTES": "unresolved quotes", + "SCRIPTERR_TOO_MANY_ARGUMENTS": "too many arguments", + "SCRIPTERR_ARGUMENT_EXPAND_FAILED": "argument expand failed", + "SCRIPTERR_QUOTE_NOT_AN_ERROR": "'not' an error", + "SCRIPTERR_SYNTAX_ERROR_AFTER_IF": "syntax error after 'if'", + "SCRIPTERR_ELIF_WITHOUT_IF": "'elif' without 'if'", + "SCRIPTERR_SYNTAX_ERROR_AFTER_ELIF": "syntax error after 'elif'", + "SCRIPTERR_ELSE_WITHOUT_IF": "'else' without 'if'", + "SCRIPTERR_END_WITHOUT_IF": "'end' without 'if'", + "SCRIPTERR_FOR_INSIDE_FOR": "'for' inside 'for'", + "SCRIPTERR_DIR_NOT_FOUND": "dir not found", + "SCRIPTERR_FOR_WITHOUT_NEXT": "'for' without 'next'", + "SCRIPTERR_NEXT_WITHOUT_FOR": "'next' without 'for'", + "SCRIPTERR_FORPATH_ERROR": "forpath error", + "SCRIPTERR_LABEL_NOT_FOUND": "label not found", + "SCRIPTERR_USER_ABORT": "user abort", + "SCRIPTERR_KEY_NOT_PRESSED": "key not pressed", + "SCRIPTERR_OUT_OF_MEMORY": "out of memory", + "SCRIPTERR_VAR_FAIL": "var fail", + "SCRIPTERR_FORBIDDEN_DRIVE": "forbidden drive", + "SCRIPTERR_INVALID_PATH": "invalid path", + "SCRIPTERR_FILESELECT_ABORT": "fileselect abort", + "SCRIPTERR_DIRSELECT_ABORT": "dirselect abort", + "SCRIPTERR_SET_FAIL": "set fail", + "SCRIPTERR_CHAR_NOT_FOUND": "char not found", + "SCRIPTERR_ARGV_2_IS_NOT_CHAR": "argv[2] is not a char", + "SCRIPTERR_ARGV_2_MUST_BE_2_CHARS": "argv[2] must be 2 chars", + "SCRIPTERR_ARG_MATCH": "arg match", + "SCRIPTERR_NO_ARG_MATCH": "no arg match", + "SCRIPTERR_PERMISSION_FAIL": "permission fail", + "SCRIPTERR_COPY_FAIL": "copy fail", + "SCRIPTERR_MOVE_FAIL": "move fail", + "SCRIPTERR_INJECT_FAIL": "inject fail", + "SCRIPTERR_FILLBYTE_FAIL": "fillbyte fail", + "SCRIPTERR_FILL_FAIL": "fill fail", + "SCRIPTERR_BAD_FILESIZE": "bad filesize", + "SCRIPTERR_CREATE_DUMMY_FILE": "create dummy fail", + "SCRIPTERR_REMOVE_FAIL": "remove fail", + "SCRIPTERR_MAKEDIR_FAIL": "makedir fail", + "SCRIPTERR_MOUNT_FAIL": "mount fail", + "SCRIPTERR_FIND_FAIL": "find fail", + "SCRIPTERR_FINDNOT_FAIL": "findnot fail", + "SCRIPTERR_NO_SIZE_GIVEN": "no size given", + "SCRIPTERR_SIZE_TOO_BIG": "size too big", + "SCRIPTERR_READ_FAIL": "read fail", + "SCRIPTERR_CONVERSION_FAIL": "conversion fail", + "SCRIPTERR_INVALID_DATA": "invalid data", + "SCRIPTERR_WRITE_FAIL": "write fail", + "SCRIPTERR_SHA_ARG0_FAIL": "sha arg0 fail", + "SCRIPTERR_SHA_ARG1_FAIL": "sha arg1 fail", + "SCRIPTERR_SHA_DOES_NOT_MATCH": "sha does not match", + "SCRIPTERR_SHA_WRITE_FAIL": "sha write fail", + "SCRIPTERR_FILE_WRITE_FAIL": "file write fail", + "SCRIPTERR_FIXCMAC_FAILED": "fixcmac failed", + "SCRIPTERR_VERIFICATION_FAILED": "verification failed", + "SCRIPTERR_DECRYPT_FAILED": "decrypt failed", + "SCRIPTERR_ENCRYPT_FAILED": "encrypt failed", + "SCRIPTERR_BUILD_CIA_FAILED": "build CIA failed", + "SCRIPTERR_INSTALL_GAME_FAILED": "install game failed", + "SCRIPTERR_DOES_NOT_CONTAIN_DOT_CODE": "does not contain .code", + "SCRIPTERR_EXTRACT_DOT_CODE_FAILED": "extract .code failed", + "SCRIPTERR_COMPRESS_DOT_CODE_FAILED": "compress .code failed", + "SCRIPTERR_BUILD_FAILED": "build failed", + "SCRIPTERR_UNKNOWN_FILE": "unknown file", + "SCRIPTERR_APPLY_IPS_FAILD": "apply IPS failed", + "SCRIPTERR_APPLY_BPS_FAILED": "apply BPS failed", + "SCRIPTERR_APPLY_BPM_FAILED": "apply BPM failed", + "SCRIPTERR_TEXTVIEWER_FAILED": "textviewer failed", + "SCRIPTERR_BAD_DUMPSIZE": "bad dumpsize", + "SCRIPTERR_CART_INIT_FAIL": "cart init fail", + "SCRIPTERR_CART_DUMP_FAILED": "cart dump failed", + "SCRIPTERR_NOT_A_DIR": "not a dir", + "SCRIPTERR_FILE_NOT_FOUND": "file not found", + "SCRIPTERR_NOT_A_BOOTABLE_FIRM": "not a bootable firm", + "SCRIPTERR_SD_NOT_MOUNTED": "SD not mounted", + "SCRIPTERR_UNKNOWN_ERROR": "unknown error", + "SCRIPTERR_COMMAND_SUCCESS": "command success", + "SCRIPTERR_CONTROL_FLOW_ERROR": "control flow error", + "SCRIPTERR_UNCLOSED_CONDITIONAL": "unclosed conditional", + "SCRIPTERR_ERROR_MESSAGE_FAIL": "error message fail", + "ERROR_INVALID_TEXT_DATA": "Error: Invalid text data", + "TEXTVIEWER_CONTROLS_DETAILS": "Textviewer Controls:\n \n↑↓→←(+R) - Scroll\nR+Y - Toggle wordwrap\nR+X - Goto line #\nB - Exit\n", + "CURRENT_LINE_N_ENTER_NEW_LINE_BELOW": "Current line: %i\nEnter new line below.", + "PREVIEW_DISABLED": "(preview disabled)", + "PATH_LINE_N_ERR_LINE": "%s\nline %lu: %s\n%s", + "END_OF_SCRIPT_UNRESOLVED_IF": "end of script: unresolved 'if'", + "END_OF_SCRIPT_UNRESOLVED_FOR": "end of script: unresolved 'for'", + "SYSINFO_MODEL": "Model: %s (%s)\r\n", + "SYSINFO_SERIAL": "Serial: %s\r\n", + "SYSINFO_REGION_SYSTEM": "Region (system): %s\r\n", + "SYSINFO_REGION_SALES": "Region (sales): %s\r\n", + "SYSINFO_SOC_MANUFACTURING_DATE": "SoC manufacturing date: %s\r\n", + "SYSINFO_SYSTEM_ASSEMBLY_DATE": "System assembly date: %s\r\n", + "SYSINFO_ORIGINAL_FIRMWARE": "Original firmware: %s\r\n", + "SYSINFO_FRIENDCODE_SEED": "Friendcode seed: %s\r\n", + "SYSINFO_SD_KEYY": "SD keyY: %s\r\n", + "SYSINFO_NAND_CID": "NAND CID: %s\r\n", + "SYSINFO_SD_CID": "SD CID: %s\r\n", + "SYSINFO_SYSTEM_ID0": "System ID0: %s\r\n", + "SYSINFO_SYSTEM_ID1": "System ID1: %s\r\n", + "SORTING_TICKETS_PLEASE_WAIT": "Sorting tickets, please wait ..." +} diff --git a/utils/transriff.py b/utils/transriff.py new file mode 100755 index 0000000..c0f2d8c --- /dev/null +++ b/utils/transriff.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +from argparse import ArgumentParser +from os import path + +import json +import struct + +parser = ArgumentParser(description="Creates an TRF translation for GodMode9 from a translation JSON") +parser.add_argument("input", type=str, help="JSON to convert from") +parser.add_argument("output", type=str, help="to output to") +parser.add_argument("version", type=int, help="translation version, from language.inl") + +args = parser.parse_args() + +with open(args.input, "r") as f: + # read JSON + strings = json.load(f) + if "GM9_LANGUAGE" not in strings: + print("Fatal: Input is not a valid JSON file") + exit(1) + + # Encode strings to UTF-8 bytestrings + strings = {item: strings[item].encode("utf-8") + b"\0" for item in strings} + + # Remove language name from strings + lang_name = strings["GM9_LANGUAGE"] + del strings["GM9_LANGUAGE"] + + # sort map + # fontMap = sorted(fontMap, key=lambda x: x["mapping"]) + + # write file + with open(args.output, "wb") as out: + out.write(b"RIFF") + out.write(struct.pack("