local ns = _G.WoWTranslate_UK_NS

local _G = _G
local fragment_lookup = ns.DB and ns.DB.FragmentLookup or {}
local set_text_hook_installed = false
ns._setTextHookInstalled = false

local _translationCache = {}
local _translationCacheCount = 0
local TRANSLATION_CACHE_MAX = 32768

local preferredFont = "Interface\\AddOns\\WoWTranslate_UK\\assets\\Montserrat-Regular.ttf"
local preferredTitleFont = "Interface\\AddOns\\WoWTranslate_UK\\assets\\Montserrat-Bold.ttf"
local preferredBoldFont = "Interface\\AddOns\\WoWTranslate_UK\\assets\\Montserrat-Bold.ttf"
local preferredCombatFont = "Interface\\AddOns\\WoWTranslate_UK\\assets\\Montserrat-SemiBold.ttf"
local fallbackFont = "Interface\\AddOns\\WoWTranslate_UK\\assets\\Montserrat-Medium.ttf"
local fallbackTitleFont = "Interface\\AddOns\\WoWTranslate_UK\\assets\\Montserrat-Bold.ttf"

ns.PreferredFont = preferredFont
ns.PreferredTitleFont = preferredTitleFont
ns.preferredFont = preferredFont
ns.preferredTitleFont = preferredTitleFont
ns.PreferredBoldFont = preferredBoldFont
ns.PreferredCombatFont = preferredCombatFont
ns.FallbackFont = fallbackFont
ns.FallbackTitleFont = fallbackTitleFont

local function hasCyrillic(text)
    if type(text) ~= "string" then return false end
    return text:find("[\208-\211]") ~= nil
end
ns.hasCyrillic = hasCyrillic

local function selectFontForContext(originalFontFile)
    if not originalFontFile then return preferredFont end
    local lower = originalFontFile:lower()
    if lower:find("morpheus") or lower:find("morp") then
        return preferredTitleFont
    end
    if lower:find("skurri") or lower:find("skur") then
        return preferredCombatFont
    end
    if lower:find("frizqt") or lower:find("friz") then
        return preferredFont
    end
    if lower:find("arial") then
        return preferredFont
    end
    return preferredFont
end

ns.selectFontForContext = selectFontForContext

local function needsCyrillicFont(fontFile)
    if not fontFile then return true end
    if fontFile:find("Montserrat") then return false end
    return true
end
ns.needsCyrillicFont = needsCyrillicFont

local untranslatedCollector = {}

local mixed_phrase_rules = {
    { "Dragon Isles Ремісничий реагент", "Реагент для крафту Драконячих островів" },
    { "Dragon Isles Crafting Reagent", "Реагент для крафту Драконячих островів" },
    { "Ремісничий реагент Драконячих островів", "Реагент для крафту Драконячих островів" },
}

local prefix_rules = {
    ["Use:"] = "Використання:",
    ["Cooldown:"] = "Перезарядка:",
    ["Cast Time:"] = "Час застосування:",
    ["Range:"] = "Дальність:",
    ["Requires:"] = "Потребує:",
    ["Reagents:"] = "Реагенти:",
    ["Duration:"] = "Тривалість:",
    ["Damage:"] = "Урон:",
    ["Healing:"] = "Зцілення:",
    ["Chance:"] = "Шанс:",
    ["Stacks:"] = "Стоси:",
    ["Radius:"] = "Радіус:",
    ["Speed:"] = "Швидкість:",
    ["Channel:"] = "Каналізація:",
}

local prefix_regex_rules = {
    { "^Experience: ([%d,]+)", "Досвід: %1" },
    { "^Reputation: (.+)", "Репутація: %1" },
    { "^Requires (.+) Level (%d+)$", "Потребує %1 рівень %2" },
    { "^Requires Level (%d+)$", "Потребує рівень %1" },
    { "^Requires (.+) to summon$", "Потребує %1 для виклику" },
    { "^Requires (.+) to open$", "Потребує %1 для відкриття" },
    { "^Requires (.+) to equip$", "Потребує %1 для спорядження" },
    { "^Requires (.+) to craft$", "Потребує %1 для крафту" },
    { "^Requires (.+) to learn$", "Потребує %1 для вивчення" },
    { "^Requires (.+) level (%d+)$", "Потребує %1 рівень %2" },
    { "^Requires (.+) %((%d+)%)$", "Потребує %1 (%2)" },
    { "^Requires (.+) %((%d+)/(%d+)%)$", "Потребує %1 (%2/%3)" },
    { "^Requires (.+) Rank (%d+)$", "Потребує %1 Ранг %2" },
    { "^Requires (.+) specialization$", "Потребує спеціалізацію %1" },
    { "^Requires (.+) and (.+)$", "Потребує %1 та %2" },
    { "^Requires (.+), (.+), and (.+)$", "Потребує %1, %2 та %3" },
    { "^Class: (.+)$", "Клас: %1" },
    { "^Race: (.+)$", "Раса: %1" },
    { "^Faction: (.+)$", "Фракція: %1" },
    { "^Quality: (.+)$", "Якість: %1" },
    { "^Item Level: (%d+)$", "Рівень предмета: %1" },
    { "^Item Level (%d+)$", "Рівень предмета %1" },
    { "^Upgrade Level: (%d+)/(%d+)$", "Рівень покращення: %1/%2" },
    { "^Upgrade Level: (%d+)$", "Рівень покращення: %1" },
    { "^Duration: (.+)$", "Тривалість: %1" },
    { "^Time Remaining: (.+)$", "Залишилось часу: %1" },
    { "^Expires: (.+)$", "Минає: %1" },
    { "^Disenchants into: (.+)$", "Розчаровується на: %1" },
    { "^Sell Price: (.+)$", "Ціна продажу: %1" },
    { "^Sells for: (.+)$", "Продається за: %1" },
    { "^Deposit: (.+)$", "Завдаток: %1" },
    { "^Buyout: (.+)$", "Викуп: %1" },
    { "^Minimum Bid: (.+)$", "Мінімальна ставка: %1" },
    { "^Current Bid: (.+)$", "Поточна ставка: %1" },
    { "^Buyout Price: (.+)$", "Ціна викупу: %1" },
    { "^Stack of (%d+)$", "Стос з %1" },
    { "^Stacks to (%d+)$", "Складується до %1" },
    { "^Charges: (.+)$", "Заряди: %1" },
    { "^Remaining charges: (.+)$", "Залишилось зарядів: %1" },
    { "^Set: (.+) %((%d+)/(%d+)%)$", "Набір: %1 (%2/%3)" },
    { "^Set: (.+)$", "Набір: %1" },
    { "^Item Set: (.+)$", "Набір предметів: %1" },
    { "^You must reach level (%d+) to use this$", "Ви маєте досягти рівня %1, щоб це використати" },
    { "^You must be level (%d+)$", "Ви маєте бути рівня %1" },
    { "^You have reached level (%d+)$", "Ви досягли рівня %1" },
    { "^You have (%d+) new mail$", "У вас %1 нових листів" },
    { "^Repair cost: (.+)$", "Вартість ремонту: %1" },
    { "^Reputation with (.+) increased by (%d+)$", "Репутація з %1 збільшилася на %2" },
    { "^You are now Exalted with (.+)$", "Тепер ви шануєтесь у %1" },
    { "^You are now Revered with (.+)$", "Тепер ви шановані у %1" },
    { "^You are now Honored with (.+)$", "Тепер вас поважають у %1" },
    { "^You are now Friendly with (.+)$", "Тепер ви дружні з %1" },
    { "^You loot (.+)$", "Ви підібрали %1" },
    { "^You receive loot: (.+)$", "Ви отримали здобич: %1" },
    { "^You create: (.+)$", "Ви створили: %1" },
    { "^Item created: (.+)$", "Предмет створено: %1" },
    { "^You receive item: (.+)$", "Ви отримали предмет: %1" },
    { "^You received item: (.+)$", "Ви отримали предмет: %1" },
    { "^You won: (.+)$", "Ви виграли: %1" },
    { "^You have learned a new spell: (.+)$", "Ви вивчили нове закляття: %1" },
    { "^You have learned a new ability: (.+)$", "Ви вивчили нову здібність: %1" },
    { "^You have unlearned: (.+)$", "Ви забули: %1" },
    { "^Achievement earned: (.+)$", "Досягнення здобуто: %1" },
    { "^Achievement progress: (.+)$", "Прогрес досягнення: %1" },
    { "^Guild achievement earned: (.+)$", "Гільдійське досягнення здобуто: %1" },
    { "^Criteria: (.+)$", "Критерій: %1" },
    { "^Trade skill increased: (.+)$", "Навичка ремесла зросла: %1" },
    { "^Your skill in (.+) has increased to (%d+)$", "Ваша навичка %1 зросла до %2" },
    { "^Your (.+) skill has increased to (%d+)$", "Ваша навичка %1 зросла до %2" },
    { "^Recipe learned: (.+)$", "Рецепт вивчено: %1" },
    { "^Appearance collected: (.+)$", "Зовнішність зібрано: %1" },
    { "^Mount collected: (.+)$", "Скакун зібрано: %1" },
    { "^Pet collected: (.+)$", "Улюбленець зібрано: %1" },
    { "^Toy collected: (.+)$", "Іграшка зібрана: %1" },
    { "^Heirloom collected: (.+)$", "Спадщина зібрана: %1" },
    { "^Currency gained: (.+)$", "Валюту отримано: %1" },
    { "^Currency spent: (.+)$", "Валюту витрачено: %1" },
    { "^Artifact power gained: (.+)$", "Силу артефакту отримано: %1" },
    { "^Azerite power gained: (.+)$", "Силу азериту отримано: %1" },
    { "^Anima gained: (.+)$", "Аніму отримано: %1" },
    { "^Flight path discovered: (.+)$", "Маршрут польоту відкрито: %1" },
    { "^Area discovered: (.+)$", "Локацію відкрито: %1" },
    { "^Waypoint learned: (.+)$", "Шляховий пункт вивчено: %1" },
    { "^Level (%d+)$", "Рівень %1" },
    { "^Level (%d+) (.+)$", "Рівень %1 %2" },
    { "^(%d+) yds?%.?$", "%1 м" },
    { "^(%d+) yds? range$", "%1 м дальність" },
    { "within (%d+) yds?", "в радіусі %1 м" },
    { "up to (%d+) yds?", "до %1 м" },
    { "(%d+) yds? radius", "%1 м радіус" },
    { "(%d+) yds? range", "%1 м дальність" },
    { "^(.+) slain$", "%1 вбито" },
    { "^(%d+/%d+) (.+) slain$", "%1/%2 %3 вбито" },
    { "^(.+) slain outside (.+)$", "%1 вбито поза %2" },
    { "^(.+) slain in the (.+)$", "%1 вбито у %2" },
    { "^(.+) slain in (.+)$", "%1 вбито у %2" },
    { "^(.+) slain at (.+)$", "%1 вбито біля %2" },
    { "^(.+) slain near (.+)$", "%1 вбито біля %2" },
    { "^Spend (%d+) more points? to unlock$", "Витратьте ще %1 очок, щоб розблокувати" },
    { "^Spend (%d+) more points? to unlock this talent$", "Витратьте ще %1 очок, щоб розблокувати цей талант" },
    { "^Spend (%d+) more points? to unlock (.+)$", "Витратьте ще %1 очок, щоб розблокувати %2" },
    { "^Requires (%d+) points? in (.+)$", "Потребує %1 очок у %2" },
    { "^Rank (%d+)/(%d+)$", "Ранг %1/%2" },
    { "^Rank (%d+)$", "Ранг %1" },
    { "^Talent (%d+)/(%d+)$", "Талант %1/%2" },
    { "^Next rank: (.+)$", "Наступний ранг: %1" },
    { "^Currently: (.+)$", "Зараз: %1" },
    { "^Click to learn$", "Натисніть, щоб вивчити" },
    { "^Click to unlearn$", "Натисніть, щоб забути" },
    { "^Already known$", "Вже вивчено" },
    { "^Already known%.$", "Вже вивчено." },
    { "^Reduces? the mana cost of (.+) by (%d+)%%$", "Зменшує витрату мани на %1 на %2%%" },
    { "^Increases? the damage of (.+) by (%d+)%%$", "Збільшує шкоду від %1 на %2%%" },
    { "^Increases? the healing of (.+) by (%d+)%%$", "Збільшує зцілення від %1 на %2%%" },
    { "^Increases? the duration of (.+) by (%d+)%%$", "Збільшує тривалість %1 на %2%%" },
    { "^Increases? the range of (.+) by (%d+)%%$", "Збільшує дальність %1 на %2%%" },
    { "^Experience: ([%d,]+)$", "Досвід: %1" },
    { "^Experience: ([%d,]+) ", "Досвід: %1 " },
    { "^Experience (%d+)$", "Досвід %1" },
}

