Pronunciation module for Tibetan. See {{bo-IPA}}.


local export = {}
local gsub = mw.ustring.gsub
local match = mw.ustring.match

function export.tidyRom(text)
	text = gsub(text, "([fhvw])(.?)", function(a, b) if b == "-" or b == "" or b == " " or b == "," then return "<sup>"..a.."</sup>"..b end end)
	return text
end

local iConv = {
	["b"] = "p", ["p"] = "pʰ",
	["d"] = "t", ["t"] = "tʰ",
	["gy"] = "c", ["ky"] = "cʰ",
	["g"] = "k", ["k"] = "kʰ",
	
	["z"] = "t͡s", ["c"] = "t͡sʰ",
	["zh"] = "ʈ͡ʂ", ["ch"] = "ʈ͡ʂʰ",
	["j"] = "t͡ɕ", ["q"] = "t͡ɕʰ",
	
	["m"] = "m", ["n"] = "n", ["ny"] = "ȵ", ["ng"] = "ŋ",
	["mh"] = "m̥", ["ngh"] = "ŋ̊", --limited
	
	["l"] = "l", ["lh"] = "ɬ",
	["f"] = "f", ["s"] = "s", ["h"] = "h",
	["sh"] = "ʂ", ["x"] = "ɕ", ["hy"] = "ç",
	
	["r"] = "ʐ",
	
	["w"] = "w", ["y"] = "j",
	
	[""] = "ʔ",
}

local fConv = {
	["i"] = "i", ["e"] = "e", ["a"] = "a", ["ac"] = "ə", ["o"] = "o", ["u"] = "u",
	
	["ii"] = "iː", ["ee"] = "eː", ["aa"] = "aː", ["acc"] = "əː", ["oo"] = "oː", ["uu"] = "uː",
	["ae"] = "ɛː", ["oe"] = "øː", ["ue"] = "yː", ["ie"] = "ɪː", ["uo"] = "ʊː",
	
	["iu"] = "iu", ["eu"] = "eu", ["acu"] = "əu",
	["ao"] = "ao", ["ua"] = "ua", ["ei"] = "ei", ["io"] = "io",
	
	["im"] = "im", ["em"] = "em", ["am"] = "am", ["acm"] = "əm", ["om"] = "om", ["um"] = "um",
	
	["in"] = "ĩ", ["en"] = "ẽ", ["an"] = "an", ["on"] = "on", ["un"] = "un",
	["aen"] = "ɛ̃", ["oen"] = "ø̃", ["uen"] = "ỹ",

	["ing"] = "iŋ", ["eng"] = "eŋ", ["ang"] = "aŋ", ["acng"] = "əŋ", ["ong"] = "oŋ", ["ung"] = "uŋ",
	
	["ib"] = "ip̚", ["eb"] = "ep̚", ["ab"] = "ap̚", ["acb"] = "əp̚", ["ob"] = "op̚", ["ub"] = "up̚",
	
	["ig"] = "i(k̚)ˀ", ["eg"] = "e(k̚)ˀ", ["acg"] = "ə(k̚)ˀ", ["ag"] = "a(k̚)ˀ", ["og"] = "o(k̚)ˀ", ["ug"] = "u(k̚)ˀ",
	
	["ir"] = "iː(ɹ)", ["er"] = "eː(ɹ)", ["ar"] = "aː(ɹ)", ["or"] = "oː(ɹ)", ["ur"] = "uː(ɹ)",
}

local tConv = {
	["f"] = "˥˥",
	["h"] = "˥˨",
	["v"] = "˩˨",
	["w"] = "˩˧˨",
	[""] = "ˑ",
}

function export.ipa(text)
	text = mw.ustring.lower(text)
	for word in mw.ustring.gmatch(text, "([a-z]+)") do
		local originalWord = word
		word = gsub(word, "^([^aeiou]*)([aeiou][aeioucmnbgr]*)([fhvw]?)$", function(initial, final, tone)
			return (iConv[initial] or initial) .. (fConv[final] or final) .. tConv[tone] end)
		text = gsub(text, originalWord, word, 1)
	end
	text = gsub(text, "-", ".")
	return text
end

function ipaFormat(word, no_intro)
	local part = mw.text.split(word, ",")
	return (no_intro and "" or "[[Wiktionary:International Phonetic Alphabet|IPA]]<sup>([[Appendix:Tibetan pronunciation|key]])</sup>: ") .. 
		'<span class=\"IPA\">/' .. table.concat(part, "/, /") .. '/</span>'
end

