Module:User:Theknightwho/cau-nec-translit

local export = {}

-- Structured like this to reduce size of loaded table. local function getSubs(lang) --Aghul if lang == "agx" then return { {				["гъ"] = "ğ", ["гь"] = "h", ["гӏ"] = "ʻʳ", ["къ"] = "qq", ["кь"] = "qʼ", ["кӏ"] = "kʼ", ["пӏ"] = "pʼ", ["тӏ"] = "tʼ", ["хъ"] = "q", ["хь"] = "x̂", ["хӏ"] = "ḥʳ", ["цӏ"] = "cʼ", ["чӏ"] = "čʼ" },			{				["а"] = "a", ["б"] = "b", ["в"] = "v", ["г"] = "g", ["д"] = "d", ["е"] = "e", ["ё"] = "jo", ["ж"] = "ž", ["з"] = "z", ["и"] = "i", ["й"] = "j", ["к"] = "k", ["л"] = "l", ["м"] = "m", ["н"] = "n", ["о"] = "o", ["п"] = "p", ["р"] = "r", ["с"] = "s", ["т"] = "t", ["у"] = "u", ["ф"] = "f", ["х"] = "x", ["ц"] = "c", ["ч"] = "č", ["ш"] = "š", ["щ"] = "sš", ["ъ"] = "ʔ", ["ы"] = "ə", ["ь"] = "ʲ", ["э"] = "e", ["ю"] = "ju", ["я"] = "ja" }		}	-- Akhvakh elseif lang == "akv" then return { {				["гъӏ"] = "ğʰ", ["къӏ"] = "qˣʼ", ["кьӏ"] = "kˡʼ", ["лӏъ"] = "ᵏl", ["хъӏ"] = "qˣ" },			{				["гъ"] = "ɣ", ["гь"] = "h", ["гӏ"] = "ʻʳ", ["къ"] = "qxʼ", ["кь"] = "kkˡʼ", ["кӏ"] = "kʼ", ["лъ"] = "lˢ", ["ль"] = "ĺ", ["лӏ"] = "ᵏll", ["пӏ"] = "pʼ", ["тӏ"] = "tʼ", ["хъ"] = "qx", ["хь"] = "x̂", ["хӏ"] = "ḥʳ", ["цӏ"] = "cʼ", ["чӏ"] = "čʼ" },			{				["а"] = "a", ["б"] = "b", ["в"] = "v", ["г"] = "g", ["д"] = "d", ["е"] = "e", ["ё"] = "jo", ["ж"] = "ž", ["з"] = "z", ["и"] = "i", ["й"] = "j", ["к"] = "k", ["л"] = "l", ["м"] = "m", ["н"] = "n", ["о"] = "o", ["п"] = "p", ["р"] = "r", ["с"] = "s", ["т"] = "t", ["у"] = "u", ["ф"] = "f", ["х"] = "x", ["ц"] = "c", ["ч"] = "č", ["ш"] = "š", ["щ"] = "sš", ["ъ"] = "ʔ", ["ы"] = "ə", ["ь"] = "ʲ", ["э"] = "e", ["ю"] = "ju", ["я"] = "ja" }		}	-- Andi elseif lang == "ani" then return { {				["къкъ"] = "qxʼ", ["хъхъ"] = "qx" },			{				["гъӏ"] = "ğʼ", ["жъӏ"] = "žʼ", ["къӏ"] = "qxʼ", ["лъӏ"] = "llˢʼ", ["хъӏ"] = "qx", ["цъӏ"] = "ccʼ", ["чъӏ"] = "cčʼ" },			{				["гъ"] = "ğ", ["гь"] = "h", ["гӏ"] = "gʼ", ["къ"] = "qˣʼ", ["кь"] = "kkˡʼ", ["кӏ"] = "kʼ", ["лъ"] = "lˢ", ["ль"] = "lˢʼ", ["лӏ"] = "ᵏll", ["пӏ"] = "pʼ", ["тӏ"] = "tʼ", ["хъ"] = "qˣ", ["хь"] = "x̂", ["хӏ"] = "xʼ", ["цӏ"] = "cʼ", ["чӏ"] = "čʼ" },			{				["а"] = "a", ["б"] = "b", ["в"] = "v", ["г"] = "g", ["д"] = "d", ["е"] = "e", ["ё"] = "jo", ["ж"] = "ž", ["з"] = "z", ["и"] = "i", ["й"] = "j", ["к"] = "k", ["л"] = "l", ["м"] = "m", ["н"] = "n", ["о"] = "o", ["п"] = "p", ["р"] = "r", ["с"] = "s", ["т"] = "t", ["у"] = "u", ["ф"] = "f", ["х"] = "x", ["ц"] = "c", ["ч"] = "č", ["ш"] = "š", ["щ"] = "sš", ["ъ"] = "ˀ", ["ы"] = "ə", ["ь"] = "ʲ", ["э"] = "e", ["ю"] = "ju", ["я"] = "ja" }		}	-- Archi elseif lang == "aqc" then return { {				["ккъӏ"] = "qq̣ʼ", ["ххьӏ"] = "xx̣" },			{				["гъӏ"] = "ğ̣", ["ккъ"] = "qqʼ", ["къӏ"] = "q̣ʼ", ["ллъ"] = "llʰ", ["хъӏ"] = "q̣", ["хьӏ"] = "x̣", ["ццӏ"] = "ccʼ", ["ччӏ"] = "cčʼ" },			{				["гъ"] = "ğ", ["гь"] = "h", ["гӏ"] = "ˀ", ["къ"] = "qʼ", ["кь"] = "kˡʼ", ["кӏ"] = "kʼ", ["лъ"] = "lʰ", ["ль"] = "lˠ", ["лӏ"] = "ᵏl", ["пӏ"] = "pʼ", ["тӏ"] = "tʼ", ["хъ"] = "q", ["хӏ"] = "ḥʳ", ["цӏ"] = "cʼ", ["чӏ"] = "čʼ" },			{				["а"] = "a", ["б"] = "b", ["в"] = "w", ["г"] = "g", ["д"] = "d", ["е"] = "e", ["ё"] = "jo", ["ж"] = "ž", ["з"] = "z", ["и"] = "i", ["й"] = "j", ["к"] = "k", ["л"] = "l", ["м"] = "m", ["н"] = "n", ["о"] = "o", ["п"] = "p", ["р"] = "r", ["с"] = "s", ["т"] = "t", ["у"] = "u", ["ф"] = "f", ["х"] = "x", ["ц"] = "c", ["ч"] = "č", ["ш"] = "š", ["щ"] = "sš", ["ъ"] = "ʔ", ["ы"] = "ə", ["ь"] = "", ["э"] = "e", ["ю"] = "ju", ["я"] = "ja" }		}	-- Avar elseif lang == "av" then return { {				["гъ"] = "ğ", ["гь"] = "h", ["гӏ"] = "ʻ", ["къ"] = "qxʼ", ["кь"] = "kkˡʼ", ["кӏ"] = "kʼ", ["лъ"] = "lˢ", ["лӏ"] = "ᵏll", ["тӏ"] = "tʼ", ["хъ"] = "qx", ["хь"] = "x̂", ["хӏ"] = "ḥʳ", ["цӏ"] = "cʼ", ["чӏ"] = "čʼ" },			{				["а"] = "a", ["б"] = "b", ["в"] = "w", ["г"] = "g", ["д"] = "d", ["е"] = "e", ["ё"] = "jo", ["ж"] = "ž", ["з"] = "z", ["и"] = "i", ["й"] = "j", ["к"] = "k", ["л"] = "l", ["м"] = "m", ["н"] = "n", ["о"] = "o", ["п"] = "p", ["р"] = "r", ["с"] = "s", ["т"] = "t", ["у"] = "u", ["ф"] = "f", ["х"] = "x", ["ц"] = "c", ["ч"] = "č", ["ш"] = "š", ["щ"] = "sš", ["ъ"] = "ʔ", ["ы"] = "ə", ["ь"] = "ʲ", ["э"] = "e", ["ю"] = "ju", ["я"] = "ja" }		}	-- Bagvalal elseif lang == "kva" then return { {				["гъ"] = "ğ", ["гь"] = "h", ["гӏ"] = "ˀ", ["къ"] = "qʼ", ["кь"] = "kkˡʼ", ["кӏ"] = "kʼ", ["лъ"] = "lˢ", ["лӏ"] = "ᵏll", ["сӏ"] = "sʼ", ["тӏ"] = "tʼ", ["хъ"] = "qx", ["хь"] = "x̂", ["хӏ"] = "ḥ", ["цӏ"] = "cʼ", ["чӏ"] = "čʼ", ["шӏ"] = "šʼ" },			{				["а"] = "a", ["б"] = "b", ["в"] = "v", ["г"] = "g", ["д"] = "d", ["е"] = "e", ["ё"] = "jo", ["ж"] = "ž", ["з"] = "z", ["и"] = "i", ["й"] = "j", ["к"] = "k", ["л"] = "l", ["м"] = "m", ["н"] = "n", ["о"] = "o", ["п"] = "p", ["р"] = "r", ["с"] = "s", ["т"] = "t", ["у"] = "u", ["ф"] = "f", ["х"] = "x", ["ц"] = "c", ["ч"] = "č", ["ш"] = "š", ["щ"] = "sš", ["ъ"] = "ʔ", ["ы"] = "ə", ["ь"] = "ʲ", ["э"] = "e", ["ю"] = "ju", ["я"] = "ja" }		}	-- Bezhta elseif lang == "kap" then return { {				["гъ"] = "ğ", ["гь"] = "h", ["гӏ"] = "ʻ", ["къ"] = "qxʼ", ["кь"] = "kˡʼ", ["кӏ"] = "kʼ", ["лъ"] = "lˢ", ["лӏ"] = "ᵏll", ["пӏ"] = "pʼ", ["тӏ"] = "tʼ", ["хъ"] = "qx", ["хь"] = "x̂", ["хӏ"] = "ḥ", ["цӏ"] = "cʼ", ["чӏ"] = "čʼ" },			{				["а"] = "a", ["б"] = "b", ["в"] = "v", ["г"] = "g", ["д"] = "d", ["е"] = "e", ["ё"] = "jo", ["ж"] = "ž", ["з"] = "z", ["и"] = "i", ["й"] = "j", ["к"] = "k", ["л"] = "l", ["м"] = "m", ["н"] = "n", ["о"] = "o", ["п"] = "p", ["р"] = "r", ["с"] = "s", ["т"] = "t", ["у"] = "u", ["ф"] = "f", ["х"] = "x", ["ц"] = "c", ["ч"] = "č", ["ш"] = "š", ["щ"] = "sš", ["ъ"] = "ʔ", ["ы"] = "ə", ["ь"] = "ʲ", ["э"] = "e", ["ю"] = "ju", ["я"] = "ja" }		}	-- Botlikh elseif lang == "bph" then return { {				["гъ"] = "ğ", ["гь"] = "h", ["къ"] = "qˣʼ", ["кь"] = "kkˡʼ", ["кӏ"] = "kʼ", ["лъ"] = "lˢ", ["лӏ"] = "ᵏll", ["пӏ"] = "pʼ", ["тӏ"] = "tʼ", ["хъ"] = "qˣ", ["хь"] = "x̂", ["цӏ"] = "cʼ", ["чӏ"] = "čʼ" },			{				["а"] = "a", ["б"] = "b", ["в"] = "w", ["г"] = "g", ["д"] = "d", ["е"] = "e", ["ё"] = "jo", ["ж"] = "ž", ["з"] = "z", ["и"] = "i", ["й"] = "j", ["к"] = "k", ["л"] = "l", ["м"] = "m", ["н"] = "n", ["о"] = "o", ["п"] = "p", ["р"] = "r", ["с"] = "s", ["т"] = "t", ["у"] = "u", ["ф"] = "f", ["х"] = "x", ["ц"] = "c", ["ч"] = "č", ["ш"] = "š", ["щ"] = "sš", ["ъ"] = "ˀ", ["ы"] = "ə", ["ь"] = "ʲ", ["э"] = "e", ["ю"] = "ju", ["я"] = "ja" }		}	-- Budukh elseif lang == "bdk" then return { {				["къг"] = "gʰ" },			{				["гъ"] = "ğ", ["гь"] = "h", ["гӏ"] = "ʻ", ["къ"] = "qq", ["кь"] = "qʼ", ["кӏ"] = "kʼ", ["пӏ"] = "pʼ", ["тӏ"] = "tʼ", ["хъ"] = "q", ["хь"] = "x̂", ["хӏ"] = "ḥ", ["цӏ"] = "cʼ", ["чӏ"] = "čʼ" },			{				["а"] = "a", ["б"] = "b", ["в"] = "v", ["г"] = "g", ["д"] = "d", ["е"] = "e", ["ё"] = "jo", ["ж"] = "ž", ["з"] = "z", ["и"] = "i", ["й"] = "j", ["к"] = "k", ["л"] = "l", ["м"] = "m", ["н"] = "n", ["о"] = "o", ["п"] = "p", ["р"] = "r", ["с"] = "s", ["т"] = "t", ["у"] = "u", ["ф"] = "f", ["х"] = "x", ["ц"] = "c", ["ч"] = "č", ["ш"] = "š", ["щ"] = "sš", ["ъ"] = "ʔ", ["ы"] = "ı", ["ь"] = "ʲ", ["э"] = "e", ["ю"] = "ju", ["я"] = "ja", ["ӏ"] = "ˀ" }		}	end end