local suffix_rules = {
    [" Elite"] = " Елітний",
    [" Rare"] = " Рідкісний",
    [" Quest"] = " Завдання",
    [" Buff"] = " Баф",
    [" Debuff"] = " Дебаф",
}

local quote_pairs = {
    { '"', '"' },
    { "'", "'" },
}

local creature_types = {
    ["Beast"] = "Звір",
    ["Humanoid"] = "Гуманоїд",
    ["Undead"] = "Нежить",
    ["Mechanical"] = "Механізм",
    ["Elemental"] = "Стихійник",
    ["Dragonkin"] = "Дракон",
    ["Demon"] = "Демон",
    ["Aberration"] = "Аберрація",
    ["Giant"] = "Велетень",
    ["Critter"] = "Тваринка",
    ["Not specified"] = "Не визначено",
}

local creature_names = {
    ["Cat"] = "Кіт",
    ["Dog"] = "Собака",
    ["Wolf"] = "Вовк",
    ["Bear"] = "Ведмідь",
    ["Boar"] = "Кабан",
    ["Raptor"] = "Раптор",
    ["Ravager"] = "Спустошувач",
    ["Spider"] = "Павук",
    ["Serpent"] = "Змій",
    ["Turtle"] = "Черепаха",
    ["Crab"] = "Краб",
    ["Bird"] = "Птах",
    ["Owl"] = "Сова",
    ["Bat"] = "Кажан",
    ["Horse"] = "Кінь",
    ["Ram"] = "Баран",
    ["Goat"] = "Коза",
    ["Fox"] = "Лисиця",
    ["Rabbit"] = "Кріль",
    ["Moth"] = "Міль",
    ["Wasp"] = "Оса",
    ["Silkworm"] = "Шовкопряд",
    ["Dragonhawk"] = "Драконячий яструб",
    ["Nether Ray"] = "Пустотний промінь",
    ["Sporebat"] = "Споровий кажан",
    ["Tallstrider"] = "Високоступ",
    ["Warp Stalker"] = "Викривлений переслідувач",
    ["Sporling"] = "Споролінг",
    ["Mushroom"] = "Гриб",
    ["Stag"] = "Олень",
    [" Doe"] = " Долинна олених",
    ["Hound"] = "Гончак",
    ["Worg"] = "Ворг",
    ["Courser"] = "Бігун",
    ["Captain Garrick"] = "Капітан Гаррік",
    ["Private Garrick"] = "Рядовий Гаррік",
    ["Ambassador Fastrasz"] = "Посол Фастрас",
    ["Commander Lethanak"] = "Командор Летанак",
    ["Wingrest Embassy"] = "Посольство Крилоспокою",
    ["Sendrax"] = "Сендракс",
    ["Exile's Reach"] = "Острів Вигнанців",
    ["Give Peace a Chance"] = "Дайте миру шанс",
    ["Stormwind"] = "Штормград",
    ["Orgrimmar"] = "Оргріммар",
    ["Ironforge"] = "Сталегорн",
    ["Darnassus"] = "Дарнас",
    ["Thunder Bluff"] = "Громове Урочище",
    ["Undercity"] = "Підмістя",
    ["Silvermoon"] = "Срібномісяць",
    ["Exodar"] = "Екзодар",
    ["Shattrath"] = "Шаттрат",
    ["Dalaran"] = "Даларан",
    ["Suramar"] = "Сурамар",
    ["Boralus"] = "Боралус",
    ["Zuldazar"] = "Зулдазар",
    ["Nazjatar"] = "Назжатар",
    ["Oribos"] = "Орібос",
    ["Valdrakken"] = "Валдраккен",
    ["Shale Beast"] = "Сланцева істота",
    ["Basilisk"] = "Василіск",
    ["Hippogryph"] = "Гіпогриф",
    ["Gryphon"] = "Грифон",
    ["Wyvern"] = "Виверна",
    ["Pterrordax"] = "Птерордакс",
    ["Frostwyrm"] = "Крижаний черв",
    ["Dragon"] = "Дракон",
    ["Whelp"] = "Велетенський змій",
    ["Proto-Drake"] = "Протодракон",
    ["Devilsaur"] = "Дияволозавр",
    ["Silithid"] = "Силітід",
    ["Qiraji"] = "Кіражі",
    ["Scorpid"] = "Скорпід",
    ["Crocolisk"] = "Кроколіск",
    ["Gorilla"] = "Горила",
    ["Monkey"] = "Мавпа",
    ["Lizard"] = "Ящірка",
    ["Toad"] = "Ропуха",
    ["Frog"] = "Жаба",
    ["Mastiff"] = "Мастиф",
    ["Carrion Bird"] = "Падальник",
    ["Tallstrider"] = "Дрободін",
    ["Water Strider"] = "Водяний блукач",
    ["Beetle"] = "Жук",
    ["Scorpion"] = "Скорпіон",
    ["Worm"] = "Хробак",
    ["Sloth"] = "Лінивець",
    ["Mammoth"] = "Мамонт",
    ["Pig"] = "Свиня",
    ["Sheep"] = "Вівця",
    ["Chicken"] = "Курка",
    ["Cow"] = "Корова",
    ["Rat"] = "Щур",
    ["Mouse"] = "Миша",
    ["Deer"] = "Олень",
    ["Elk"] = "Лось",
    ["Caribou"] = "Карибу",
}