function export.show(frame)
	local args = frame:getParent().args
	local p, ipa, textShow, textHide = {}, {}, "", ""
	
	if args["otb"] ~= "-" then
		local otb_ipa = {}
		local lang = require("Module:languages").getByCode("bo")
		local page_title = lang:transliterate(args["word"] or mw.title.getCurrentTitle().text)
		if page_title then
			local single_letter = {
				["kh"] = "ġ", ["ch"] = "ċ", ["th"] = "ṫ", ["ph"] = "ṗ",
				["ng"] = "ŋ", ["ny"] = "ñ",
				["ts"] = "ʒ", ["dz"] = "ž",
				["zh"] = "ż", ["sh"] = "ṡ"
			}
			
			local voiceless_lateral = {
				["lh"] = "ĺ", ["hr"] = "ŕ"
			}
			
			local function voice(text)
				return match(text, "[kġcċtṫpṗʒǯṡshĺŕ]") and "voiceless" or "voiced"
			end
			
			local base_ipa = {
				["g"] = "ɡ", ["ġ"] = "kʰ",
				["c"] = "t͡ɕ", ["ċ"] = "t͡ɕʰ", ["j"] = "d͡ʑ", ["ñ"] = "ȵ",
				["ṫ"] = "tʰ",
				["ṗ"] = "pʰ",
				["ʒ"] = "t͡s", ["ǯ"] = "t͡sʰ", ["ž"] = "d͡z",
				["ż"] = "ʑ", ["'"] = "ɣ",
				["y"] = "j", 
				["ṡ"] = "ɕ",
				["ĺ"] = "l̥", ["ŕ"] = "r̥"
			}
			
			local syllable_structure = "^(b?)([dkgbmz'srl]?)(%.?)([kġgŋcċjñtṫdnpṗbmʒǯžwżz'yrlṡshĺŕʔ])([yr]?)(w?)([aeiouI])([gdbŋnms'rl]?)([sd]?)$"
			local voicing = { ["s"] = "z" }
			local devoicing = { ["b"] = "p", ["d"] = "t", ["g"] = "k" }
				
			local function initial_process(prefix, superscript, base)
				local prenasal = { ["kġgŋ"] = "ᵑ", ["cċjñtṫdnʒǯžwżz'yrlṡshĺŕʔ"] = "ⁿ", ["pṗbm"] = "ᵐ" }
				if superscript == "'" then
					for ensuing, nasal in pairs(prenasal) do
						superscript = match(base, "[" .. ensuing .. "]") and nasal or superscript
					end
				end
				return gsub(prefix .. superscript, ".", (voice(base) == "voiced" and voicing or devoicing)) .. (base_ipa[base] or base)
			end
			
			local function vowel_process(glide_a, glide_b, vowel, sep)
				local glide_ipa = { ["y"] = "ʲ", ["w"] = "ʷ" }
				local glide_sep_ipa = { ["y"] = "j", ["w"] = "ʷ" }
				local vowel_ipa = { ["I"] = "ᵻ" }
				return gsub(gsub(glide_a .. glide_b, ".", sep ~= "." and glide_ipa or glide_sep_ipa), "rʷ", "ʷr") .. gsub(vowel, ".", vowel_ipa)
			end
			
			local function coda_process(coda, suffix)
				coda = gsub(coda, "'", "(ɣ)")
				return (devoicing[coda] or coda) .. suffix
			end
			
			page_title = gsub(page_title, "tsh", "ǯ")
			for original, replaced in pairs(single_letter) do
				page_title = gsub(page_title, original, replaced)
			end
			page_title = gsub(page_title, "[lh][hr]", voiceless_lateral)
			
			for syllable in mw.text.gsplit(page_title, " ") do
				syllable = gsub(syllable, "^([aeiouI])", "ʔ%1")
				
				if match(syllable, syllable_structure) then
					syllable = gsub(syllable, syllable_structure, function(prefix, superscript, sep, base, glide_a, glide_b, vowel, coda, suffix)
						if match(base, "[yrw]") and glide_a .. glide_b == "" and prefix .. superscript ~= "" then
							glide_a, glide_b = match(base, "[yr]") or "", match(base, "w") or ""
							base = prefix .. superscript
							prefix, superscript = "", ""
						end
						return
							initial_process(prefix, superscript, base) ..
							vowel_process(glide_a, glide_b, vowel, sep) ..
							coda_process(coda, suffix)
						end)
					
					table.insert(otb_ipa, syllable)
				else
					erroneous = true
					break
				end
			end
			textShow = textShow .. "\n* [[w:Old Tibetan|Old Tibetan]]: " .. ipaFormat("*" .. table.concat(otb_ipa, "."), true)
			textHide = textHide .. (not erroneous and "* [[w:Old Tibetan|Old Tibetan]]:\n** " .. ipaFormat("*" .. table.concat(otb_ipa, ".")) .. " <span style=\"font-size:80%\">(reconstructed)</span>" or "")
		end
	end
	
	if args[1] then
		for index, item in ipairs(args) do
			table.insert(p, (item ~= "") and item or nil)
		end
		for _, transcription in ipairs(p) do
			table.insert(ipa, export.ipa(transcription))
		end
		textShow = textShow .. "\n* [[w:Standard Tibetan|Lhasa]]: " .. ipaFormat(table.concat(ipa, ","), true)
		textHide = textHide .. "\n* [[w:Central Tibetan language|Ü-Tsang]]" ..
			"\n** [[w:Tibetan pinyin|Tibetan pinyin]]: <span style=\"font-family:monospace;\" class=\"tr\">" .. export.tidyRom(table.concat(p, ", ")) .. "</span>" ..
			"\n** (''[[w:Standard Tibetan|Lhasa]]'') " .. ipaFormat(table.concat(ipa, ","))
	end

	if args["batang"] or args["dege"] then
		textHide = textHide .. "\n* [[w:Khams Tibetan|Khams]]"
		if args["batang"] then
			textShow = textShow .. "\n* [[w:Batang County|Batang]]: " .. ipaFormat(args["batang"], true)
			textHide = textHide .. "\n** (''[[w:Batang County|Batang]]'') " .. ipaFormat(args["batang"])
		end
		if args["dege"] then
			textShow = textShow .. "\n* [[w:Dêgê County|Dêgê]]: " .. ipaFormat(args["dege"], true)
			textHide = textHide .. "\n** (''[[w:Dêgê County|Dêgê]]'') " .. ipaFormat(args["dege"])
		end
		if args["gyaitang"] then
			textShow = textShow .. "\n* [[w:Jiantang|Gyaitang]]: " .. ipaFormat(args["gyaitang"], true)
			textHide = textHide .. "\n** (''[[w:Jiantang|Gyaitang]]'') " .. ipaFormat(args["gyaitang"])
		end
	end
	
	if args["zeku"] or args["labrang"] or args["arik"] or args["maqu"] or args["mdungnag"] then
		textHide = textHide .. "\n* [[w:Amdo Tibetan|Amdo]]"
		if args["zeku"] then
			textShow = textShow .. "\n* [[w:Zêkog County|Zêkog]]: " .. ipaFormat(args["zeku"], true)
			textHide = textHide .. "\n** (''[[w:Zêkog County|Zêkog]]'') " .. ipaFormat(args["zeku"])
		end
		if args["labrang"] then
			textShow = textShow .. "\n* [[w:Xiahe County|Bla-Brang]]: " .. ipaFormat(args["labrang"], true)
			textHide = textHide .. "\n** (''[[w:Xiahe County|Bla-Brang]]'') " .. ipaFormat(args["labrang"])
		end
		if args["arik"] then
			textShow = textShow .. "\n* [[w:Qilian County|Arik]]: " .. ipaFormat(args["arik"], true)
			textHide = textHide .. "\n** (''[[w:Qilian County|Arik]]'') " .. ipaFormat(args["arik"])
		end
		if args["maqu"] then
			textShow = textShow .. "\n* [[w:Maqu County|Maqu]]: " .. ipaFormat(args["maqu"], true)
			textHide = textHide .. "\n** (''[[w:Maqu County|Maqu]]'') " .. ipaFormat(args["maqu"])
		end
		if args["aba"] then
			textShow = textShow .. "\n* [[w:Ngawa County|Ngawa]]: " .. ipaFormat(args["aba"], true)
			textHide = textHide .. "\n** (''[[w:Ngawa County|Ngawa]]'') " .. ipaFormat(args["aba"])
		end
		if args["mdungnag"] then
			textShow = textShow .. "\n* [[w:Sunan Yugur Autonomous County|Mdung-Nag]]: " .. ipaFormat(args["mdungnag"], true)
			textHide = textHide .. "\n** (''[[w:Sunan Yugur Autonomous County|Mdung-Nag]]'') " .. ipaFormat(args["mdungnag"])
		end
	end

	if args["spiti"] then
		textShow = textShow .. "\n* [[w:Lahuli–Spiti language|Lahuli–Spiti]]: " .. ipaFormat(args["spiti"], true)
		textHide = textHide .. "\n* [[w:Lahuli–Spiti language|Lahuli–Spiti]]"
		textHide = textHide .. "\n** (''[[w:Lahaul and Spiti district|Spiti]]'') " .. ipaFormat(args["spiti"])
	end
	
	
	
	return '<div class="toccolours mw-collapsible mw-collapsed" style="width:400px; font-size:100%">' .. textShow ..
	'\n<div class="mw-collapsible-content">\n----\n' .. textHide .. '</div></div>'
end

return export