diff --git a/memory/build_and_verification.md b/memory/build_and_verification.md index c6022d9..cf66997 100644 --- a/memory/build_and_verification.md +++ b/memory/build_and_verification.md @@ -159,3 +159,11 @@ Chinese numeric-format follow-up: GetCurrentGameLanguage() values schinese/tchin - Validation: four new tag-parser regression tests first reproduced rejection in the index and all manifest version conditions; all 11 Python tests passed after the change. Verified the official release archive SHA-256, validated all 27 upstream snapshots, then supplied its immutable index and verified cache to the real synchronizer entry point. All 23 pruned snapshots passed standalone manifest validation and CLI validate-only; Decay retained exactly client/g_iVisibleMouse and client CRC64 8a933c53ba9f3979. The original 22 snapshots remained byte-identical when pruned with the old versus new manifest. - Publication dependency: at verification time Pages still had 26 upstream snapshots and no decay. A real default online-sync attempt failed with `gameVersion(s) absent from the index: decay`; the release archive being available does not publish the Pages index. Default online builds require the upstream Pages deployment before they can consume this manifest. - Scope/evidence: Python/catalog changes only; no native rebuild, deployment or Decay in-game test. Temporary release and verification output: C:/Users/HZDEV/AppData/Local/Temp/vgui2extension-release-check-163b7a2af3ae46419e53b07bdac2423c. This verifies catalog compatibility, not host/runtime compatibility. + + +## Issue 951: Career confirmation localization (2026-10-25) + +- Trigger/root cause: the rewritten Career storage confirmation uses wide English literals for both QueryBox title and body. DeleteProfile is intercepted before the native CareerBoxDelete resource path; adding the official token again cannot localize those literals. Issue attachment 1 shows this English dialog, while attachment 2 is a Chinese reference; neither shows a bare token. Official czero_schinese/resource/czero_schinese.txt already contains Career_DeleteProfileTitle/Text. +- Fix: ConfirmOperation reuses the existing delete and overwrite title/text tokens, converts the complete identity.rawUtf8 with ConvertCareerPlayerNameToUnicode, and formats the delete body with ILocalize::ConstructString. Allocate from the format and complete Unicode name lengths; use readable English title/body fallbacks for missing tokens. Prepare display text before issuing the sidecar confirmation; preserve existing confirmation-token commands, cancel handling and verified deletion ownership. No language-file override or gamedata change. +- Verification: MSVC x86 Release DLL build, all 8 existing CTests, pinned format-check (66 files) passed. Existing ClientVGUI.cpp C4018 warning remains. Windows czero engine 10210, schinese, 1280x720 live: delete title/body localized and displayed the complete Issue951_123456789012345678901234中文Z name beyond the native 31-byte limit. Delete cancel and overwrite cancel preserved the task profile SHA-256; overwrite title/body localized. ENTER confirmed deletion of the task profile, while pre-existing profile hashes were unchanged. +- Scope/cleanup: game PID 67992 quit normally with exit code 0. Original 21 backed-up DLL/PDB/config/profile/list/appid files were restored and SHA-256 verified. Five task screenshots moved to build/issue951-runtime/screenshots (HalfLife47.tga deletion; HalfLife48.tga overwrite). English language, forced missing-token fallback, other builds and extreme-length layout were not tested in-game. This fixes localization, not the separate native difficulty-label ellipsis. diff --git a/src/CareerProfileStorageHooks.cpp b/src/CareerProfileStorageHooks.cpp index b4d54a4..06b57fc 100644 --- a/src/CareerProfileStorageHooks.cpp +++ b/src/CareerProfileStorageHooks.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -1226,17 +1227,38 @@ void __fastcall ProfileCommand(void* self, int, const char* command); void ConfirmOperation(void* frame, Operation operation, const Identity& identity) { - auto token = sidecars.Confirm(Handle(frame), operation, operation == Operation::Create ? identity.rawUtf8 : std::string_view{}); + const bool create = operation == Operation::Create; + auto* localization = vgui::localize(); + const auto title = localization->Find(create ? "#Career_OverwriteConfirmationTitle" : "#Career_DeleteProfileTitle"); + const auto format = localization->Find(create ? "#Career_OverwriteConfirmationText" : "#Career_DeleteProfileText"); + std::wstring text; + if (create) + { + text = format ? format : L"This will overwrite a saved profile.\nContinue anyway?"; + } + else + { + std::wstring name; + if (!ConvertCareerPlayerNameToUnicode(identity.rawUtf8.c_str(), name)) + { + ShowError(StorageError::InvalidUtf8); + return; + } + + const auto query = format ? format : L"Are you sure you want to delete %s1?"; + text.resize(wcslen(query) + name.size() + 1, L'\0'); + localization->ConstructString(text.data(), static_cast(text.size() * sizeof(wchar_t)), query, 1, name.c_str()); + } + + auto token = sidecars.Confirm(Handle(frame), operation, create ? identity.rawUtf8 : std::string_view{}); if (!token) { ShowError(token.error); return; } - const auto command = std::string(operation == Operation::Create ? "CareerStorageCreate " : "CareerStorageDelete ") + token.value; - auto* box = new vgui::QueryBox(L"Career profile", - operation == Operation::Create ? L"Overwrite the existing profile with this complete player name?" : L"Delete this profile and its verified legacy copies?", - nullptr); + const auto command = std::string(create ? "CareerStorageCreate " : "CareerStorageDelete ") + token.value; + auto* box = new vgui::QueryBox(title ? title : (create ? L"Overwrite profile" : L"Delete profile"), text.c_str(), nullptr); box->SetParent(VPanel(frame)); box->AddActionSignalTarget(static_cast(frame)); box->SetOKCommand(new KeyValues("Command", "command", command.c_str()));