local TITLE_INFLECTIONS = {
    ["Капітан"] = { ins = "Капітаном", gen = "Капітана", dat = "Капітану", loc = "Капітанові", acc = "Капітана" },
    ["Рядовий"] = { ins = "Рядовим", gen = "Рядового", dat = "Рядовому", loc = "Рядовому", acc = "Рядового" },
    ["Посол"] = { ins = "Послом", gen = "Посла", dat = "Послу", loc = "Послові", acc = "Посла" },
    ["Амбасадор"] = { ins = "Амбасадором", gen = "Амбасадора", dat = "Амбасадору", loc = "Амбасадорові", acc = "Амбасадора" },
    ["Командор"] = { ins = "Командором", gen = "Командора", dat = "Командору", loc = "Командору", acc = "Командора" },
    ["Лорд"] = { ins = "Лордом", gen = "Лорда", dat = "Лорду", loc = "Лорду", acc = "Лорда" },
    ["Леді"] = { ins = "Леді", gen = "Леді", dat = "Леді", loc = "Леді", acc = "Леді" },
    ["Сер"] = { ins = "Сером", gen = "Сера", dat = "Серу", loc = "Серу", acc = "Сера" },
    ["Магістер"] = { ins = "Магістром", gen = "Магістра", dat = "Магістру", loc = "Магістрові", acc = "Магістра" },
    ["Архімаг"] = { ins = "Архімагом", gen = "Архімага", dat = "Архімагу", loc = "Архімагу", acc = "Архімага" },
    ["Верховний маг"] = { ins = "Верховним магом", gen = "Верховного мага", dat = "Верховному магу", loc = "Верховному магу", acc = "Верховного мага" },
    ["Генерал"] = { ins = "Генералом", gen = "Генерала", dat = "Генералу", loc = "Генералу", acc = "Генерала" },
    ["Адмірал"] = { ins = "Адміралом", gen = "Адмірала", dat = "Адміралу", loc = "Адміралу", acc = "Адмірала" },
    ["Король"] = { ins = "Королем", gen = "Короля", dat = "Королю", loc = "Королю", acc = "Короля" },
    ["Королівна"] = { ins = "Королівною", gen = "Королівни", dat = "Королівні", loc = "Королівні", acc = "Королівну" },
    ["Принц"] = { ins = "Принцом", gen = "Принца", dat = "Принцу", loc = "Принцю", acc = "Принца" },
    ["Принцеса"] = { ins = "Принцесою", gen = "Принцеси", dat = "Принцесі", loc = "Принцесі", acc = "Принцесу" },
    ["Барон"] = { ins = "Бароном", gen = "Барона", dat = "Барону", loc = "Барону", acc = "Барона" },
    ["Баронеса"] = { ins = "Баронесою", gen = "Баронеси", dat = "Баронесі", loc = "Баронесі", acc = "Баронесу" },
    ["Граф"] = { ins = "Графом", gen = "Графа", dat = "Графу", loc = "Графу", acc = "Графа" },
    ["Графиня"] = { ins = "Графинею", gen = "Графіні", dat = "Графіні", loc = "Графіні", acc = "Графиню" },
    ["Лицар"] = { ins = "Лицарем", gen = "Лицаря", dat = "Лицарю", loc = "Лицарю", acc = "Лицаря" },
    ["Страж"] = { ins = "Стражем", gen = "Стража", dat = "Стражу", loc = "Стражу", acc = "Стража" },
    ["Вартовий"] = { ins = "Вартовим", gen = "Вартового", dat = "Вартовому", loc = "Вартовому", acc = "Вартового" },
    ["Вартова"] = { ins = "Вартовою", gen = "Вартової", dat = "Вартовій", loc = "Вартовій", acc = "Вартову" },
    ["Наглядач"] = { ins = "Наглядачем", gen = "Наглядача", dat = "Наглядачу", loc = "Наглядачу", acc = "Наглядача" },
    ["Командир"] = { ins = "Командиром", gen = "Командира", dat = "Командиру", loc = "Командиру", acc = "Командира" },
    ["Сержант"] = { ins = "Сержантом", gen = "Сержанта", dat = "Сержанту", loc = "Сержанту", acc = "Сержанта" },
    ["Майор"] = { ins = "Майором", gen = "Майора", dat = "Майору", loc = "Майору", acc = "Майора" },
    ["Капрал"] = { ins = "Капралом", gen = "Капрала", dat = "Капралу", loc = "Капралу", acc = "Капрала" },
    ["Лейтенант"] = { ins = "Лейтенантом", gen = "Лейтенанта", dat = "Лейтенанту", loc = "Лейтенанту", acc = "Лейтенанта" },
    ["Охоронець"] = { ins = "Охоронцем", gen = "Охоронця", dat = "Охоронцю", loc = "Охоронцю", acc = "Охоронця" },
    ["Охорона"] = { ins = "Охороною", gen = "Охорони", dat = "Охороні", loc = "Охороні", acc = "Охорону" },
    ["Майстер"] = { ins = "Майстром", gen = "Майстра", dat = "Майстру", loc = "Майстру", acc = "Майстра" },
    ["Головний майстер"] = { ins = "Головним майстром", gen = "Головного майстра", dat = "Головному майстру", loc = "Головному майстру", acc = "Головного майстра" },
    ["Старійшина"] = { ins = "Старійшиною", gen = "Старійшини", dat = "Старійшині", loc = "Старійшині", acc = "Старійшину" },
    ["Шаман"] = { ins = "Шаманом", gen = "Шамана", dat = "Шаману", loc = "Шаману", acc = "Шамана" },
    ["Жриця"] = { ins = "Жрицею", gen = "Жриці", dat = "Жриці", loc = "Жриці", acc = "Жрицю" },
    ["Друїд"] = { ins = "Друїдом", gen = "Друїда", dat = "Друїду", loc = "Друїду", acc = "Друїда" },
    ["Паладин"] = { ins = "Паладином", gen = "Паладина", dat = "Паладину", loc = "Паладину", acc = "Паладина" },
    ["Чорнокнижник"] = { ins = "Чорнокнижником", gen = "Чорнокнижника", dat = "Чорнокнижнику", loc = "Чорнокнижнику", acc = "Чорнокнижника" },
    ["Маг"] = { ins = "Магом", gen = "Мага", dat = "Магу", loc = "Магу", acc = "Мага" },
    ["Розбійник"] = { ins = "Розбійником", gen = "Розбійника", dat = "Розбійнику", loc = "Розбійнику", acc = "Розбійника" },
    ["Мисливець"] = { ins = "Мисливцем", gen = "Мисливця", dat = "Мисливцю", loc = "Мисливцю", acc = "Мисливця" },
    ["Воїн"] = { ins = "Воїном", gen = "Воїна", dat = "Воїну", loc = "Воїну", acc = "Воїна" },
    ["Жрець"] = { ins = "Жрецем", gen = "Жреця", dat = "Жрецю", loc = "Жрецю", acc = "Жреця" },
    ["Чернець"] = { ins = "Чернецем", gen = "Черця", dat = "Черцю", loc = "Черцю", acc = "Черця" },
    ["Рицар смерті"] = { ins = "Рицарем смерті", gen = "Рицаря смерті", dat = "Рицарю смерті", loc = "Рицарю смерті", acc = "Рицаря смерті" },
    ["Демонолог"] = { ins = "Демонологом", gen = "Демонолога", dat = "Демонологу", loc = "Демонологу", acc = "Демонолога" },
    ["Коваль"] = { ins = "Ковалем", gen = "Коваля", dat = "Ковалю", loc = "Ковалю", acc = "Коваля" },
    ["Зброяр"] = { ins = "Зброярем", gen = "Зброяра", dat = "Зброярю", loc = "Зброярю", acc = "Зброяра" },
    ["Ювелір"] = { ins = "Ювеліром", gen = "Ювеліра", dat = "Ювеліру", loc = "Ювеліру", acc = "Ювеліра" },
    ["Інженер"] = { ins = "Інженером", gen = "Інженера", dat = "Інженеру", loc = "Інженеру", acc = "Інженера" },
    ["Цілитель"] = { ins = "Цілителем", gen = "Цілителя", dat = "Цілителю", loc = "Цілителю", acc = "Цілителя" },
    ["Тренер"] = { ins = "Тренером", gen = "Тренера", dat = "Тренеру", loc = "Тренеру", acc = "Тренера" },
    ["Торговець"] = { ins = "Торговцем", gen = "Торговця", dat = "Торговцю", loc = "Торговцю", acc = "Торговця" },
    ["Купець"] = { ins = "Купцем", gen = "Купця", dat = "Купцю", loc = "Купцю", acc = "Купця" },
    ["Постачальник"] = { ins = "Постачальником", gen = "Постачальника", dat = "Постачальнику", loc = "Постачальнику", acc = "Постачальника" },
    ["Користувач"] = { ins = "Користувачем", gen = "Користувача", dat = "Користувачу", loc = "Користувачу", acc = "Користувача" },
    ["Водій"] = { ins = "Водієм", gen = "Водія", dat = "Водію", loc = "Водію", acc = "Водія" },
    ["Пілот"] = { ins = "Пілотом", gen = "Пілота", dat = "Пілоту", loc = "Пілоту", acc = "Пілота" },
    ["Капітан"] = { ins = "Капітаном", gen = "Капітана", dat = "Капітану", loc = "Капітанові", acc = "Капітана" },
    ["Брат"] = { ins = "Братом", gen = "Брата", dat = "Брату", loc = "Брату", acc = "Брата" },
    ["Сестра"] = { ins = "Сестрою", gen = "Сестри", dat = "Сестрі", loc = "Сестрі", acc = "Сестру" },
    ["Матір"] = { ins = "Матір'ю", gen = "Матері", dat = "Матері", loc = "Матері", acc = "Матір" },
    ["Батько"] = { ins = "Батьком", gen = "Батька", dat = "Батьку", loc = "Батьку", acc = "Батька" },
    ["Син"] = { ins = "Сином", gen = "Сина", dat = "Сину", loc = "Сину", acc = "Сина" },
    ["Донька"] = { ins = "Донькою", gen = "Доньки", dat = "Доньці", loc = "Доньці", acc = "Доньку" },
    ["Дід"] = { ins = "Дідом", gen = "Діда", dat = "Діду", loc = "Діду", acc = "Діда" },
    ["Бабуся"] = { ins = "Бабусею", gen = "Бабусі", dat = "Бабусі", loc = "Бабусі", acc = "Бабусю" },
    ["Друг"] = { ins = "Другом", gen = "Друга", dat = "Другу", loc = "Другу", acc = "Друга" },
    ["Ворог"] = { ins = "Ворогом", gen = "Ворога", dat = "Ворогу", loc = "Ворогу", acc = "Ворога" },
    ["Вчитель"] = { ins = "Вчителем", gen = "Вчителя", dat = "Вчителю", loc = "Вчителю", acc = "Вчителя" },
    ["Учень"] = { ins = "Унем", gen = "Уня", dat = "Уню", loc = "Уню", acc = "Уня" },
    ["Наставник"] = { ins = "Наставником", gen = "Наставника", dat = "Наставнику", loc = "Наставнику", acc = "Наставника" },
    ["Агент"] = { ins = "Агентом", gen = "Агента", dat = "Агенту", loc = "Агенту", acc = "Агента" },
    ["Шпигун"] = { ins = "Шпигуном", gen = "Шпигуна", dat = "Шпигуну", loc = "Шпигуну", acc = "Шпигуна" },
    ["Асасин"] = { ins = "Асасином", gen = "Асасина", dat = "Асасину", loc = "Асасину", acc = "Асасина" },
    ["Найманий вбивця"] = { ins = "Найманим вбивцею", gen = "Найманого вбивці", dat = "Найманому вбивці", loc = "Найманому вбивці", acc = "Найманого вбивцю" },
    ["Пірат"] = { ins = "Піратом", gen = "Пірата", dat = "Пірату", loc = "Пірату", acc = "Пірата" },
    ["Контрабандист"] = { ins = "Контрабандистом", gen = "Контрабандиста", dat = "Контрабандисту", loc = "Контрабандисту", acc = "Контрабандиста" },
    ["Рабовласник"] = { ins = "Рабовласником", gen = "Рабовласника", dat = "Рабовласнику", loc = "Рабовласнику", acc = "Рабовласника" },
    ["Раб"] = { ins = "Рабом", gen = "Раба", dat = "Рабу", loc = "Рабу", acc = "Раба" },
    ["В'язень"] = { ins = "В'язнем", gen = "В'язня", dat = "В'язню", loc = "В'язню", acc = "В'язня" },
    ["Біженець"] = { ins = "Біженцем", gen = "Біженця", dat = "Біженцю", loc = "Біженцю", acc = "Біженця" },
    ["Післядослідник"] = { ins = "Дослідником", gen = "Дослідника", dat = "Досліднику", loc = "Досліднику", acc = "Дослідника" },
    ["Дослідник"] = { ins = "Дослідником", gen = "Дослідника", dat = "Досліднику", loc = "Досліднику", acc = "Дослідника" },
    ["Авантюрист"] = { ins = "Авантюристом", gen = "Авантюриста", dat = "Авантюристу", loc = "Авантюристу", acc = "Авантюриста" },
    ["Шукач пригод"] = { ins = "Шукачем пригод", gen = "Шукача пригод", dat = "Шукачу пригод", loc = "Шукачу пригод", acc = "Шукача пригод" },
    ["Чаклун"] = { ins = "Чаклуном", gen = "Чаклуна", dat = "Чаклуну", loc = "Чаклуну", acc = "Чаклуна" },
    ["Відьма"] = { ins = "Відьмою", gen = "Відьми", dat = "Відьмі", loc = "Відьмі", acc = "Відьму" },
    ["Некромант"] = { ins = "Некромантом", gen = "Некроманта", dat = "Некроманту", loc = "Некроманту", acc = "Некроманта" },
    ["Пророк"] = { ins = "Пророком", gen = "Пророка", dat = "Пророку", loc = "Пророку", acc = "Пророка" },
    ["Жерць"] = { ins = "Жерцем", gen = "Жерця", dat = "Жерцю", loc = "Жерцю", acc = "Жерця" },
    ["Оракул"] = { ins = "Оракулом", gen = "Оракула", dat = "Оракулу", loc = "Оракулу", acc = "Оракула" },
    ["Аптекар"] = { ins = "Аптекарем", gen = "Аптекаря", dat = "Аптекарю", loc = "Аптекарю", acc = "Аптекаря" },
    ["Алхімік"] = { ins = "Алхіміком", gen = "Алхіміка", dat = "Алхіміку", loc = "Алхіміку", acc = "Алхіміка" },
    ["Зачарувальник"] = { ins = "Зачарувальником", gen = "Зачарувальника", dat = "Зачарувальнику", loc = "Зачарувальнику", acc = "Зачарувальника" },
    ["Кравець"] = { ins = "Кравцем", gen = "Кравця", dat = "Кравцю", loc = "Кравцю", acc = "Кравця" },
    ["Швець"] = { ins = "Швецем", gen = "Швеця", dat = "Швецю", loc = "Швецю", acc = "Швеця" },
    ["Кухар"] = { ins = "Кухарем", gen = "Кухаря", dat = "Кухарю", loc = "Кухарю", acc = "Кухаря" },
    ["Рибалка"] = { ins = "Рибалкою", gen = "Рибалки", dat = "Рибалці", loc = "Рибалці", acc = "Рибалку" },
    ["Рибалко"] = { ins = "Рибалком", gen = "Рибалка", dat = "Рибалку", loc = "Рибалку", acc = "Рибалка" },
    ["Гірник"] = { ins = "Гірником", gen = "Гірника", dat = "Гірнику", loc = "Гірнику", acc = "Гірника" },
    ["Шкіряник"] = { ins = "Шкіряником", gen = "Шкіряника", dat = "Шкірянику", loc = "Шкірянику", acc = "Шкіряника" },
    ["Скорняк"] = { ins = "Скорняком", gen = "Скорняка", dat = "Скорняку", loc = "Скорняку", acc = "Скорняка" },
    ["Травник"] = { ins = "Травником", gen = "Травника", dat = "Травнику", loc = "Травнику", acc = "Травника" },
    ["Лісоруб"] = { ins = "Лісорубом", gen = "Лісоруба", dat = "Лісорубу", loc = "Лісорубу", acc = "Лісоруба" },
    ["Фермер"] = { ins = "Фермером", gen = "Фермера", dat = "Фермеру", loc = "Фермеру", acc = "Фермера" },
    ["Пастух"] = { ins = "Пастухом", gen = "Пастуха", dat = "Пастуху", loc = "Пастуху", acc = "Пастуха" },
    ["Стрелець"] = { ins = "Стрільцем", gen = "Стрільця", dat = "Стрільцю", loc = "Стрільцю", acc = "Стрільця" },
    ["Лучник"] = { ins = "Лучником", gen = "Лучника", dat = "Лучнику", loc = "Лучнику", acc = "Лучника" },
    ["Арбалетник"] = { ins = "Арбалетником", gen = "Арбалетника", dat = "Арбалетнику", loc = "Арбалетнику", acc = "Арбалетника" },
    ["Облоговий інженер"] = { ins = "Облоговим інженером", gen = "Облогового інженера", dat = "Облоговому інженеру", loc = "Облоговому інженеру", acc = "Облогового інженера" },
    ["Дипломат"] = { ins = "Дипломатом", gen = "Дипломата", dat = "Дипломату", loc = "Дипломату", acc = "Дипломата" },
    ["Посланник"] = { ins = "Посланником", gen = "Посланника", dat = "Посланнику", loc = "Посланнику", acc = "Посланника" },
    ["Гонець"] = { ins = "Гонцем", gen = "Гонця", dat = "Гонцю", loc = "Гонцю", acc = "Гонця" },
    ["Розвідник"] = { ins = "Розвідником", gen = "Розвідника", dat = "Розвіднику", loc = "Розвіднику", acc = "Розвідника" },
    ["Шпигунка"] = { ins = "Шпигункою", gen = "Шпигунки", dat = "Шпигунці", loc = "Шпигунці", acc = "Шпигунку" },
    ["Кат"] = { ins = "Катом", gen = "Ката", dat = "Кату", loc = "Кату", acc = "Ката" },
    ["Суддя"] = { ins = "Суддею", gen = "Судді", dat = "Судді", loc = "Судді", acc = "Суддю" },
    ["Законник"] = { ins = "Законником", gen = "Законника", dat = "Законнику", loc = "Законнику", acc = "Законника" },
    ["Стражник"] = { ins = "Стражником", gen = "Стражника", dat = "Стражнику", loc = "Стражнику", acc = "Стражника" },
    ["Патрульний"] = { ins = "Патрульним", gen = "Патрульного", dat = "Патрульному", loc = "Патрульному", acc = "Патрульного" },
    ["Слідопит"] = { ins = "Слідопитом", gen = "Слідопита", dat = "Слідопиту", loc = "Слідопиту", acc = "Слідопита" },
    ["Мисливець за головами"] = { ins = "Мисливцем за головами", gen = "Мисливця за головами", dat = "Мисливцю за головами", loc = "Мисливцю за головами", acc = "Мисливця за головами" },
    ["Загін"] = { ins = "Загоном", gen = "Загону", dat = "Загону", loc = "Загону", acc = "Загін" },
    ["Представник"] = { ins = "Представником", gen = "Представника", dat = "Представнику", loc = "Представнику", acc = "Представника" },
    ["Заступник"] = { ins = "Заступником", gen = "Заступника", dat = "Заступнику", loc = "Заступнику", acc = "Заступника" },
    ["Володар"] = { ins = "Володарем", gen = "Володаря", dat = "Володарю", loc = "Володарю", acc = "Володаря" },
    ["Владика"] = { ins = "Владикою", gen = "Владики", dat = "Владиці", loc = "Владиці", acc = "Владику" },
    ["Правитель"] = { ins = "Правителем", gen = "Правителя", dat = "Правителю", loc = "Правителю", acc = "Правителя" },
    ["Зверхній"] = { ins = "Зверхнім", gen = "Зверхнього", dat = "Зверхньому", loc = "Зверхньому", acc = "Зверхнього" },
    ["Зверхня"] = { ins = "Зверхнею", gen = "Зверхньої", dat = "Зверхній", loc = "Зверхній", acc = "Зверхню" },
    ["Староста"] = { ins = "Старостою", gen = "Старости", dat = "Старості", loc = "Старості", acc = "Старосту" },
    ["Отаман"] = { ins = "Отаманом", gen = "Отамана", dat = "Отаману", loc = "Отаману", acc = "Отамана" },
    ["Вождь"] = { ins = "Вождем", gen = "Вождя", dat = "Вождю", loc = "Вождю", acc = "Вождя" },
    ["Шаманка"] = { ins = "Шаманкою", gen = "Шаманки", dat = "Шаманці", loc = "Шаманці", acc = "Шаманку" },
    ["Провідник"] = { ins = "Провідником", gen = "Провідника", dat = "Провіднику", loc = "Провіднику", acc = "Провідника" },
    ["Мечник"] = { ins = "Мечником", gen = "Мечника", dat = "Мечнику", loc = "Мечнику", acc = "Мечника" },
    ["Мечниця"] = { ins = "Мечницею", gen = "Мечниці", dat = "Мечниці", loc = "Мечниці", acc = "Мечницю" },
    ["Клинкар"] = { ins = "Клинарем", gen = "Клинаря", dat = "Клинарю", loc = "Клинарю", acc = "Клинаря" },
    ["Вартовий смерті"] = { ins = "Вартовим смерті", gen = "Вартового смерті", dat = "Вартовому смерті", loc = "Вартовому смерті", acc = "Вартового смерті" },
    ["Кривавий ельф"] = { ins = "Кривавим ельфом", gen = "Кривавого ельфа", dat = "Кривавому ельфу", loc = "Кривавому ельфу", acc = "Кривавого ельфа" },
    ["Кривава ельфійка"] = { ins = "Кривавою ельфійкою", gen = "Кривавої ельфійки", dat = "Кривавій ельфійці", loc = "Кривавій ельфійці", acc = "Криваву ельфійку" },
    ["Вищий ельф"] = { ins = "Вищим ельфом", gen = "Вищого ельфа", dat = "Вищому ельфу", loc = "Вищому ельфу", acc = "Вищого ельфа" },
    ["Нічний ельф"] = { ins = "Нічним ельфом", gen = "Нічного ельфа", dat = "Нічному ельфу", loc = "Нічному ельфу", acc = "Нічного ельфа" },
    ["Нічна ельфійка"] = { ins = "Нічною ельфійкою", gen = "Нічної ельфійки", dat = "Нічній ельфійці", loc = "Нічній ельфійці", acc = "Нічну ельфійку" },
    ["Дворф"] = { ins = "Дворфом", gen = "Дворфа", dat = "Дворфу", loc = "Дворфу", acc = "Дворфа" },
    ["Дворфійка"] = { ins = "Дворфійкою", gen = "Дворфійки", dat = "Дворфійці", loc = "Дворфійці", acc = "Дворфійку" },
    ["Гном"] = { ins = "Гномом", gen = "Гнома", dat = "Гному", loc = "Гному", acc = "Гнома" },
    ["Гномка"] = { ins = "Гномкою", gen = "Гномки", dat = "Гномці", loc = "Гномці", acc = "Гномку" },
    ["Орк"] = { ins = "Орком", gen = "Орка", dat = "Орку", loc = "Орку", acc = "Орка" },
    ["Оркиця"] = { ins = "Оркицею", gen = "Оркиці", dat = "Оркиці", loc = "Оркиці", acc = "Оркицю" },
    ["Троль"] = { ins = "Тролем", gen = "Троля", dat = "Тролю", loc = "Тролю", acc = "Троля" },
    ["Тролиха"] = { ins = "Тролихою", gen = "Тролихи", dat = "Тролисі", loc = "Тролисі", acc = "Тролиху" },
    ["Таурен"] = { ins = "Тауреном", gen = "Таурена", dat = "Таурену", loc = "Таурену", acc = "Таурена" },
    ["Гоблін"] = { ins = "Гобліном", gen = "Гобліна", dat = "Гобліну", loc = "Гобліну", acc = "Гобліна" },
    ["Вульпера"] = { ins = "Вульперою", gen = "Вульпери", dat = "Вульпері", loc = "Вульпері", acc = "Вульперу" },
    ["Пандарен"] = { ins = "Пандареном", gen = "Пандарена", dat = "Пандарену", loc = "Пандарену", acc = "Пандарена" },
    ["Дреней"] = { ins = "Дренеєм", gen = "Дренея", dat = "Дренею", loc = "Дренею", acc = "Дренея" },
    ["Дренейка"] = { ins = "Дренейкою", gen = "Дренейки", dat = "Дренейці", loc = "Дренейці", acc = "Дренейку" },
    ["Зінчаний"] = { ins = "Зінчаним", gen = "Зінчаного", dat = "Зінчаному", loc = "Зінчаному", acc = "Зінчаного" },
    ["Механогном"] = { ins = "Механогномом", gen = "Механогнома", dat = "Механогному", loc = "Механогному", acc = "Механогнома" },
    ["Ерєдран"] = { ins = "Ерєдраном", gen = "Ерєдрана", dat = "Ерєдрану", loc = "Ерєдрану", acc = "Ерєдрана" },
    ["Дітнотворець"] = { ins = "Дітнотворцем", gen = "Дітнотворця", dat = "Дітнотворцю", loc = "Дітнотворцю", acc = "Дітнотворця" },
    ["Володар небес"] = { ins = "Володарем небес", gen = "Володаря небес", dat = "Володарю небес", loc = "Володарю небес", acc = "Володаря небес" },
    ["Верховний лорд"] = { ins = "Верховним лордом", gen = "Верховного лорда", dat = "Верховному лорду", loc = "Верховному лорду", acc = "Верховного лорда" },
    ["Верховний вождь"] = { ins = "Верховним вождем", gen = "Верховного вождя", dat = "Верховному вождю", loc = "Верховному вождю", acc = "Верховного вождя" },
    ["Верховна жриця"] = { ins = "Верховною жрицею", gen = "Верховної жриці", dat = "Верховній жриці", loc = "Верховній жриці", acc = "Верховну жрицю" },
    ["Верховний командор"] = { ins = "Верховним командором", gen = "Верховного командора", dat = "Верховному командору", loc = "Верховному командору", acc = "Верховного командора" },
    ["Архімаг"] = { ins = "Архімагом", gen = "Архімага", dat = "Архімагу", loc = "Архімагу", acc = "Архімага" },
    ["Архідруїд"] = { ins = "Архідруїдом", gen = "Архідруїда", dat = "Архідруїду", loc = "Архідруїду", acc = "Архідруїда" },
    ["Архієпископ"] = { ins = "Архієпископом", gen = "Архієпископа", dat = "Архієпископу", loc = "Архієпископу", acc = "Архієпископа" },
    ["Архішаман"] = { ins = "Архішаманом", gen = "Архішамана", dat = "Архішаману", loc = "Архішаману", acc = "Архішамана" },
    ["Великий вождь"] = { ins = "Великим вождем", gen = "Великого вождя", dat = "Великому вождю", loc = "Великому вождю", acc = "Великого вождя" },
    ["Гранд адмірал"] = { ins = "Гранд адміралом", gen = "Гранд адмірала", dat = "Гранд адміралу", loc = "Гранд адміралу", acc = "Гранд адмірала" },
    ["Гранд майстер"] = { ins = "Гранд майстром", gen = "Гранд майстра", dat = "Гранд майстру", loc = "Гранд майстру", acc = "Гранд майстра" },
    ["Воєначальник"] = { ins = "Воєначальником", gen = "Воєначальника", dat = "Воєначальнику", loc = "Воєначальнику", acc = "Воєначальника" },
    ["Пан сталі"] = { ins = "Паном сталі", gen = "Пана сталі", dat = "Пану сталі", loc = "Пану сталі", acc = "Пана сталі" },
    ["Підземний лорд"] = { ins = "Підземним лордом", gen = "Підземного лорда", dat = "Підземному лорду", loc = "Підземному лорду", acc = "Підземного лорда" },
    ["Лорд-наставник"] = { ins = "Лордом-наставником", gen = "Лорда-наставника", dat = "Лорду-наставнику", loc = "Лорду-наставнику", acc = "Лорда-наставника" },
    ["Лорд-командор"] = { ins = "Лордом-командором", gen = "Лорда-командора", dat = "Лорду-командору", loc = "Лорду-командору", acc = "Лорда-командора" },
    ["Рига смерті"] = { ins = "Ригою смерті", gen = "Риги смерті", dat = "Ризі смерті", loc = "Ризі смерті", acc = "Ригу смерті" },
    ["Крій лорд"] = { ins = "Крій лордом", gen = "Крій лорда", dat = "Крій лорду", loc = "Крій лорду", acc = "Крій лорда" },
    ["Тіньова жриця"] = { ins = "Тіньовою жрицею", gen = "Тіньової жриці", dat = "Тіньовій жриці", loc = "Тіньовій жриці", acc = "Тіньову жрицю" },
    ["Ветеран"] = { ins = "Ветераном", gen = "Ветерана", dat = "Ветерану", loc = "Ветерану", acc = "Ветерана" },
    ["Маршал"] = { ins = "Маршалом", gen = "Маршала", dat = "Маршалу", loc = "Маршалу", acc = "Маршала" },
    ["Фельдмаршал"] = { ins = "Фельдмаршалом", gen = "Фельдмаршала", dat = "Фельдмаршалу", loc = "Фельдмаршалу", acc = "Фельдмаршала" },
    ["Страж смерти"] = { ins = "Стражем смерті", gen = "Стража смерті", dat = "Стражу смерті", loc = "Стражу смерті", acc = "Стража смерті" },
    ["Рицар Срібної Долі"] = { ins = "Рицарем Срібної Долі", gen = "Рицаря Срібної Долі", dat = "Рицарю Срібної Долі", loc = "Рицарю Срібної Долі", acc = "Рицаря Срібної Долі" },
    ["Вершник Апокаліпсису"] = { ins = "Вершником Апокаліпсису", gen = "Вершника Апокаліпсису", dat = "Вершнику Апокаліпсису", loc = "Вершнику Апокаліпсису", acc = "Вершника Апокаліпсису" },
    ["Чорний лицар"] = { ins = "Чорним лицарем", gen = "Чорного лицаря", dat = "Чорному лицарю", loc = "Чорному лицарю", acc = "Чорного лицаря" },
    ["Первісний лорд"] = { ins = "Первісним лордом", gen = "Первісного лорда", dat = "Первісному лорду", loc = "Первісному лорду", acc = "Первісного лорда" },
    ["Титан-хранитель"] = { ins = "Титаном-хранителем", gen = "Титана-хранителя", dat = "Титану-хранителю", loc = "Титану-хранителю", acc = "Титана-хранителя" },
    ["Хранитель"] = { ins = "Хранителем", gen = "Хранителя", dat = "Хранителю", loc = "Хранителю", acc = "Хранителя" },
    ["Спостерігач"] = { ins = "Спостерігачем", gen = "Спостерігача", dat = "Спостерігачу", loc = "Спостерігачу", acc = "Спостерігача" },
    ["Зберігач"] = { ins = "Зберігачем", gen = "Зберігача", dat = "Зберігачу", loc = "Зберігачу", acc = "Зберігача" },
    ["Вартовий_MAYстер"] = { ins = "Вартовим майстром", gen = "Вартового майстра", dat = "Вартовому майстру", loc = "Вартовому майстру", acc = "Вартового майстра" },
    ["Цирульник"] = { ins = "Цирульником", gen = "Цирульника", dat = "Цирульнику", loc = "Цирульнику", acc = "Цирульника" },
    ["Аукціонатор"] = { ins = "Аукціонатором", gen = "Аукціонатора", dat = "Аукціонатору", loc = "Аукціонатору", acc = "Аукціонатора" },
    ["Банкір"] = { ins = "Банкіром", gen = "Банкіра", dat = "Банкіру", loc = "Банкіру", acc = "Банкіра" },
    ["Духовник"] = { ins = "Духовником", gen = "Духовника", dat = "Духовнику", loc = "Духовнику", acc = "Духовника" },
    ["Проситель"] = { ins = "Просителем", gen = "Просителя", dat = "Просителю", loc = "Просителю", acc = "Просителя" },
    ["Вісник"] = { ins = "Вісником", gen = "Вісника", dat = "Віснику", loc = "Віснику", acc = "Вісника" },
    ["Літописець"] = { ins = "Літописцем", gen = "Літописця", dat = "Літописцю", loc = "Літописцю", acc = "Літописця" },
    ["Чорнокнижник"] = { ins = "Чорнокнижником", gen = "Чорнокнижника", dat = "Чорнокнижнику", loc = "Чорнокнижнику", acc = "Чорнокнижника" },
    ["Ілюзіонер"] = { ins = "Ілюзіонером", gen = "Ілюзіонера", dat = "Ілюзіонеру", loc = "Ілюзіонеру", acc = "Ілюзіонера" },
    ["Некролорд"] = { ins = "Некролордом", gen = "Некролорда", dat = "Некролорду", loc = "Некролорду", acc = "Некролорда" },
    ["Сідігард"] = { ins = "Сідігардом", gen = "Сідігарда", dat = "Сідігарду", loc = "Сідігарду", acc = "Сідігарда" },
    ["Каратель"] = { ins = "Карателем", gen = "Карателя", dat = "Карателю", loc = "Карателю", acc = "Карателя" },
    ["Чаклунка"] = { ins = "Чаклункою", gen = "Чаклунки", dat = "Чаклунці", loc = "Чаклунці", acc = "Чаклунку" },
    ["Відьмак"] = { ins = "Відьмаком", gen = "Відьмака", dat = "Відьмаку", loc = "Відьмаку", acc = "Відьмака" },
    ["Чорний маг"] = { ins = "Чорним магом", gen = "Чорного мага", dat = "Чорному магу", loc = "Чорному магу", acc = "Чорного мага" },
    ["Кривавий принц"] = { ins = "Кривавим принцом", gen = "Кривавого принца", dat = "Кривавому принцу", loc = "Кривавому принцю", acc = "Кривавого принца" },
    ["Кривава принцеса"] = { ins = "Кривавою принцесою", gen = "Кривавої принцеси", dat = "Кривавій принцесі", loc = "Кривавій принцесі", acc = "Криваву принцесу" },
    ["Тіньовий мисливець"] = { ins = "Тіньовим мисливцем", gen = "Тіньового мисливця", dat = "Тіньовому мисливцю", loc = "Тіньовому мисливцю", acc = "Тіньового мисливця" },
    ["Тіньова мисливиця"] = { ins = "Тіньовою мисливицею", gen = "Тіньової мисливиці", dat = "Тіньовій мисливиці", loc = "Тіньовій мисливиці", acc = "Тіньову мисливицю" },
    ["Майстер отрут"] = { ins = "Майстром отрут", gen = "Майстра отрут", dat = "Майстру отрут", loc = "Майстру отрут", acc = "Майстра отрут" },
    ["Майстер зілля"] = { ins = "Майстром зілля", gen = "Майстра зілля", dat = "Майстру зілля", loc = "Майстру зілля", acc = "Майстра зілля" },
    ["Майстер клинків"] = { ins = "Майстром клинків", gen = "Майстра клинків", dat = "Майстру клинків", loc = "Майстру клинків", acc = "Майстра клинків" },
    ["Братство"] = { ins = "Братством", gen = "Братства", dat = "Братству", loc = "Братстві", acc = "Братство" },
    ["Орден"] = { ins = "Орденом", gen = "Ордену", dat = "Ордену", loc = "Ордені", acc = "Орден" },
    ["Ковен"] = { ins = "Ковеном", gen = "Ковена", dat = "Ковену", loc = "Ковені", acc = "Ковен" },
    ["Клан"] = { ins = "Кланом", gen = "Клану", dat = "Клану", loc = "Клані", acc = "Клан" },
    ["Плем'я"] = { ins = "Плем'ям", gen = "Племені", dat = "Племені", loc = "Племені", acc = "Плем'я" },
    ["Дім"] = { ins = "Домом", gen = "Дому", dat = "Дому", loc = "Домі", acc = "Дім" },
    ["Родина"] = { ins = "Родиною", gen = "Родини", dat = "Родині", loc = "Родині", acc = "Родину" },
    ["Легіон"] = { ins = "Легіоном", gen = "Легіону", dat = "Легіону", loc = "Легіоні", acc = "Легіон" },
    ["Армія"] = { ins = "Армією", gen = "Армії", dat = "Армії", loc = "Армії", acc = "Армію" },
    ["Флот"] = { ins = "Флотом", gen = "Флоту", dat = "Флоту", loc = "Флоті", acc = "Флот" },
    ["Гільдія"] = { ins = "Гільдією", gen = "Гільдії", dat = "Гільдії", loc = "Гільдії", acc = "Гільдію" },
    ["Конклав"] = { ins = "Конклавом", gen = "Конклаву", dat = "Конклаву", loc = "Конклаві", acc = "Конклав" },
    ["Синод"] = { ins = "Синодом", gen = "Синоду", dat = "Синоду", loc = "Синоді", acc = "Синод" },
    ["Скарбник"] = { ins = "Скарбником", gen = "Скарбника", dat = "Скарбнику", loc = "Скарбнику", acc = "Скарбника" },
    ["Рахівник"] = { ins = "Рахівником", gen = "Рахівника", dat = "Рахівнику", loc = "Рахівнику", acc = "Рахівника" },
    ["Збирач"] = { ins = "Збирачем", gen = "Збирача", dat = "Збирачу", loc = "Збирачу", acc = "Збирача" },
    ["Руйнівник"] = { ins = "Руйнівником", gen = "Руйнівника", dat = "Руйнівнику", loc = "Руйнівнику", acc = "Руйнівника" },
    ["Визволитель"] = { ins = "Визволителем", gen = "Визволителя", dat = "Визволителю", loc = "Визволителю", acc = "Визволителя" },
    ["Захисник"] = { ins = "Захисником", gen = "Захисника", dat = "Захиснику", loc = "Захиснику", acc = "Захисника" },
    ["Захисниця"] = { ins = "Захисницею", gen = "Захисниці", dat = "Захисниці", loc = "Захисниці", acc = "Захисницю" },
    ["Вершитель"] = { ins = "Вершителем", gen = "Вершителя", dat = "Вершителю", loc = "Вершителю", acc = "Вершителя" },
    ["Виконавець"] = { ins = "Виконавцем", gen = "Виконавця", dat = "Виконавцю", loc = "Виконавцю", acc = "Виконавця" },
    ["Вихователь"] = { ins = "Вихователем", gen = "Вихователя", dat = "Вихователю", loc = "Вихователю", acc = "Вихователя" },
    ["Паламар"] = { ins = "Паламарем", gen = "Паламаря", dat = "Паламарю", loc = "Паламарю", acc = "Паламаря" },
    ["Працівник"] = { ins = "Працівником", gen = "Працівника", dat = "Працівнику", loc = "Працівнику", acc = "Працівника" },
    ["Слуга"] = { ins = "Слугою", gen = "Слуги", dat = "Слузі", loc = "Слузі", acc = "Слугу" },
    ["Керуючий"] = { ins = "Керуючим", gen = "Керуючого", dat = "Керуючому", loc = "Керуючому", acc = "Керуючого" },
    ["Наглядачка"] = { ins = "Наглядачкою", gen = "Наглядачки", dat = "Наглядачці", loc = "Наглядачці", acc = "Наглядачку" },
    ["Місіонер"] = { ins = "Місіонером", gen = "Місіонера", dat = "Місіонеру", loc = "Місіонеру", acc = "Місіонера" },
    ["Проповідник"] = { ins = "Проповідником", gen = "Проповідника", dat = "Проповіднику", loc = "Проповіднику", acc = "Проповідника" },
    ["Віщун"] = { ins = "Віщуном", gen = "Віщуна", dat = "Віщуну", loc = "Віщуну", acc = "Віщуна" },
    ["Ворожка"] = { ins = "Ворожкою", gen = "Ворожки", dat = "Ворожці", loc = "Ворожці", acc = "Ворожку" },
    ["Оракул"] = { ins = "Оракулом", gen = "Оракула", dat = "Оракулу", loc = "Оракулу", acc = "Оракула" },
    ["Месник"] = { ins = "Месником", gen = "Месника", dat = "Меснику", loc = "Меснику", acc = "Месника" },
    ["Мститель"] = { ins = "Мстителем", gen = "Мстителя", dat = "Мстителю", loc = "Мстителю", acc = "Мстителя" },
    ["Мстительниця"] = { ins = "Мстительницею", gen = "Мстительниці", dat = "Мстительниці", loc = "Мстительниці", acc = "Мстительницю" },
    ["Карательниця"] = { ins = "Карательницею", gen = "Карательниці", dat = "Карательниці", loc = "Карательниці", acc = "Карательницю" },
    ["Згубитель"] = { ins = "Згубителем", gen = "Згубителя", dat = "Згубителю", loc = "Згубителю", acc = "Згубителя" },
    ["Порятунок"] = { ins = "Порятунком", gen = "Порятунку", dat = "Порятунку", loc = "Порятунку", acc = "Порятунок" },
    ["Майстер бойових мистецтв"] = { ins = "Майстром бойових мистецтв", gen = "Майстра бойових мистецтв", dat = "Майстру бойових мистецтв", loc = "Майстру бойових мистецтв", acc = "Майстра бойових мистецтв" },
    ["Лікар"] = { ins = "Лікарем", gen = "Лікаря", dat = "Лікарю", loc = "Лікарю", acc = "Лікаря" },
    ["Цілителька"] = { ins = "Цілителькою", gen = "Цілительки", dat = "Цілительці", loc = "Цілительці", acc = "Цілительку" },
    ["Хірург"] = { ins = "Хірургом", gen = "Хірурга", dat = "Хірургу", loc = "Хірургу", acc = "Хірурга" },
    ["Зброєносець"] = { ins = "Зброєносцем", gen = "Зброєносця", dat = "Зброєносцю", loc = "Зброєносцю", acc = "Зброєносця" },
    ["Паж"] = { ins = "Пажем", gen = "Пажа", dat = "Пажу", loc = "Пажу", acc = "Пажа" },
    ["Сквайр"] = { ins = "Сквайром", gen = "Сквайра", dat = "Сквайру", loc = "Сквайру", acc = "Сквайра" },
    ["Засуджений"] = { ins = "Засудженим", gen = "Засудженого", dat = "Засудженому", loc = "Засудженому", acc = "Засудженого" },
    ["Засуджена"] = { ins = "Засудженою", gen = "Засудженої", dat = "Засудженій", loc = "Засудженій", acc = "Засуджену" },
    ["Вигнанець"] = { ins = "Вигнанцем", gen = "Вигнанця", dat = "Вигнанцю", loc = "Вигнанцю", acc = "Вигнанця" },
    ["Вигнаниця"] = { ins = "Вигнаницею", gen = "Вигнаниці", dat = "Вигнаниці", loc = "Вигнаниці", acc = "Вигнаницю" },
    ["Відступник"] = { ins = "Відступником", gen = "Відступника", dat = "Відступнику", loc = "Відступнику", acc = "Відступника" },
    ["Відступниця"] = { ins = "Відступницею", gen = "Відступниці", dat = "Відступниці", loc = "Відступниці", acc = "Відступницю" },
    ["Предател"] = { ins = "Предателем", gen = "Предателя", dat = "Предателю", loc = "Предателю", acc = "Предателя" },
    ["Зрадник"] = { ins = "Зрадником", gen = "Зрадника", dat = "Зраднику", loc = "Зраднику", acc = "Зрадника" },
    ["Зрадниця"] = { ins = "Зрадницею", gen = "Зрадниці", dat = "Зрадниці", loc = "Зрадниці", acc = "Зрадницю" },
    ["Воскреситель"] = { ins = "Воскресителем", gen = "Воскресителя", dat = "Воскресителю", loc = "Воскресителю", acc = "Воскресителя" },
    ["Укротитель"] = { ins = "Укротителем", gen = "Укротителя", dat = "Укротителю", loc = "Укротителю", acc = "Укротителя" },
    ["Зверувальник"] = { ins = "Зверувальником", gen = "Зверувальника", dat = "Зверувальнику", loc = "Зверувальнику", acc = "Зверувальника" },
    ["Приручальник"] = { ins = "Приручальником", gen = "Приручальника", dat = "Приручальнику", loc = "Приручальнику", acc = "Приручальника" },
    ["Аванпост"] = { ins = "Аванпостом", gen = "Аванпоста", dat = "Аванпосту", loc = "Аванпосту", acc = "Аванпост" },
    ["Фортеця"] = { ins = "Фортецею", gen = "Фортеці", dat = "Фортеці", loc = "Фортеці", acc = "Фортецю" },
    ["Вежа"] = { ins = "Вежею", gen = "Вежі", dat = "Вежі", loc = "Вежі", acc = "Вежу" },
    ["Башта"] = { ins = "Баштою", gen = "Башти", dat = "Башті", loc = "Башті", acc = "Башту" },
    ["Храм"] = { ins = "Храмом", gen = "Храму", dat = "Храму", loc = "Храмі", acc = "Храм" },
    ["Санктуарій"] = { ins = "Санктуарієм", gen = "Санктуарію", dat = "Санктуарію", loc = "Санктуарії", acc = "Санктуарій" },
    ["Святиня"] = { ins = "Святиною", gen = "Святині", dat = "Святині", loc = "Святині", acc = "Святиню" },
    ["Посольство"] = { ins = "Посольством", gen = "Посольства", dat = "Посольству", loc = "Посольстві", acc = "Посольство" },
    ["Базилика"] = { ins = "Базиликою", gen = "Базилики", dat = "Базилиці", loc = "Базилиці", acc = "Базилику" },
    ["Собор"] = { ins = "Собором", gen = "Собору", dat = "Собору", loc = "Соборі", acc = "Собор" },
    ["Каплиця"] = { ins = "Каплицею", gen = "Каплиці", dat = "Каплиці", loc = "Каплиці", acc = "Каплицю" },
    ["Міст"] = { ins = "Мостом", gen = "Мосту", dat = "Мосту", loc = "Мості", acc = "Міст" },
    ["Табір"] = { ins = "Табором", gen = "Табору", dat = "Табору", loc = "Таборі", acc = "Табір" },
    ["Дім"] = { ins = "Домом", gen = "Дому", dat = "Дому", loc = "Домі", acc = "Дім" },
    ["Палац"] = { ins = "Палацом", gen = "Палаца", dat = "Палацу", loc = "Палаці", acc = "Палац" },
    ["Замок"] = { ins = "Замком", gen = "Замка", dat = "Замку", loc = "Замку", acc = "Замок" },
    ["Оплот"] = { ins = "Оплотом", gen = "Оплоту", dat = "Оплоту", loc = "Оплоті", acc = "Оплот" },
    ["Причал"] = { ins = "Причалом", gen = "Причала", dat = "Причалу", loc = "Причалі", acc = "Причал" },
    ["Маяк"] = { ins = "Маяком", gen = "Маяка", dat = "Маяку", loc = "Маяку", acc = "Маяк" },
    ["Гавань"] = { ins = "Гаванню", gen = "Гавані", dat = "Гавані", loc = "Гавані", acc = "Гавань" },
    ["Контракт"] = { ins = "Контрактом", gen = "Контракту", dat = "Контракту", loc = "Контракті", acc = "Контракт" },
}