function export.tr(text, lang, sc) local subs = getSubs(lang) local UTF8_char = "[%z\1-\127\194-\244][\128-\191]*" local CyrlConsonant = "бвгджзклмнпрстфхцчшщъьӏБВГДЖЗКЛМНПРСТФХЦЧШЩЪЬӀ" local CyrlVowel = "аеёиоуыэюяАЕЁИОУЫЭЮЯ" local ACUTE, CIRC, TILDE, MACRON, BREVE, DIAER, CARON, DOTBELOW = mw.ustring.char(0x301), mw.ustring.char(0x302), mw.ustring.char(0x303), mw.ustring.char(0x304), mw.ustring.char(0x306), mw.ustring.char(0x308), mw.ustring.char(0x30C), mw.ustring.char(0x323) local br = mw.ustring.char(0xF000) local noDoubleAccent = ACUTE .. CIRC .. BREVE .. CARON .. DOTBELOW if sc == "Arab" then return require("Module:ar-translit").tr(text, lang, sc) elseif sc == "Geor" then return require("Module:Geor-translit").tr(text, lang, sc) elseif not subs then return nil end -- Convert uppercase palochka to lowercase, along with any "false" palochkas (entered as Latin "I" or "l", or Cyrillic "І"). Lowercase palochka is found in tables above. text = mw.ustring.gsub(text, "[IlІӀ]", "ӏ") -- Convert dialectal nasal ᵸ written as Latin ᴴ. text = mw.ustring.gsub(text, "ᴴ", "ᵸ") -- Decompose precomposed characters, except for ё and й. text = mw.ustring.gsub(text, "[^ёЁйЙ]", mw.ustring.toNFD) -- Substitute double consonants for macrons over consonants. Add a temporary breaking character after, to prevent the creation of false multigraphs with following characters. local function macronToDouble(a, b) return a .. b .. mw.ustring.lower(a) .. b .. br end text = mw.ustring.gsub(text, "([" .. CyrlConsonant .. "])" .. MACRON .. "([ъь])" .. MACRON, macronToDouble) text = mw.ustring.gsub(text, "([" .. CyrlConsonant .. "])" .. MACRON .. "(ӏ?)" .. MACRON .. "?", macronToDouble) -- Remove any double hard/soft signs or palochkas this creates. text = mw.ustring.gsub(text, "([ъьӏЪЬӀ])" .. "([ъьӏ])", function(a, b) if b == mw.ustring.lower(a) then return a else return a .. b end end) -- Contextual substitution of "j" before "е", "w" for "у" and ʷ for "в". if lang == "aqc" then text = mw.ustring.gsub(text, "([" .. CyrlConsonant .. "]" .. br .. "?[ӏӀ]?" .. br .. "?)в", "%1ʷ") else text = mw.ustring.gsub(text, "^е", "jе") text = mw.ustring.gsub(text, "^Е", "Jе") text = mw.ustring.gsub(text, "([" .. CyrlVowel .. "%s]" .. MACRON .. "?ь?ӏ?ᵸ?)е", "%1jе") text = mw.ustring.gsub(text, "(%s)Е", "%1Jе") text = mw.ustring.gsub(text, "у([аиоуыэ])", "w%1") text = mw.ustring.gsub(text, "У([аиоуыэ])", "W%1") text = mw.ustring.gsub(text, "([" .. CyrlVowel .. "]" .. MACRON .. "?ь?ӏ?ᵸ?)у", "%1w") text = mw.ustring.gsub(text, "([" .. CyrlConsonant .. "]" .. br .. "?)в", "%1ʷ") end -- Process vowel modifiers. text = mw.ustring.gsub(text, "([" .. CyrlVowel .. "])(" .. MACRON .. "?)ь", "%1" .. DIAER .. "%2") text = mw.ustring.gsub(text, "([" .. CyrlVowel .. "])(" .. DIAER .. "?" .. MACRON .. "?)ӏ", "%1" .. DOTBELOW .. "%2") text = mw.ustring.gsub(text, "([аяАЯ])(" .. DOTBELOW .. "?)(" .. DIAER .. "?)" .. MACRON, "%1%3а%2%3") text = mw.ustring.gsub(text, "([еэЕЭ])(" .. DOTBELOW .. "?)(" .. DIAER .. "?)" .. MACRON, "%1%3э%2%3") text = mw.ustring.gsub(text, "([иИ])(" .. DOTBELOW .. "?)(" .. DIAER .. "?)" .. MACRON, "%1%3и%2%3") text = mw.ustring.gsub(text, "([ёЁоО])(" .. DOTBELOW .. "?)(" .. DIAER .. "?)" .. MACRON, "%1%3о%2%3") text = mw.ustring.gsub(text, "([уюУЮ])(" .. DOTBELOW .. "?)(" .. DIAER .. "?)" .. MACRON, "%1%3у%2%3") text = mw.ustring.gsub(text, "([ыЫ])(" .. DOTBELOW .. "?)(" .. DIAER .. "?)" .. MACRON, "%1%3ы%2%3") text = mw.ustring.gsub(text, "ᵸ", TILDE) -- Apply language-specific substitutions by iterating over each table in the language-specific submodule. For each one, create a temporary table that stores each substitution in lowercase and uppercase variants. Then, iterate over all substitutions. for _,i in ipairs(subs) do		local t = {} -- Create a temporary table, then iterate over all of them. for k, v in pairs(i) do			t[k] = v			t[mw.ustring.gsub(k, "^.", mw.ustring.upper)] = mw.ustring.gsub(v, "^.", mw.ustring.upper) end for letter, replacement in pairs(t) do			text = string.gsub(text, letter, replacement) end end -- Decompose and remove temporary breaking character. text = mw.ustring.gsub(mw.ustring.toNFD(text), br, "") -- When double letters both have certain diacritics, a modifier letter and/or an apostrophe, only show on the first or second for readability purposes. for letter in string.gmatch("abcdefghijklmnopqrstuvwxyzəɣıʔABCDEFGHIJKLMNOPQRSTUVWXYZƏƔɁʻˀ", UTF8_char) do text = mw.ustring.gsub(text, "(ᵏ?)" .. letter .. "([" .. noDoubleAccent .. "]?)([" .. noDoubleAccent .. "]?)([ʰʲˡʳˢʷˣˠ]?)([ʲʷ]?)(ʼ?)" .. "%1" .. mw.ustring.lower(letter) .. "%2%3%4%5%6", "%1" .. letter .. mw.ustring.lower(letter) .. "%2%3%4%5%6") end -- Reposition apostrophes and recompose. text = mw.ustring.toNFC(mw.ustring.gsub(mw.ustring.gsub(text, "ʼ([ʲʷ])", "%1ʼ"), "ʼ([ʲʷ])", "%1ʼ")) -- Remove consecutive ʲ/j and ʷ/w. return (mw.ustring.gsub(mw.ustring.gsub(text, "ʲ?jʲ?", "j"), "ʷ?wʷ?", "w")) end

return export