diff --git a/runtime/hle/delegate_null.c b/runtime/hle/delegate_null.c index b015ec41a..6e6d1e38a 100644 --- a/runtime/hle/delegate_null.c +++ b/runtime/hle/delegate_null.c @@ -55,12 +55,25 @@ int rt_delegate_null(Cpu *c, int slot) { plat_sleep_until_ns(plat_now_ns() + 50000); } } + bool recovered = false; + // A stale chain-job release can be the only wakeup after its original release was skipped (#23). + if (!forwarded && vt == GA(DELEGATE_JOB_VTABLE_BASE) && in_owner && !rd64(obj + 0x10) && + rd32(obj + 0x20) == 1 && !rd32(owner + 0x1f8)) { + uint8_t expected = 0; + if (__atomic_compare_exchange_n((uint8_t *)(uintptr_t)(owner + 0x1d8), &expected, 1, false, + __ATOMIC_RELEASE, __ATOMIC_RELAXED)) { + c->x[0] = owner + 0x204; + guest_call(c, guest_sym("_ZNSt3__118condition_variable10notify_oneEv")); + recovered = true; + } + } static int logged; if (logged++ < 16) LOG("[delegate] %#llx slot +0x%x: no delegate at [this+0x10] (vtable %#llx, count %#x, lr %#llx, owner %#llx done %d " "lock %#x) - %s after %llu us (issue #19)\n", (unsigned long long)obj, slot, (unsigned long long)vt, rd32(obj + 0x20), (unsigned long long)c->x[30], (unsigned long long)owner, in_owner ? *(uint8_t *)(uintptr_t)(owner + 0x1d8) : -1, - in_owner ? rd32(owner + 0x1f8) : 0, forwarded ? "forwarded" : "skipped", (unsigned long long)(waited / 1000)); + in_owner ? rd32(owner + 0x1f8) : 0, forwarded ? "forwarded" : recovered ? "recovered" : "skipped", + (unsigned long long)(waited / 1000)); if (forwarded) return 0; c->x[0] = 0; // (returns 0, as slot +0x38 does when its delegate is missing: x0 is the delegate it loaded) return 1; diff --git a/runtime/ui/controls_ui.mm b/runtime/ui/controls_ui.mm index 7b3229192..d2307ab95 100644 --- a/runtime/ui/controls_ui.mm +++ b/runtime/ui/controls_ui.mm @@ -221,7 +221,7 @@ static void configure_inputs(float scale) { } } g_in_right = in_right; - if (cd == dev) ImGui::TextDisabled("Esc cancels."); + if (cd == dev) ImGui::TextDisabled("%s", T("Esc cancels.")); else if (msg[0]) ImGui::TextDisabled("%s", msg); } opt_split_end(); diff --git a/runtime/ui/i18n_pt_br.h b/runtime/ui/i18n_pt_br.h index f2c27b8ab..a69733eb9 100644 --- a/runtime/ui/i18n_pt_br.h +++ b/runtime/ui/i18n_pt_br.h @@ -18,6 +18,10 @@ {"Close", "Fechar"}, {"Delete", "Excluir"}, {"Done", "Concluído"}, +{"Move", "Mover"}, +{"Use it", "Usar"}, +{"Start fresh", "Começar do zero"}, +{"Change...", "Alterar..."}, {"Play", "Jogar"}, {"PLAY", "JOGAR"}, {"Settings", "Configurações"}, @@ -26,9 +30,20 @@ {"Quit", "Sair"}, {"Random", "Aleatório"}, {"Tap the letters, then OK (%d / %d)", "Toque nas letras e depois em OK (%d / %d)"}, +{"%s type %s delete %s OK (%d / %d)", "%s digitar %s apagar %s OK (%d / %d)"}, {"Buttons", "Botões"}, {"What the game uses", "Os que o jogo usa"}, {"All", "Todos"}, +{"Triggers", "Gatilhos"}, +{"Sticks", "Analógicos"}, +{"D-pad", "Direcional"}, +{"Game layout", "Layout do jogo"}, +{"Controller convention", "Padrão do controle"}, +{"Confirm button", "Botão de confirmação"}, +{"Which button confirms in LAS Recomp's menus.", "Qual botão confirma nos menus do LAS Recomp."}, +{"Esc cancels.", "Esc cancela."}, +{"Companion:", "Companheiro:"}, +{"(also on the pause menu's Items page: LEFT from the item grid)", "(também na página Itens do menu de pausa: ESQUERDA na grade de itens)"}, {"What the game uses: only the buttons that do something right now - B once Link has the sword, R with the shield, X / Y with the items you equip. All: every button, all the time.", "Os que o jogo usa: só os botões que fazem algo agora - B quando o Link tem a espada, R com o escudo, X / Y com os itens equipados. Todos: todos os botões, o tempo todo."}, {"Storage", "Armazenamento"}, @@ -227,6 +242,8 @@ {"Chinese (Traditional)", "Chinês (tradicional)"}, {"The game's text language, as its own system setting. Applies when the game restarts: Quit -> Quit to Start Screen, then Play. App language: this menu and the start screen, at once.", "O idioma dos textos do jogo, como a configuração de sistema do próprio console. Vale quando o jogo reinicia: Sair -> Voltar à tela inicial, depois Jogar. Idioma do app: este menu e a tela inicial, na hora."}, +{"This menu and the start screen, at once. Auto: the system's language. Spanish, French, German, Italian and Dutch cover the main menus and settings; the rest stays in English.", + "Este menu e a tela inicial, na hora. Automático: o idioma do sistema. Espanhol, francês, alemão, italiano e holandês estão disponíveis nos menus principais e nas configurações; o restante fica em inglês."}, {"Portuguese (Brazil) needs the fan translation: copy its files to translations/pt-BR in the app's data folder. Until then the game's text stays in English.", "Português (Brasil) precisa da tradução de fãs: copie os arquivos dela para translations/pt-BR na pasta de dados do app. Até lá os textos do jogo ficam em inglês."}, {"Portuguese (Brazil) needs the fan translation: import the folder extracted from its zip. Until then the game's text stays in English.", @@ -254,6 +271,9 @@ "Selecione um comando e pressione o novo botão ou tecla. Esc (ou 5 segundos) cancela. Um botão que já está em uso troca de lugar com o antigo."}, {"Controller bindings reset to the defaults.", "Comandos do controle restaurados para o padrão."}, {"Keyboard bindings reset to the defaults.", "Comandos do teclado restaurados para o padrão."}, +{"Restore default controls", "Restaurar controles padrão"}, +{"Puts every controller button back to its default.", "Restaura todos os botões do controle para o padrão."}, +{"Puts every key back to its default.", "Restaura todas as teclas para o padrão."}, {"%s is now %s.", "%s agora é %s."}, {"%s is now %s; %s moved to %s (swapped).", "%s agora é %s; %s foi para %s (trocados)."}, {"Cancelled: %s unchanged.", "Cancelado: %s não mudou."}, @@ -300,6 +320,20 @@ // ---- Gameplay {"General", "Geral"}, +{"Goal", "Objetivo"}, +{"Extra pieces", "Peças extras"}, +{"Pieces needed", "Peças necessárias"}, +{"How many pieces finish the game.", "Quantas peças são necessárias para zerar o jogo."}, +{"How many pieces finish the game: 1 to 50.", "Quantas peças são necessárias para zerar o jogo: de 1 a 50."}, +{"Mode", "Modo"}, +{"Seeded", "Determinístico"}, +{"Mini-boss frequency", "Frequência de mini-chefes"}, +{"How often overworld enemies become mini-bosses. All: every one with room for one.", + "Com que frequência os inimigos do mundo aberto viram mini-chefes. Todos: cada inimigo em uma sala que comporte um."}, +{"Keysanity", "Keysanity"}, +{"Shopsanity", "Shopsanity"}, +{"Every good in the Mabe Village shop is a check: the shield, hearts, shovel, bombs, chamber stone and piece of heart. Buy it, or steal it (the shopkeeper remembers a thief).", + "Cada produto da loja de Mabe Village é um check: o escudo, os corações, a pá, as bombas, as chamber stones e a piece of heart. Compre ou roube (o vendedor se lembra de um ladrão)."}, {"Hookshot anything", "Hookshot em tudo"}, {"On: this randomizer seed was made with Hookshot Anything, and its logic counts on it.", "Ligado: esta seed do randomizer foi feita com Hookshot em tudo, e a lógica dela conta com isso."}, {"The hookshot latches onto any wall or object, not only its targets. Randomizer seeds made with Hookshot Anything always have it on.", @@ -314,6 +348,10 @@ {"Half", "Metade"}, {"Damage taken", "Dano recebido"}, {"How much damage Link takes from every hit: half, the game's own, or up to eight times as much.", "Quanto dano o Link leva de cada golpe: metade, o do jogo, ou até oito vezes mais."}, +{"Brisk", "Rápida"}, +{"Running", "Correndo"}, +{"Sprinting", "Disparando"}, +{"Zoomies", "Superveloz"}, {"One-hit KO", "Morte com um golpe"}, {"Any hit defeats Link, whatever his hearts.", "Qualquer golpe derrota o Link, não importa quantos corações ele tenha."}, @@ -358,6 +396,8 @@ // ---- start screen (launcher.mm) {"Test build ", "Build de teste "}, {"Version ", "Versão "}, +{"Fonts aren't included. For the original look, import your own copies of nintendo_udsg-r_std_003.bfttf (text), the same-named files for Chinese and Korean (nintendo_udsg-r_org_zh-cn_003, nintendo_udsg-r_ext_zh-cn_003, nintendo_udjxh-db_zh-tw_003, nintendo_udsg-r_ko_003) and nintendo_ext_003.bfttf (button icons). .ttf versions with the same names work too.", + "As fontes não vêm incluídas. Para o visual original, importe suas próprias cópias de nintendo_udsg-r_std_003.bfttf (texto), dos arquivos de mesmo nome para chinês e coreano (nintendo_udsg-r_org_zh-cn_003, nintendo_udsg-r_ext_zh-cn_003, nintendo_udjxh-db_zh-tw_003, nintendo_udsg-r_ko_003) e de nintendo_ext_003.bfttf (ícones dos botões). Arquivos .ttf com os mesmos nomes também funcionam."}, {"Game files incomplete (%d of %d files)", "Arquivos do jogo incompletos (%d de %d arquivos)"}, {"No game files yet", "Ainda sem arquivos do jogo"}, {"Wrong version of the game", "Versão errada do jogo"}, @@ -410,6 +450,9 @@ "O .xci / .nsp parece danificado ou incompleto. Extraia ou copie de novo e escolha a pasta outra vez."}, {"The folder with your own copy of The Legend of Zelda: Link's Awakening for Nintendo Switch, version 1.0.0: its .xci or .nsp together with the prod.keys from your Switch (asked for if it isn't there), or its extracted exefs and romfs folders. The game isn't included with LAS Recomp.", "A pasta com a sua cópia de The Legend of Zelda: Link's Awakening para Nintendo Switch, versão 1.0.0: o .xci ou .nsp junto com o prod.keys do seu Switch (pedido se não estiver lá), ou as pastas exefs e romfs extraídas. O jogo não vem com o LAS Recomp."}, +{"The folder with your own extracted game files (exefs/romfs) of The Legend of Zelda: Link's Awakening for Nintendo Switch. The game isn't included with LAS Recomp.", + "A pasta com os arquivos extraídos do seu próprio jogo (exefs/romfs) de The Legend of Zelda: Link's Awakening para Nintendo Switch. O jogo não vem incluído no LAS Recomp."}, +{"LAS Recomp needs version 1.0.0, 1.0.1 or 1.1.0 of the game.", "O LAS Recomp precisa da versão 1.0.0, 1.0.1 ou 1.1.0 do jogo."}, {"Your game files are incomplete", "Seus arquivos do jogo estão incompletos"}, {"The game code didn't build", "O código do jogo não compilou"}, {"Choose the folder that has the game's exefs and romfs folders in it.", "Escolha a pasta que contém as pastas exefs e romfs do jogo."}, @@ -417,7 +460,7 @@ {"Make sure there's about 12 GB free and try again.", "Verifique se há uns 12 GB livres e tente de novo."}, {"Some of the game's files are missing - usually a copy or unzip that stopped partway. Copy the game files again so none are missing, then choose the folder again.", "Faltam alguns arquivos do jogo - normalmente uma cópia ou extração que parou no meio. Copie os arquivos do jogo de novo para não faltar nenhum e escolha a pasta outra vez."}, -{"Make sure there's about 2 GB free and try again. If it keeps happening, report it on Discord or GitHub.", "Verifique se há uns 2 GB livres e tente de novo. Se continuar acontecendo, avise no Discord ou no GitHub."}, +{"Make sure there's about 2 GB free and try again. If it keeps happening, report it on GitHub.", "Verifique se há uns 2 GB livres e tente de novo. Se continuar acontecendo, relate o problema no GitHub."}, {"The romfs folder has %d of the game's %d files - some are missing, usually from a copy or unzip that stopped partway. Copy the game files again so none are missing, then choose the folder again.", "A pasta romfs tem %d dos %d arquivos do jogo - faltam alguns, normalmente por uma cópia ou extração que parou no meio. Copie os arquivos do jogo de novo para não faltar nenhum e escolha a pasta outra vez."}, {"Copying the game files...", "Copiando os arquivos do jogo..."}, @@ -426,6 +469,30 @@ {" GB more. Free some space and try again.", " GB. Libere espaço e tente de novo."}, {"Build liblasgame.so from these game files on a computer (tools/android/build_game.sh) and install it.", "Compile o liblasgame.so a partir destes arquivos do jogo num computador (tools/android/build_game.sh) e instale-o."}, {"Game files ready.", "Arquivos do jogo prontos."}, +{"Resume game code", "Retomar compilação do jogo"}, +{"Build cache", "Cache de compilação"}, +{"Clear build cache", "Limpar cache de compilação"}, +{"Removes the saved game-code build files. The next setup compiles everything again.", + "Remove os arquivos salvos da compilação do código do jogo. Na próxima preparação, tudo será compilado novamente."}, +{"Build cache cleared.", "Cache de compilação limpo."}, +{"Could not clear the build cache.", "Não foi possível limpar o cache de compilação."}, +{"Data folder", "Pasta de dados"}, +{"Moving your data", "Movendo seus dados"}, +{"This folder is synced by OneDrive", "Esta pasta é sincronizada pelo OneDrive"}, +{"All game files (about %.0f GB) will be uploaded to your OneDrive.", "Todos os arquivos do jogo (cerca de %.0f GB) serão enviados para o seu OneDrive."}, +{"Choose another folder", "Escolher outra pasta"}, +{"Keep here", "Manter aqui"}, +{"This folder is synced by OneDrive too.", "Esta pasta também é sincronizada pelo OneDrive."}, +{"This folder already has LAS Recomp data. Use it?", "Esta pasta já contém dados do LAS Recomp. Quer usá-la?"}, +{"Move your saves, seeds, settings and game files (%.1f GB) there, or start fresh?", + "Mover seus saves, seeds, configurações e arquivos do jogo (%.1f GB) para lá ou começar do zero?"}, +{"Not enough free space there to move them (%.1f GB free).", "Não há espaço livre suficiente para movê-los para lá (%.1f GB livres)."}, +{"Couldn't start the move.", "Não foi possível iniciar a transferência."}, +{"Copying...", "Copiando..."}, +{"Checking the copy...", "Verificando a cópia..."}, +{"Removing the old copy...", "Removendo a cópia antiga..."}, +{"Restarting...", "Reiniciando..."}, +{"Your data is still in %s", "Seus dados ainda estão em %s"}, {"Looking for the game files...", "Procurando os arquivos do jogo..."}, {"Reading the game code...", "Lendo o código do jogo..."}, {"Recompiling...", "Recompilando..."}, @@ -692,6 +759,11 @@ // ---- Save editor (item names stay as the game has them) {"Load a save file first: the editor changes the save that's currently being played.", "Carregue um save antes: o editor muda o save que está sendo jogado."}, +{"Heart Containers", "Recipientes de coração"}, +{"Pieces of Heart", "Pedaços de coração"}, +{"Golden Leaves", "Folhas douradas"}, +{"Rupees", "Rupees"}, +{"Secret Seashells", "Secret Seashells"}, {"Quick", "Rápido"}, {"Max out everything", "Maximizar tudo"}, {"Every heart, item, upgrade, song, instrument and dungeon key, full ammo, 999 rupees, all 50 Secret Seashells and 5 Golden Leaves.\n\nThe hearts on the HUD update after the next screen change.", @@ -804,6 +876,7 @@ {"Intensity", "Intensidade"}, {"How strong the vibration is.", "A força da vibração."}, {"The button icons the game shows, and which button confirms in these menus. Auto: the connected controller's.", "Os ícones de botões que o jogo mostra, e qual botão confirma nestes menus. Automático: os do controle conectado."}, +{"The button icons the game shows. Auto: the connected controller's.", "Os ícones de botões exibidos pelo jogo. Automático: os do controle conectado."}, {"The game's text language, as its own system setting. Applies when the game restarts.", "O idioma dos textos do jogo, como a configuração do sistema dele. Vale quando o jogo reinicia."}, {"This menu and the start screen, at once. Auto: the system's language.", "Este menu e a tela inicial, na hora. Automático: o idioma do sistema."}, {"Walk speed", "Velocidade de caminhada"}, diff --git a/runtime/ui/launcher.mm b/runtime/ui/launcher.mm index 61389a1a9..bdc63f55c 100644 --- a/runtime/ui/launcher.mm +++ b/runtime/ui/launcher.mm @@ -749,8 +749,8 @@ static int onedrive_notice(float s, float w, bool ready) { ImGui::PopStyleVar(2); ImGui::PopStyleColor(); ImGui::PushTextWrapPos(0); - ImGui::TextColored(ImVec4(1, 0.72f, 0.4f, 1), "! This folder is synced by OneDrive"); - ImGui::TextColored(ImVec4(0.86f, 0.85f, 0.80f, 1), "All game files (about %.0f GB) will be uploaded to your OneDrive.", + ImGui::TextColored(ImVec4(1, 0.72f, 0.4f, 1), "! %s", T("This folder is synced by OneDrive")); + ImGui::TextColored(ImVec4(0.86f, 0.85f, 0.80f, 1), T("All game files (about %.0f GB) will be uploaded to your OneDrive."), fmax(1.0, gb)); ImGui::PopTextWrapPos(); ImGui::Dummy(ImVec2(0, 4 * s)); @@ -760,11 +760,11 @@ static int onedrive_notice(float s, float w, bool ready) { pthread_mutex_unlock(&g_lock); if (!rt_data_root_fixed()) { ImGui::BeginDisabled(busy); - if (ImGui::Button("Choose another folder")) r = 2; + if (ImGui::Button(T("Choose another folder"))) r = 2; ImGui::EndDisabled(); ImGui::SameLine(); } - if (ImGui::Button("Keep here")) r = 1; + if (ImGui::Button(T("Keep here"))) r = 1; ImGui::EndChild(); return r; } @@ -1022,7 +1022,7 @@ static bool menu_tip(float s) { ImGui::Dummy(ImVec2(0, 14 * s)); ImGui::SetCursorPosX((ImGui::GetWindowWidth() - 180 * s) * 0.5f); ImGui::SetItemDefaultFocus(); - if (ImGui::Button("OK", ImVec2(180 * s, 44 * s)) || ImGui::IsKeyPressed(ImGuiKey_Enter) || + if (ImGui::Button(T("OK"), ImVec2(180 * s, 44 * s)) || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_GamepadFaceDown)) { g_settings.menu_tip_seen = true; settings_save(); @@ -1431,7 +1431,7 @@ static void data_folder_popup(float s) { ImVec2 bw(240 * sc, 0); ImGui::PushFont(g_font_small); ImGui::PushFont(g_font_menu); - ImGui::TextColored(ImVec4(0.93f, 0.76f, 0.33f, 1), g_df == DF_MOVING ? "Moving your data" : "Data folder"); + ImGui::TextColored(ImVec4(0.93f, 0.76f, 0.33f, 1), "%s", T(g_df == DF_MOVING ? "Moving your data" : "Data folder")); ImGui::PopFont(); ImGui::PushTextWrapPos(900 * sc); bool close = false, esc = ImGui::IsKeyPressed(ImGuiKey_GamepadFaceRight, false) || ImGui::IsKeyPressed(ImGuiKey_Escape, false); @@ -1443,25 +1443,25 @@ static void data_folder_popup(float s) { }; if (g_df == DF_ASK) { ImGui::TextDisabled("%s", t.path); - if (g_df_onedrive) ImGui::TextColored(ImVec4(1, 0.72f, 0.4f, 1), "This folder is synced by OneDrive too."); + if (g_df_onedrive) ImGui::TextColored(ImVec4(1, 0.72f, 0.4f, 1), "%s", T("This folder is synced by OneDrive too.")); ImGui::Spacing(); if (t.refuse[0]) { ImGui::TextColored(red, "%s", t.refuse); ImGui::Spacing(); - close = ImGui::Button("OK", bw) || esc; + close = ImGui::Button(T("OK"), bw) || esc; } else if (t.has_data) { - ImGui::Text("This folder already has LAS Recomp data. Use it?"); + ImGui::TextUnformatted(T("This folder already has LAS Recomp data. Use it?")); ImGui::Spacing(); - if (ImGui::Button("Use it", bw) || g_df_auto_fresh) g_df_auto_fresh = false, use_it(); + if (ImGui::Button(T("Use it"), bw) || g_df_auto_fresh) g_df_auto_fresh = false, use_it(); ImGui::SameLine(); - close = ImGui::Button("Cancel", bw) || esc; + close = ImGui::Button(T("Cancel"), bw) || esc; } else { bool room = t.free >= t.need; - ImGui::Text("Move your saves, seeds, settings and game files (%.1f GB) there, or start fresh?", t.bytes / 1e9); - if (!room) ImGui::TextColored(red, "Not enough free space there to move them (%.1f GB free).", t.free / 1e9); + ImGui::Text(T("Move your saves, seeds, settings and game files (%.1f GB) there, or start fresh?"), t.bytes / 1e9); + if (!room) ImGui::TextColored(red, T("Not enough free space there to move them (%.1f GB free)."), t.free / 1e9); ImGui::Spacing(); ImGui::BeginDisabled(!room); - if ((ImGui::Button("Move", bw) || g_df_auto_move) && room) { + if ((ImGui::Button(T("Move"), bw) || g_df_auto_move) && room) { g_df_auto_move = false; stop_background_prep(); settings_save(); @@ -1472,24 +1472,24 @@ static void data_folder_popup(float s) { } ImGui::EndDisabled(); ImGui::SameLine(); - if (ImGui::Button("Start fresh", bw) || g_df_auto_fresh) g_df_auto_fresh = false, use_it(); + if (ImGui::Button(T("Start fresh"), bw) || g_df_auto_fresh) g_df_auto_fresh = false, use_it(); ImGui::SameLine(); ImGui::SetItemDefaultFocus(); - close = ImGui::Button("Cancel", bw) || esc; + close = ImGui::Button(T("Cancel"), bw) || esc; } } else if (g_df == DF_MOVING) { static const char *const steps[] = {"Copying...", "Checking the copy...", "Removing the old copy..."}; int r = g_df_result, k = g_df_step; - ImGui::Text("%s", r == 1 ? "Restarting..." : steps[k < 0 ? 0 : k > 2 ? 2 : k]); + ImGui::TextUnformatted(T(r == 1 ? "Restarting..." : steps[k < 0 ? 0 : k > 2 ? 2 : k])); ImGui::ProgressBar(r == 1 ? 1.0f : g_df_frac.load(), ImVec2(900 * sc, 0)); ImGui::TextDisabled("%s", t.path); if (r == 1) df_restart(); else if (r == -1) g_df = DF_FAILED; } else { ImGui::TextColored(red, "%s", g_df_err); - ImGui::Text("Your data is still in %s", rt_data_root()); + ImGui::Text(T("Your data is still in %s"), rt_data_root()); ImGui::Spacing(); - close = ImGui::Button("OK", bw) || esc; + close = ImGui::Button(T("OK"), bw) || esc; } ImGui::PopTextWrapPos(); ImGui::PopFont(); @@ -1598,7 +1598,7 @@ static void prelaunch_tab(float sc) { ImGui::PopTextWrapPos(); const char *fixed = rt_data_root_fixed(); ImGui::BeginDisabled(fixed != NULL); - if (ImGui::Button("Change...")) choose_data_folder(); + if (ImGui::Button(T("Change..."))) choose_data_folder(); ImGui::EndDisabled(); if (fixed) ImGui::SameLine(), ImGui::TextDisabled("%s", fixed); ImGui::Spacing(); diff --git a/runtime/ui/option_rows.mm b/runtime/ui/option_rows.mm index 20968fceb..0c2f3b3a2 100644 --- a/runtime/ui/option_rows.mm +++ b/runtime/ui/option_rows.mm @@ -317,7 +317,7 @@ bool opt_colour(const char *label, CosColour *c, int slot, const char *desc) { c->rgb = (uint32_t)lroundf(f[0] * 255) << 16 | (uint32_t)lroundf(f[1] * 255) << 8 | (uint32_t)lroundf(f[2] * 255); changed = true; } - if (ImGui::Button("Done") || ImGui::IsKeyPressed(ImGuiKey_Escape, false)) + if (ImGui::Button(T("Done")) || ImGui::IsKeyPressed(ImGuiKey_Escape, false)) ImGui::CloseCurrentPopup(); ImGui::EndPopup(); } diff --git a/runtime/ui/osk.mm b/runtime/ui/osk.mm index ea181cb17..a337479ae 100644 --- a/runtime/ui/osk.mm +++ b/runtime/ui/osk.mm @@ -146,7 +146,7 @@ int osk_keys(char *text, size_t cap, int max_chars, bool appearing, float scale, if (ImGui::Button(T("Cancel"), ImVec2(w2, k))) r = -1; ImGui::SameLine(); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.80f, 0.60f, 0.15f, 0.85f)); - if (ImGui::Button("OK", ImVec2(w2, k))) r = 1; + if (ImGui::Button(T("OK"), ImVec2(w2, k))) r = 1; ImGui::PopStyleColor(); ImGui::TextDisabled(T("Tap the letters, then OK (%d / %d)"), len, max_chars); return r; @@ -159,7 +159,7 @@ int osk_keys(char *text, size_t cap, int max_chars, bool appearing, float scale, ImGui::SameLine(); if (ImGui::Button(T("Cancel"), ImVec2(k * 2, k))) r = -1; ImGui::SameLine(); - if (ImGui::Button("OK", ImVec2(k * 2, k))) r = 1; + if (ImGui::Button(T("OK"), ImVec2(k * 2, k))) r = 1; ImGui::TextDisabled(T("%s type %s delete %s OK (%d / %d)"), ui_pad_confirm_label(), ui_pad_back_label(), ui_pad_start_label(), len, max_chars); return r; diff --git a/runtime/ui/pets_ui.mm b/runtime/ui/pets_ui.mm index d60b2c005..77b52710b 100644 --- a/runtime/ui/pets_ui.mm +++ b/runtime/ui/pets_ui.mm @@ -2,6 +2,7 @@ // same choice as the Items page's companion slot, runtime/ui/inventory_overlay.mm; the swap happens at once). // Shown once a pet has been found on a seed with pets (tools/rando/pets.py). #include "imgui.h" +#include "i18n.h" extern "C" { int game_in_play(void); @@ -18,14 +19,14 @@ for (int i = 0; i < n; i++) any_pet |= c[i] >= 2; // (Marin / Ghost / Rooster: BowWow alone isn't a pet) if (!any_pet) return; ImGui::AlignTextToFramePadding(); - ImGui::TextUnformatted("Companion:"); + ImGui::TextUnformatted(T("Companion:")); for (int i = -1; i < n; i++) { int v = i < 0 ? 0 : c[i]; ImGui::SameLine(); ImGui::PushID(v); - if (ImGui::RadioButton(v ? pets_name(v) : "None", cur == v)) pets_call(v); + if (ImGui::RadioButton(v ? T(pets_name(v)) : T("None"), cur == v)) pets_call(v); ImGui::PopID(); } ImGui::SameLine(); - ImGui::TextDisabled("(also on the pause menu's Items page: LEFT from the item grid)"); + ImGui::TextDisabled("%s", T("(also on the pause menu's Items page: LEFT from the item grid)")); } diff --git a/runtime/ui/rando_tab.mm b/runtime/ui/rando_tab.mm index 757068444..994e71498 100644 --- a/runtime/ui/rando_tab.mm +++ b/runtime/ui/rando_tab.mm @@ -879,7 +879,7 @@ static void gen_overlay(float scale) { ImGui::TextUnformatted(T("With the entrance randomizer on, at least one kind of entrance must be shuffled.")); ImGui::Spacing(); ImGui::SetItemDefaultFocus(); - if (ImGui::Button("OK", ImVec2(220 * scale, 0)) || ImGui::IsKeyPressed(ImGuiKey_GamepadFaceRight, false) || + if (ImGui::Button(T("OK"), ImVec2(220 * scale, 0)) || ImGui::IsKeyPressed(ImGuiKey_GamepadFaceRight, false) || ImGui::IsKeyPressed(ImGuiKey_Escape, false)) ImGui::CloseCurrentPopup(); ImGui::EndPopup(); @@ -994,7 +994,7 @@ static void gen_overlay(float scale) { } opt_split(); ImGui::SetWindowFontScale(1.3f); // (as the descriptions) - ImGui::TextWrapped("How many pieces finish the game: 1 to 50."); + ImGui::TextWrapped("%s", T("How many pieces finish the game: 1 to 50.")); ImGui::SetWindowFontScale(1.0f); ImGui::Spacing(); opt_section("Custom");