Fix Russian character deletion confirmation #9

Merged
sindoring merged 1 commits from fix/ruru-delete-confirmation into main 2026-10-17 23:43:35 +03:00
2 changed files with 93 additions and 0 deletions
@@ -5,6 +5,27 @@
BENILLA_REALMLIST and BENILLA_REALMLIST_PINNED (set while $WOW_HOST fixes the address),
and reopens the dialog with the typed text when it is not an address. -->
<Script>
-- CharacterSelect.xml:679 compares the confirmation through strupper. Native 1.12 upper
-- (0x7fc180) leaves Cyrillic unchanged; the community ruRU pack needs its own case fold.
if GetLocale() == "ruRU" then
local function upper(text)
local result = strupper(text)
local lower = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя"
local capitals = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ"
for i = 1, string.len(lower), 2 do
result = string.gsub(result, string.sub(lower, i, i + 1), string.sub(capitals, i, i + 1))
end
return result
end
CharacterDeleteEditBox:SetScript("OnTextChanged", function()
if upper(this:GetText()) == upper(DELETE_CONFIRM_STRING) then
CharacterDeleteButton1:Enable()
else
CharacterDeleteButton1:Disable()
end
end)
end
GlueDialogTypes["BENILLA_REALMLIST"] = {
-- The realmList CVar's registered help text.
text = "Address of realm list server",
@@ -38,6 +38,78 @@ fn ruru_stock_glue_loads_and_keeps_cyrillic_character_names() {
assert!(script.take_errors().is_empty());
}
#[test]
fn ruru_delete_confirmation_accepts_typed_cyrillic_without_case_sensitivity() {
let data = benilla_formats::wow_data_or_skip!();
let locale = benilla_formats::ClientLocale::RuRu;
if locale.pack_folder(&data).is_none() {
benilla_formats::skipped_optional("no ruRU language pack", &[data.join("ruRU")]);
return;
}
let chain = benilla_formats::Chain::open_localized(&data, locale).unwrap();
let _selected = super::reference_ui::fixture::use_chain(chain);
let mut script = UiScript::new_glue().unwrap();
script.set_russian_language_pack(true);
script.set_screen_size(1024.0, 768.0);
assert!(load_glue(&mut script).is_empty());
// Offline only: exercise the stock buttons and Enter without requesting a real deletion.
script
.run(
"GetCharacterInfo = function() return 'Probe', 'Human', 'Warrior', 1 end; \
DELETE_REQUESTS = 0; \
DeleteCharacter = function() DELETE_REQUESTS = DELETE_REQUESTS + 1 end; \
CharacterSelect.selectedIndex = 1; GlueParent:Show()",
)
.unwrap();
for (typed, accepted) in [
("Удалить", true),
("удалить", true),
("УдАлИтЬ", true),
("УДАЛИТЬ", true),
("Удали", false),
("Удалить!", false),
(" Удалить", false),
("DELETE", false),
("", false),
] {
for enter in [false, true] {
script
.run(
"CharacterDeleteDialog:Hide(); CharacterDeleteDialog:Show(); \
CharacterDeleteEditBox:SetFocus()",
)
.unwrap();
script.tick(0.01);
assert_eq!(text(&script, "CharacterDeleteEditBox"), "");
for c in typed.chars() {
script.char_input(&c.to_string());
}
script.tick(0.01);
assert_eq!(text(&script, "CharacterDeleteEditBox"), typed);
assert_eq!(
script
.eval::<bool>("return CharacterDeleteButton1:IsEnabled() == 1")
.unwrap(),
accepted,
"{typed:?}"
);
let before: i64 = script.eval("return DELETE_REQUESTS").unwrap();
if enter {
script.frame_key_input("ENTER");
script.key_up("ENTER");
} else {
script.run("CharacterDeleteButton1:Click()").unwrap();
}
assert_eq!(
script.eval::<i64>("return DELETE_REQUESTS").unwrap() - before,
i64::from(accepted),
"{typed:?}, enter={enter}"
);
}
}
assert!(script.take_errors().is_empty());
}
/// The stock glue VM on `screen` with both agreements accepted, as a returning player's is.
fn glue_on(screen: GlueScreen) -> UiScript {
let mut s = UiScript::new_glue().unwrap();