ns.TITLE_INFLECTIONS = TITLE_INFLECTIONS

local function utf8last(s)
    local n = #s
    if n == 0 then return "" end
    local b = s:byte(n)
    if b < 0x80 then return s:sub(n) end
    while n > 1 and s:byte(n) >= 0x80 and s:byte(n) <= 0xBF do
        n = n - 1
    end
    return s:sub(n)
end

local function utf8striplast(s)
    local n = #s
    if n == 0 then return "" end
    local b = s:byte(n)
    if b < 0x80 then return s:sub(1, #s - 1) end
    while n > 1 and s:byte(n) >= 0x80 and s:byte(n) <= 0xBF do
        n = n - 1
    end
    return s:sub(1, n - 1)
end

local function utf8len(s)
    if type(s) ~= "string" then return 0 end
    local count = 0
    for _ in s:gmatch("[%z\1-\127\194-\244][\128-\191]*") do count = count + 1 end
    return count
end

local function utf8suffix(s, nchars)
    if type(s) ~= "string" or nchars <= 0 then return "" end
    local pos = #s
    for _ = 1, nchars do
        if pos <= 0 then return s end
        while pos > 1 and s:byte(pos) >= 0x80 and s:byte(pos) <= 0xBF do
            pos = pos - 1
        end
        pos = pos - 1
    end
    return s:sub(pos + 1)
end

local function utf8first(s)
    if not s or s == "" then return "" end
    local b = s:byte(1)
    if not b then return "" end
    if b < 0x80 then return s:sub(1, 1) end
    if b >= 0xC0 and b < 0xE0 then return s:sub(1, 2) end
    if b >= 0xE0 and b < 0xF0 then return s:sub(1, 3) end
    return s:sub(1, 4)
end

local function utf8rest(s)
    local first = utf8first(s)
    if not first or first == "" then return "" end
    return s:sub(#first + 1)
end

local function isPureCyrillic(word)
    if type(word) ~= "string" or word == "" then return false end
    local hasCyr = false
    for c in word:gmatch("[%z\1-\127\194-\244][\128-\191]*") do
        local b1 = c:byte(1)
        if (b1 >= 0x41 and b1 <= 0x5A) or (b1 >= 0x61 and b1 <= 0x7A) then
            return false
        end
        if b1 >= 0xD0 and b1 <= 0xD3 then
            hasCyr = true
        end
    end
    return hasCyr
end

local function inflectSingleWord(word, case)
    if type(word) ~= "string" or word == "" then return word end
    if not isPureCyrillic(word) then return word end
    local last = utf8last(word)
    local prev = utf8last(utf8striplast(word))
    local base = utf8striplast(word)
    if case == "ins" then
        if last == "а" then return base .. "ою"
        elseif last == "я" then
            if prev == "ц" or prev == "с" or prev == "з" then return base .. "єю"
            else return utf8striplast(base) .. "ією" end
        elseif last == "ь" then return base .. "ем"
        elseif last == "о" then return base .. "ом"
        elseif last == "е" then return base .. "ем"
        elseif last == "й" then return base .. "єм"
        else return word .. "ом" end
    elseif case == "loc" then
        if last == "а" then return base .. "і"
        elseif last == "я" then
            if prev == "і" then return utf8striplast(base) .. "ії"
            else return base .. "і" end
        elseif last == "ь" then return base .. "ю"
        elseif last == "о" then return base .. "і"
        elseif last == "е" then return base .. "і"
        elseif last == "й" then return base .. "ю"
        else return word .. "і" end
    elseif case == "gen" then
        if last == "а" then return base .. "и"
        elseif last == "я" then
            if prev == "і" then return utf8striplast(base) .. "ії"
            elseif prev == "ц" or prev == "с" or prev == "з" then return base .. "і"
            else return base .. "і" end
        elseif last == "ь" then return base .. "я"
        elseif last == "о" then return base .. "а"
        elseif last == "е" then return base .. "а"
        elseif last == "й" then return base .. "я"
        else return word .. "а" end
    elseif case == "dat" then
        if last == "а" then return base .. "і"
        elseif last == "я" then
            if prev == "і" then return utf8striplast(base) .. "ії"
            else return base .. "і" end
        elseif last == "ь" then return base .. "ю"
        elseif last == "о" then return base .. "у"
        elseif last == "е" then return base .. "у"
        elseif last == "й" then return base .. "ю"
        else return word .. "у" end
    elseif case == "acc" then
        return word
    end
    return word
end

local INFLECTED_ENDINGS = {
    "ого", "ої", "ій", "им", "ими", "ому", "ові", "ах", "ях",
    "ем", "ім", "ам", "ям", "ами", "ою", "ією", "ці", "ні",
}

local INFLECTIBLE_SUFFIXES = {
    "ість", "ення", "ування", "ництво", "ництва", "ування", "ниця",
    "ик", "иця", "ок", "ка", "ня", "це", "це", "ля",
}

local function isAlreadyInflected(word)
    if type(word) ~= "string" or not word:find(" ") then return false end
    local lastWord = word:match("^.*%s+(%S+)$")
    if not lastWord or utf8len(lastWord) < 3 then return false end
    local ending = utf8suffix(lastWord, 3)
    for _, e in ipairs(INFLECTED_ENDINGS) do
        if ending == e then return true end
    end
    ending = utf8suffix(lastWord, 2)
    if ending == "ом" or ending == "ем" or ending == "ію" or ending == "ню"
    or ending == "ку" or ending == "ам" or ending == "ям"
    or ending == "ах" or ending == "ях" then return true end
    local last = utf8last(lastWord)
    if last == "а" or last == "я" or last == "і" or last == "ю" or last == "у" or last == "е" or last == "є" then return true end
    return false
end

local function isInflectible(word)
    if type(word) ~= "string" or utf8len(word) < 3 then return false end
    if not isPureCyrillic(word) then return false end
    if utf8len(word) <= 12 then return true end
    for _, s in ipairs(INFLECTIBLE_SUFFIXES) do
        if word:sub(-#s) == s then return true end
    end
    return false
end

local function inflectBySuffix(word, case)
    if type(word) ~= "string" or word == "" then return word end
    if isAlreadyInflected(word) then return word end
    if word:find(" ") then
        local lastWord = word:match("^.*%s+(%S+)$")
        if lastWord and isInflectible(lastWord) then
            local prefix = word:sub(1, #word - #lastWord - 1)
            local infl = inflectSingleWord(lastWord, case)
            if infl ~= lastWord then
                return prefix .. " " .. infl
            end
        end
        return word
    end
    if not isInflectible(word) then return word end
    return inflectSingleWord(word, case)
end

local function normalizeKey(key)
    if type(key) ~= "string" then return key end
    local k = key:gsub("^%s+", ""):gsub("%s+$", ""):gsub("%s+", " ")
    return k
end

local function stripPreposition(word)
    if type(word) ~= "string" then return word, nil end
    local first = utf8first(word)
    if not first then return word, nil end
    local rest = word:sub(#first + 1):gsub("^%s+", "")
    if first == "У" or first == "у" or first == "В" or first == "в" then
        if rest ~= "" then return rest, first end
    end
    local first2 = word:sub(1, 4)
    if utf8len(first2) == 2 then
        local rest2 = word:sub(5):gsub("^%s+", "")
        if first2 == "До" or first2 == "до" then if rest2 ~= "" then return rest2, first2 end end
        if first2 == "На" or first2 == "на" then if rest2 ~= "" then return rest2, first2 end end
        if first2 == "За" or first2 == "за" then if rest2 ~= "" then return rest2, first2 end end
        if first2 == "Із" or first2 == "із" then if rest2 ~= "" then return rest2, first2 end end
        if first2 == "Зі" or first2 == "зі" then if rest2 ~= "" then return rest2, first2 end end
    end
    local first3 = word:sub(1, 6)
    if utf8len(first3) == 3 then
        local rest3 = word:sub(7):gsub("^%s+", "")
        if first3 == "Про" or first3 == "про" then if rest3 ~= "" then return rest3, first3 end end
        if first3 == "Під" or first3 == "під" then if rest3 ~= "" then return rest3, first3 end end
    end
    local first4 = word:sub(1, 8)
    if utf8len(first4) == 4 then
        local rest4 = word:sub(9):gsub("^%s+", "")
        if first4 == "Біля" or first4 == "біля" then if rest4 ~= "" then return rest4, first4 end end
        if first4 == "Поза" or first4 == "поза" then if rest4 ~= "" then return rest4, first4 end end
    end
    local first5 = word:sub(1, 10)
    if utf8len(first5) == 5 then
        local rest5 = word:sub(11):gsub("^%s+", "")
        if first5 == "Крізь" or first5 == "крізь" then if rest5 ~= "" then return rest5, first5 end end
    end
    return word, nil
end

function ns.Inflect(word, case)
    if not word or word == "" then return word end
    word = normalizeKey(word)
    local infl = ns.INFLECTIONS
    if infl then
        local entry = infl[word]
        if entry and entry[case] then return entry[case] end
        local stripped, prep = stripPreposition(word)
        if prep and stripped ~= word then
            entry = infl[stripped]
            if entry and entry[case] then
                return prep .. " " .. entry[case]
            end
        end
    end
    local titleInfl = ns.TITLE_INFLECTIONS
    if titleInfl then
        local firstSpace = word:find(" ")
        if firstSpace then
            local firstWord = word:sub(1, firstSpace - 1)
            local rest = word:sub(firstSpace + 1)
            local tEntry = titleInfl[firstWord]
            if tEntry and tEntry[case] then
                return tEntry[case] .. " " .. inflectBySuffix(rest, case)
            end
            local secondSpace = rest:find(" ")
            if secondSpace then
                local twoWords = firstWord .. " " .. rest:sub(1, secondSpace - 1)
                local rest2 = rest:sub(secondSpace + 1)
                local t2Entry = titleInfl[twoWords]
                if t2Entry and t2Entry[case] then
                    return t2Entry[case] .. " " .. inflectBySuffix(rest2, case)
                end
            end
            local inflFirst = inflectBySuffix(firstWord, case)
            if inflFirst ~= firstWord then
                return inflFirst .. " " .. rest
            end
        end
    end
    return inflectBySuffix(word, case)
end

local function apply_runtime_rules(text)
    if type(text) ~= "string" or text == "" then
        return nil
    end
    local lookup = ns.DB and ns.DB.Lookup

    local level, ctype = text:match("^Level (%d+) (%w+)$")
    if level and ctype then
        local translated_type = creature_types[ctype]
        if translated_type then
            return "Рівень " .. level .. " " .. translated_type
        end
    end

    local level = text:match("^Level (%d+)$")
    if level then
        return "Рівень " .. level
    end

    local owner = text:match("^(.+)'s Pet$")
    if owner then
        return "Улюбленець " .. owner
    end

    local campaign_chapters = text:match("^Campaign: (%d+)/(%d+) Chapters$")
    if campaign_chapters then
        return "Кампанія: " .. campaign_chapters .. "/" .. text:match("^Campaign: %d+/(%d+) Chapters$") .. " Розділів"
    end

    for _, rule in ipairs(mixed_phrase_rules) do
        if text == rule[1] then
            return rule[2]
        end
    end

    for prefix, translated_prefix in pairs(prefix_rules) do
        if text:sub(1, #prefix) == prefix then
            local rest = text:sub(#prefix + 1)
            rest = rest:gsub("^%s+", "")
            local translated_rest = lookup[rest] or fragment_lookup[rest]
            if translated_rest and translated_rest ~= rest then
                return translated_prefix .. " " .. translated_rest
            end
        end
    end

    for _, rule in ipairs(prefix_regex_rules) do
        local result = text:match(rule[1])
        if result then
            return text:gsub(rule[1], rule[2])
        end
    end

    for _, pair in ipairs(quote_pairs) do
        local open_q, close_q = pair[1], pair[2]
        if text:sub(1, #open_q) == open_q and text:sub(-#close_q) == close_q then
            local inner = text:sub(#open_q + 1, #text - #close_q)
            local translated_inner = lookup[inner] or fragment_lookup[inner]
            if translated_inner and translated_inner ~= inner then
                return open_q .. translated_inner .. close_q
            end
        end
    end

    return nil
end

local function fixCapitalization(original, translated)
    if type(original) ~= "string" or type(translated) ~= "string" then return translated end
    if #original == 0 or #translated == 0 then return translated end
    local origFirst = utf8first(original)
    local transFirst = utf8first(translated)
    if origFirst:match("%u") and transFirst:match("%l") then
        local upper = transFirst:upper()
        if upper ~= transFirst then
            translated = upper .. utf8rest(translated)
        end
    elseif origFirst:match("%l") and transFirst:match("%u") then
        local lower = transFirst:lower()
        if lower ~= transFirst then
            translated = lower .. utf8rest(translated)
        end
    end
    if utf8len(original) >= 2 and original:match("^%u%u") and not translated:match("^%u%u") then
        local f1 = utf8first(translated)
        local r1 = utf8rest(translated)
        local f2 = utf8first(r1)
        if f1 and f2 then
            translated = f1:upper() .. f2:upper() .. utf8rest(r1)
        end
    end
    return translated
end

local _playerNameCache = nil
local _playerNameCacheLen = 0
local function getPlayerName()
    if _playerNameCache then return _playerNameCache end
    local ok, name = pcall(UnitName, "player")
    if ok and type(name) == "string" then
        local ok2, notempty = pcall(function() return name ~= "" end)
        if ok2 and notempty then
            _playerNameCache = name
            _playerNameCacheLen = #name
        end
    end
    return _playerNameCache
end

local function stripPlayerName(text)
    local playerName = getPlayerName()
    if not playerName or _playerNameCacheLen == 0 then return text, false end
    local ok, found = pcall(text.find, text, playerName, 1, true)
    if not ok or not found then return text, false end
    local cleaned = text:gsub(playerName, "{name}")
    return cleaned, true
end

local function applyPatterns(text)
    if type(text) ~= "string" or text == "" then return nil end
    local lookup = ns.DB and ns.DB.Lookup
    local function tryTranslate(part)
        if not part or part == "" then return part end
        local hit = lookup and lookup[part]
        if hit then return hit end
        return part
    end

    local npc, place = text:match("^Meet (.+) at the (.+)%.$")
    if npc and place then return "Зустріньте " .. tryTranslate(npc) .. " у " .. tryTranslate(place) end
    npc, place = text:match("^Meet (.+) at (.+)%.$")
    if npc and place then return "Зустріньте " .. tryTranslate(npc) .. " у " .. tryTranslate(place) end
    npc, place = text:match("^Find (.+) at the (.+)%.$")
    if npc and place then return "Знайдіть " .. tryTranslate(npc) .. " у " .. tryTranslate(place) end
    npc, place = text:match("^Find (.+) in the (.+)%.$")
    if npc and place then return "Знайдіть " .. tryTranslate(npc) .. " у " .. tryTranslate(place) end

    local who, where = text:match("^Speak to (.+) in (.+)%.$")
    if who and where then return "Поговоріть з " .. tryTranslate(who) .. " у " .. tryTranslate(where) end
    who = text:match("^Speak to (.+)%.$")
    if who then return "Поговоріть з " .. tryTranslate(who) end
    who = text:match("^Talk to (.+)%.$")
    if who then return "Поговоріть з " .. tryTranslate(who) end
    who = text:match("^Speak with (.+)%.$")
    if who then return "Поговоріть з " .. tryTranslate(who) end

    local what, who2 = text:match("^Deliver (.+) to (.+)%.$")
    if what and who2 then return "Доставте " .. tryTranslate(what) .. " до " .. tryTranslate(who2) end
    local item, target = text:match("^Bring (.+) to (.+)%.$")
    if item and target then return "Принесіть " .. tryTranslate(item) .. " до " .. tryTranslate(target) end
    local target2, item2 = text:match("^Collect (.+) from (.+)%.$")
    if item2 and target2 then return "Зберіть " .. tryTranslate(item2) .. " від " .. tryTranslate(target2) end

    target2 = text:match("^Kill (.+)%.$")
    if target2 then return "Вбийте " .. tryTranslate(target2) end
    target2 = text:match("^Slay (.+)%.$")
    if target2 then return "Вбийте " .. tryTranslate(target2) end
    target2 = text:match("^Defeat (.+)%.$")
    if target2 then return "Переможіть " .. tryTranslate(target2) end
    target2 = text:match("^Destroy (.+)%.$")
    if target2 then return "Знищте " .. tryTranslate(target2) end

    local count, what2 = text:match("^(%d+)/(%d+ .+)$")
    if count and what2 then
        local trWhat = tryTranslate(what2)
        if trWhat ~= what2 then return count .. "/" .. trWhat end
    end

    what2 = text:match("^Gather (.+)%.$")
    if what2 then return "Зберіть " .. tryTranslate(what2) end
    what2 = text:match("^Collect (.+)%.$")
    if what2 then return "Зберіть " .. tryTranslate(what2) end

    local where3, what3 = text:match("^Search (.+) for (.+)%.$")
    if where3 and what3 then return "Шукайте " .. tryTranslate(what3) .. " у " .. tryTranslate(where3) end

    what2 = text:match("^Escort (.+)%.$")
    if what2 then return "Супроводжуйте " .. tryTranslate(what2) end
    what2 = text:match("^Rescue (.+)%.$")
    if what2 then return "Врятуйте " .. tryTranslate(what2) end
    what2 = text:match("^Free (.+)%.$")
    if what2 then return "Звільніть " .. tryTranslate(what2) end
    what2 = text:match("^Investigate the (.+)%.$")
    if what2 then return "Дослідіть " .. tryTranslate(what2) end
    what2 = text:match("^Explore the (.+)%.$")
    if what2 then return "Дослідіть " .. tryTranslate(what2) end

    return nil
end

local function sanitizeForLookup(text)
    if not text then return nil end
    local ok_t, is_str = pcall(function() return type(text) == "string" end)
    if not ok_t or not is_str then return nil end
    local ok_s, s = pcall(function()
        local r = text
        r = r:gsub("|c%x%x%x%x%x%x%x%x", "")
        r = r:gsub("|r", "")
        r = r:gsub("|H[^|]*|h%[([^%]]*)%]|h", "%1")
        r = r:gsub("|H[^|]*|h", "")
        r = r:gsub("|h", "")
        r = r:gsub("|T[^|]*|t", "")
        local pn = getPlayerName()
        if pn and #pn > 0 and r:find(pn, 1, true) then
            r = r:gsub(pn:gsub("([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1"), "{name}")
        end
        r = r:gsub("|n", " ")
        r = r:gsub("[\r\n]+", " ")
        r = r:gsub("%s+", " ")
        r = r:gsub("^%s+", "")
        r = r:gsub("%s+$", "")
        return r
    end)
    if not ok_s or not s or s == "" then return nil end
    return s
end

local function translate_text_value(text)
    if not text then return nil end
    local ok_type, is_str = pcall(function() return type(text) == "string" end)
    if not ok_type or not is_str then return nil end
    local ok_e, is_empty = pcall(function() return text == "" end)
    if ok_e and is_empty then return nil end
    local ok_len, tlen = pcall(function() return #text end)
    if not ok_len or tlen <= 1 then return nil end
    local ok_a, has_alpha = pcall(function() return not not text:find("[%a\128-\255]") end)
    if not ok_a or not has_alpha then return nil end

    local ok_ch, cached = pcall(function() return _translationCache[text] end)
    if ok_ch and cached ~= nil then return cached end

    local hit = ns.GUARANTEED_OVERRIDES and ns.GUARANTEED_OVERRIDES[text]
    if hit then _translationCache[text] = hit; return hit end

    local lookup = ns.DB and ns.DB.Lookup
    if not lookup then return nil end

    local ok_lk, hit = pcall(function() return lookup[text] end)
    if ok_lk and hit then _translationCache[text] = hit; return hit end

    local clean = sanitizeForLookup(text)
    if not clean then _translationCache[text] = false; return nil end

    if clean ~= text then
        hit = lookup[clean]
        if hit then _translationCache[text] = hit; return hit end
    end

    local runtime_hit = apply_runtime_rules(clean)
    if runtime_hit then
        runtime_hit = fixCapitalization(text, runtime_hit)
        _translationCache[text] = runtime_hit
        return runtime_hit
    end

    if WoWTranslate_UK_Untranslated and type(WoWTranslate_UK_Untranslated) == "table" then
        if #clean >= 3 and #clean < 300 and clean:find("[a-zA-Z]") and not clean:find("^%d+$") then
            local existing = WoWTranslate_UK_Untranslated[clean]
            if type(existing) == "table" then
                existing[1] = (existing[1] or 0) + 1
            elseif type(existing) == "number" then
                WoWTranslate_UK_Untranslated[clean] = {existing + 1, text}
            else
                WoWTranslate_UK_Untranslated[clean] = {1, text}
            end
        end
    end

    _translationCache[text] = false
    return nil
end

function ns.resolvePlaceholders(text)
    if not text or type(text) ~= "string" then return text end
    local playerName = UnitName and UnitName("player") or ""
    local playerClass = (UnitClass and select(1, UnitClass("player"))) or ""
    local playerRace = UnitRace and UnitRace("player") or ""
    local playerGender = UnitSex and (UnitSex("player") == 2 and "чоловічий" or "жіночий") or ""
    text = text:gsub("{name}", playerName)
    text = text:gsub("{class}", playerClass)
    text = text:gsub("{race}", playerRace)
    text = text:gsub("{gender}", playerGender)
    text = text:gsub("<name>", playerName)
    text = text:gsub("<class>", playerClass)
    text = text:gsub("<race>", playerRace)
    text = text:gsub("<gender>", playerGender)
    text = text:gsub("%[name%]", playerName)
    text = text:gsub("%[class%]", playerClass)
    text = text:gsub("%[race%]", playerRace)
    text = text:gsub("%[gender%]", playerGender)
    return text
end

function ns.GetTranslation(text)
    return translate_text_value(text)
end

local function isProtectedFrame(f)
    if not f then return true end
    local ok_ip, prot = pcall(f.IsProtected, f)
    if ok_ip and prot then return true end
    local ok_name, name = pcall(f.GetName, f)
    if not ok_name or type(name) ~= "string" then return false end
    if name:find("StatusBar") or name:find("Health") or name:find("Mana") then return true end
    if name:find("PowerBar") or name:find("UnitPower") or name:find("ComboPoint") then return true end
    if name:find("PlayerFrame") or name:find("TargetFrame") or name:find("FocusFrame") or name:find("PetFrame") then return true end
    if name:find("Boss") or name:find("Arena") or name:find("PartyFrame") or name:find("CompactRaid") then return true end
    return false
end
ns.isProtectedFrame = isProtectedFrame

function ns.TranslateTextObject(obj)
    if not obj or not obj.GetText or not obj.SetText or obj._wt_updating then
        return false
    end

    if InCombatLockdown and InCombatLockdown() then return false end
    if isProtectedFrame(obj) then return false end

    local ok_gp, parent = pcall(obj.GetParent, obj)
    if ok_gp and parent then
        if isProtectedFrame(parent) then return false end
        local ok_pt, ptype = pcall(parent.GetObjectType, parent)
        if ok_pt and ptype == "StatusBar" then return false end
    end

    local ok_gt, text = pcall(obj.GetText, obj)
    if not ok_gt then return false end
    local ok_type = pcall(function()
        if type(text) ~= "string" then error("__skip") end
        if text == "" then error("__skip") end
    end)
    if not ok_type then return false end

    local ok_trans, translated = pcall(translate_text_value, text)
    if not ok_trans or not translated then return false end
    translated = ns.resolvePlaceholders(translated)
    if type(translated) ~= "string" then return false end

    local ok_cmp, same = pcall(function() return translated == text end)
    if ok_cmp and same then return false end

    if hasCyrillic(translated) and obj.SetFont then
        if InCombatLockdown and InCombatLockdown() then return false end
        local ok, fontFile, height, flags = pcall(obj.GetFont, obj)
        if ok and fontFile and needsCyrillicFont(fontFile) then
            local chosen = selectFontForContext(fontFile)
            pcall(obj.SetFont, obj, chosen, height or 13, flags or "")
        end
    end

    local hasTextColor = type(obj.GetTextColor) == "function" and type(obj.SetTextColor) == "function"
    local r, g, b, a
    if hasTextColor then
        local ok_tc = pcall(function() r, g, b, a = obj:GetTextColor() end)
        if not ok_tc then hasTextColor = false end
    end

    obj._wt_updating = true
    pcall(obj.SetText, obj, translated)
    if hasTextColor and r and g and b then
        pcall(obj.SetTextColor, obj, r, g, b, a or 1)
    end
    obj._wt_updating = nil
    obj._wt_tr = translated
    obj._wt_orig = text
    return true
end

function ns.TranslateFontString(fontString)
    return ns.TranslateTextObject(fontString)
end

function ns.TranslateTooltip(tooltip)
    if not tooltip then
        return
    end
    ns.TranslateFrame(tooltip)
end

function ns.TranslateFrame(frame, visited, depth)
    if not frame then
        return
    end
    if isProtectedFrame(frame) then
        return
    end
    depth = depth or 0
    if depth > 8 then
        return
    end
    visited = visited or {}
    if visited[frame] then
        return
    end
    visited[frame] = true

    if frame.GetText and frame.SetText then
        ns.TranslateTextObject(frame)
    end

    if frame.GetRegions then
        local ok, regions = pcall(function()
            local t = {frame:GetRegions()}
            return t
        end)
        if ok and type(regions) == "table" then
            for _, region in ipairs(regions) do
                if region and not isProtectedFrame(region) and region.GetText and region.SetText then
                    ns.TranslateTextObject(region)
                end
            end
        end
    end

    if frame.GetChildren then
        local ok, children = pcall(function()
            local t = {frame:GetChildren()}
            return t
        end)
        if ok and type(children) == "table" then
            for _, child in ipairs(children) do
                if not isProtectedFrame(child) then
                    ns.TranslateFrame(child, visited, depth + 1)
                end
            end
        end
    end
end

function ns.ApplyFonts()
    if InCombatLockdown and InCombatLockdown() then return end
    for key, obj in pairs(_G) do
        if type(obj) == "table" and type(key) == "string" and key:find("Font") then
            local ok, fontFile, height, flags = pcall(obj.GetFont, obj)
            if ok and fontFile and needsCyrillicFont(fontFile) then
                local f = selectFontForContext(fontFile)
                if key:find("Title") or key:find("Huge") or key:find("Enormous") or key:find("Header") then
                    f = preferredTitleFont
                end
                pcall(obj.SetFont, obj, f, height or 13, flags or "")
            end
        end
    end

    local fontObjMT = getmetatable(UIParent:CreateFontString(nil, "ARTWORK", "GameFontNormal"))
    local fontObjIndex = fontObjMT and fontObjMT.__index

    if fontObjIndex and fontObjIndex.SetFontObject then
        hooksecurefunc(fontObjIndex, "SetFontObject", function(self, fontObj)
            if not self or self._wt_font_busy or isProtectedFrame(self) then return end
            if InCombatLockdown and InCombatLockdown() then return end
            local ok_gt, text = pcall(self.GetText, self)
            if not ok_gt or not hasCyrillic(text) then return end
            local ok, fontFile, height, flags = pcall(self.GetFont, self)
            if not ok or not needsCyrillicFont(fontFile) then return end
            self._wt_font_busy = true
            pcall(self.SetFont, self, preferredFont, height or 13, flags or "")
            self._wt_font_busy = nil
        end)
    end

    pcall(hooksecurefunc, "UIDropDownMenu_CreateFrames", function(level)
        level = level or 1
        for i = 1, UIDROPDOWNMENU_MAXBUTTONS or 20 do
            local button = _G["DropDownList" .. level .. "Button" .. i]
            if button then
                local ok, regions = pcall(function()
                    local t = {button:GetRegions()}
                    return t
                end)
                if ok and type(regions) == "table" then
                    for _, region in ipairs(regions) do
                        if region and region.GetFont then
                            if InCombatLockdown and InCombatLockdown() then return end
                            local ok2, fontFile, height, flags = pcall(region.GetFont, region)
                            if ok2 and needsCyrillicFont(fontFile) then
                                pcall(region.SetFont, region, preferredFont, height or 12, flags or "")
                            end
                        end
                    end
                end
            end
        end
    end)
end

function ns.InstallSetTextHook()
    if set_text_hook_installed or not hooksecurefunc or not UIParent then
        return
    end

    local function hook_object(obj)
        if not obj then
            return false
        end
        local mt = getmetatable(obj)
        local index = mt and mt.__index
        if not index or type(index.SetText) ~= "function" then
            return false
        end

        local ok_hook = pcall(hooksecurefunc, index, "SetText", function(self, text)
            if not self or self._wt_updating then return end
            local ok_t, is_str = pcall(function() return type(text) == "string" end)
            if not ok_t or not is_str then return end
            local ok_e, is_empty = pcall(function() return text == "" end)
            if ok_e and is_empty then return end
            local ok_a, has_alpha = pcall(function() return not not text:find("%a") end)
            if not ok_a or not has_alpha then return end

            local function isMoneyFrame(frame)
                if not frame then return false end
                local ok_ot, otype = pcall(frame.GetObjectType, frame)
                if ok_ot and otype == "MoneyFrame" then return true end
                local ok_n, name = pcall(frame.GetName, frame)
                if ok_n and type(name) == "string" then
                    if name:find("MoneyFrame") or name:find("Gold") or name:find("Silver") or name:find("Copper") then
                        return true
                    end
                end
                return false
            end

            local function isQuestMoneyFrame(frame)
                if not frame then return false end
                local ok_n, name = pcall(frame.GetName, frame)
                if ok_n and type(name) == "string" and name:find("QuestInfo") then
                    return true
                end
                local ok_gp, p = pcall(frame.GetParent, frame)
                if ok_gp and p then
                    local ok_pn, pn = pcall(p.GetName, p)
                    if ok_pn and type(pn) == "string" and pn:find("QuestInfo") then return true end
                end
                return false
            end

            if isMoneyFrame(self) and not isQuestMoneyFrame(self) then return end

            local ok_sn, sname = pcall(self.GetName, self)
            if ok_sn and type(sname) == "string" then
                if sname:find("MoneyFrame") or sname:find("Gold") or sname:find("Silver") or sname:find("Copper") then
                    if not sname:find("QuestInfo") then return end
                end
                if sname:find("AltPowerBar") or sname:find("PowerBar") or sname:find("MenuBar") then return end
                if sname:find("Menu") or sname:find("ContextMenu") or sname:find("Dropdown") then return end
            end

            local _parentMoney = false
            do
                local ok_p, p = pcall(self.GetParent, self)
                if ok_p and p and isMoneyFrame(p) and not isQuestMoneyFrame(p) then
                    _parentMoney = true
                end
            end
            if _parentMoney then return end

            do
                local ok_mt, mt = pcall(getmetatable, self)
                if ok_mt and mt then
                    local idx = mt.__index
                    if type(idx) == "function" then return end
                    if type(idx) == "table" then
                        local ok_df, df = pcall(function() return idx.disallowedFunctions end)
                        if ok_df and type(df) == "table" and (df.SetFont or df.SetText) then return end
                    end
                end
            end

            do
                local ok_gp2, p2 = pcall(self.GetParent, self)
                if ok_gp2 and p2 then
                    local ok_pn2, pn2 = pcall(p2.GetName, p2)
                    if ok_pn2 and type(pn2) == "string" and (pn2:find("Menu") or pn2:find("Dropdown")) then return end
                    local ok_gpp, gp2 = pcall(p2.GetParent, p2)
                    if ok_gpp and gp2 then
                        local ok_gpn2, gpn2 = pcall(gp2.GetName, gp2)
                        if ok_gpn2 and type(gpn2) == "string" and (gpn2:find("Menu") or gpn2:find("Dropdown")) then return end
                    end
                end
            end

            if isProtectedFrame(self) then return end
            local ok_gp, parent = pcall(self.GetParent, self)
            if ok_gp and parent then
                if isProtectedFrame(parent) then return end
                local ok_pt, ptype = pcall(parent.GetObjectType, parent)
                if ok_pt and ptype == "StatusBar" then return end
                local ok_pp, gparent = pcall(parent.GetParent, parent)
                if ok_pp and gparent then
                    if isMoneyFrame(gparent) and not isQuestMoneyFrame(gparent) then return end
                end
            end

            local ok_tr, tr_match = pcall(function() return self._wt_tr == text end)
            if ok_tr and tr_match then return end
            local ok_or, orig_match = pcall(function() return self._wt_orig == text and self._wt_tr end)
            if ok_or and orig_match then
                self._wt_updating = true
                pcall(self.SetText, self, self._wt_tr)
                self._wt_updating = nil
                return
            end

            local rawColorPrefix = ""
            local rawColorSuffix = ""
            local rawClean = text
            local ok_cp, cp = pcall(function() return text:match("^(|c%x%x%x%x%x%x%x%x)") end)
            if ok_cp and cp then rawColorPrefix = cp end
            local ok_cs, cs = pcall(function() return text:match("(|r)$") end)
            if ok_cs and cs then rawColorSuffix = cs end
            if rawColorPrefix ~= "" or rawColorSuffix ~= "" then
                local ok_strip, stripped = pcall(function()
                    return text:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", "")
                end)
                if ok_strip and stripped then rawClean = stripped end
            end

            local ok_trans, translated = pcall(translate_text_value, rawClean)
            if not ok_trans or not translated then
                return
            end
            translated = ns.resolvePlaceholders(translated)

            local ok_cmp, same = pcall(function() return translated == rawClean end)
            if ok_cmp and same then
                return
            end

            if rawColorPrefix ~= "" or rawColorSuffix ~= "" then
                translated = rawColorPrefix .. translated .. rawColorSuffix
            end

            local hasTextColor = false
            do
                local ok_gtc, gtc = pcall(function() return self.GetTextColor end)
                local ok_stc, stc = pcall(function() return self.SetTextColor end)
                if ok_gtc and ok_stc and gtc and stc then hasTextColor = true end
            end
            local r, g, b, a
            if hasTextColor then
                local ok_tc = pcall(function() r, g, b, a = self:GetTextColor() end)
                if not ok_tc then hasTextColor = false end
            end

            if hasCyrillic(translated) then
                if InCombatLockdown and InCombatLockdown() then
                else
                    local ok2, fontFile, height, flags = pcall(self.GetFont, self)
                    if ok2 and fontFile and needsCyrillicFont(fontFile) then
                        local chosen = selectFontForContext(fontFile)
                        pcall(self.SetFont, self, chosen, height or 13, flags or "")
                    end
                end
            end

            self._wt_updating = true
            pcall(self.SetText, self, translated)
            if hasTextColor and r and g and b then
                pcall(self.SetTextColor, self, r, g, b, a or 1)
            end
            self._wt_updating = nil
            self._wt_tr = translated
            self._wt_orig = text
        end)

        if not ok_hook then return false end
        return true
    end

    local hooked = false
    hooked = hook_object(UIParent:CreateFontString(nil, "ARTWORK", "GameFontNormal")) or hooked

    local button = CreateFrame("Button", nil, UIParent, "UIPanelButtonTemplate")
    if button then
        hooked = hook_object(button) or hooked
        button:Hide()
    end

    local html = CreateFrame("SimpleHTML", nil, UIParent)
    if html then
        hooked = hook_object(html) or hooked
        html:Hide()
    end

    set_text_hook_installed = hooked
    ns._setTextHookInstalled = hooked
end