Module:yo-pron

From Wiktionary, the free dictionary
Jump to navigation Jump to search

This module is not to be directly used. It is used by Template:yo-IPA, see there for usage. While it works for the vast majority of words, the code still needs to be cleaned up.

Testcases

Module:yo-pron/testcases:

All tests passed. (refresh)

TextExpectedActualComments
test_pron:
PassedAdébáyọ̀ā.dé.bá.jɔ̀ā.dé.bá.jɔ̀
Passedẹẹ́sàn-ándínláàádọ́sàn-ánɛ̄ɛ́.sã̀ã́.dĩ́.láàá.dɔ́.sã̀ã́ɛ̄ɛ́.sã̀ã́.dĩ́.láàá.dɔ́.sã̀ã́
PassedẸ káàárọ̀ɛ̄ káàá.ɾɔ̀ɛ̄ káàá.ɾɔ̀
Passed
Passedkọ̀m̀pútàkɔ̀.ŋ̀.k͡pú.tàkɔ̀.ŋ̀.k͡pú.tà
Passednàánã̀ã́nã̀ã́
Passedoghóō.ɣóō.ɣó
Passedsẹngwàsɛ̃̄.ɡʷàsɛ̃̄.ɡʷà
Passedụ̀ṣàʊ̀.ʃàʊ̀.ʃà
Passedị̀kàràɪ̀.kà.ɾàɪ̀.kà.ɾà
Passedn̄ǹkanŋ̄ŋ̀.kã̄ŋ̄ŋ̀.kã̄
PassedṢáínàʃá.í.nàʃá.í.nà
PassedYorùbájō.ɾù.bájō.ɾù.bá
Passedmárùn-únmá.ɾũ̀ṹmá.ɾũ̀ṹ
Passedẹ̀ẹ́dẹ́gbẹ̀rùn-ún lọ́náɛ̀ɛ́.dɛ́.ɡ͡bɛ̀.ɾũ̀ṹ lɔ́.nã́ɛ̀ɛ́.dɛ́.ɡ͡bɛ̀.ɾũ̀ṹ lɔ́.nã́
Passedlálálá.lálá.lá
Passedlálálá.ꜜlálá.ꜜlá

local gsub = mw.ustring.gsub
local lower = mw.ustring.lower
local toNFC = mw.ustring.toNFC
local toNFD = mw.ustring.toNFD
local u = require("Module:string/char")

local export = {}

local m_IPA = require("Module:IPA")
local lang = require("Module:languages").getByCode("yo")

-- apply rsub() repeatedly until no change
local function gsub_repeatedly(term, foo, bar)
	while true do
		local new_term = gsub(term, foo, bar)
		if new_term == term then
			return term
		end
		term = new_term
	end
end

local MACRON = u(0x0304) -- macron =  ̄
local DOT = u(0x0323) -- dot =  ̣
local NASAL = u(0x0303) -- nasal =  ̃

local consonants = {
	["b"] = "b",
	["d"] = "d",
	["f"] = "f",
	["g"] = "ɡ",
	["gb"] = "ɡ͡b",
	["h"] = "h",
	["j"] = "d͡ʒ",
	["k"] = "k",
	["l"] = "l",
	["m"] = "m",
	["n"] = "n",
	["p"] = "k͡p",
	["r"] = "ɾ",
	["s"] = "s",
	["ṣ"] = "ʃ",
	["t"] = "t",
	["w"] = "w",
	["y"] = "j",
	
	["gh"] = "ɣ",
	["gw"] = "ɡʷ",
}

local vowels = {
	["a"] = "a",
	["e"] = "e",
	["ẹ"] = "ɛ",
	["i"] = "i",
	["o"] = "o",
	["ọ"] = "ɔ",
	["u"] = "u",
	
	["ị"] = "ɪ",
	["ụ"] = "ʊ",
}

local nasals = {
	["an"] = "ã",
	["ẹn"] = "ɛ̃",
	["in"] = "ĩ",
	["ọn"] = "ɔ̃",
	["un"] = "ũ",
	["m"] = "m",
	["n"] = "ŋ",
}

function export.IPA(text, loanword, downstep)
	text = lower(text)
	text = gsub(text, "%-", "z")
	text = toNFD(text)
	text = gsub(text, ".[" .. DOT .. "]", {
		["e" .. DOT] = "ẹ",
		["o" .. DOT] = "ọ",
		["s" .. DOT] = "ṣ",
		["i" .. DOT] = "ị",
		["u" .. DOT] = "ụ",
	})

	text = text .. "x"

	text = gsub(text, "%s+", " ")
	text = gsub(text, "^ ", "")
	text = gsub(text, " $", "")
	text = gsub(text, "\n", "")
	text = gsub(text, "'", "")
	text = gsub(text, "ẹ", "ɛ")
	text = gsub(text, "gb", "ɡ͡b")
	text = gsub(text, "gh", "ɣ")
	text = gsub(text, "gw", "ɡʷ")
	text = gsub(text, "g", "ɡ")
	text = gsub(text, "ị", "ɪ")
	text = gsub(text, "j", "d͡ʒ")
	text = gsub(text, "ọ", "ɔ")
	text = gsub(text, "p", "k͡p")
	text = gsub(text, "r", "ɾ")
	text = gsub(text, "ṣ", "ʃ")
	text = gsub(text, "ụ", "ʊ")
	text = gsub(text, "y", "j")

	text = gsub(text, "m([́̀̄])", "ŋ" .. "%1")
	text = gsub(text, "n([́̀̄])", "ŋ" .. "%1")

	text = gsub_repeatedly(text, "([aeɛiɪoɔuʊ])([aeɛiɪoɔuʊnbdfɡhjklmnŋɾsʃtwxzɣ ])", "%1" .. MACRON .. "%2")

	text = gsub(text, "([aɛiɪɔuʊ])([́̀̄])n([bdfɡhjklmnŋɾsʃtwxzɣ ])", "%1" .. NASAL .. "%2%3")

	--TODO: FIX LOANWORDS
	if not loanword then
		text = gsub(text, "n([aiɪuʊ])([́̀̄])", "n%1" .. NASAL .. "%2")
	end

	if not loanword then
		text = gsub(text, "m([iɪɔuʊ])([́̀̄])", "m%1" .. NASAL .. "%2")
	end
	text = gsub_repeatedly(text, "([aɛiɪɔuʊ])([̃])([́̀̄])([aɛiɔu])([́̀̄])", "%1%2%3%4" .. NASAL .. "%5")

	text = gsub(text, "([aeɛiɪoɔuʊ])([́̀̄])", "%1" .. "%2")

	text = gsub(text, "a([̃])([́̀̄])za","a" .. "%1" .. "%2a")
	text = gsub(text, "ɛ([̃])([́̀̄])zɛ","ɛ" .. "%1" .. "%2ɛ")
	text = gsub(text, "i([̃])([́̀̄])zi","i" .. "%1" .. "%2i")
	text = gsub(text, "ɪ([̃])([́̀̄])zɪ","ɪ" .. "%1" .. "%2ɪ")
	text = gsub(text, "ɔ([̃])([́̀̄])zɔ","ɔ" .. "%1" .. "%2ɔ")
	text = gsub(text, "u([̃])([́̀̄])zu","u" .. "%1" .. "%2u")
	text = gsub(text, "ʊ([̃])([́̀̄])zʊ","ʊ" .. "%1" .. "%2ʊ")

	text = gsub(text, "z", ".")

	-- Split into syllables
	text = gsub(text, "a([́̀̄])([eɛiɪoɔuʊbdfɡhjklmnŋɾsʃtwɣ])","a" .. "%1.%2")
	text = gsub(text, "a([̃])([́̀̄])([eɛiɪoɔuʊbdfɡhjklmnŋɾsʃtwɣ])","a" .. "%1" .. "%2.%3")
	text = gsub(text, "e([́̀̄])([aɛiɪoɔuʊbdfɡhjklmnŋɾsʃtwɣ])","e" .. "%1.%2")
	text = gsub(text, "ɛ([́̀̄])([aeiɪoɔuʊbdfɡhjklmnŋɾsʃtwɣ])","ɛ" .. "%1.%2")
	text = gsub(text, "ɛ([̃])([́̀̄])([aeiɪoɔuʊbdfɡhjklmnŋɾsʃtwɣ])","ɛ" .. "%1" .. "%2.%3")
	text = gsub(text, "i([́̀̄])([aeɛɪɔuʊbdfɡhjklmnŋɾsʃtwɣ])","i" .. "%1.%2")
	text = gsub(text, "i([̃])([́̀̄])([aeɛɪoɔuʊbdfɡhjklmnŋɾsʃtwɣ])","i" .. "%1" .. "%2.%3")
	text = gsub(text, "ɪ([́̀̄])([aeɛioɔuʊbdfɡhjklmnŋɾsʃtwɣ])","ɪ" .. "%1.%2")
	text = gsub(text, "ɪ([̃])([́̀̄])([aeɛioɔuʊbdfɡhjklmnŋɾsʃtwɣ])","ɪ" .. "%1" .. "%2.%3")
	text = gsub(text, "o([́̀̄])([aeɛiɪɔuʊbdfɡhjklmnŋɾsʃtwɣ])","o" .. "%1.%2")
	text = gsub(text, "ɔ([́̀̄])([aeɛiɪouʊbdfɡhjklmnŋɾsʃtwɣ])","ɔ" .. "%1.%2")
	text = gsub(text, "ɔ([̃])([́̀̄])([aeɛiɪouʊbdfɡhjklmnŋɾsʃtwɣ])","ɔ" .. "%1" .. "%2.%3")
	text = gsub(text, "u([́̀̄])([aeɛiɪɔoʊbdfɡhjklmnŋɾsʃtwɣ])","u" .. "%1.%2")
	text = gsub(text, "u([̃])([́̀̄])([aeɛiɪɔoʊbdfɡhjklmnŋɾsʃtwɣ])","u" .. "%1" .. "%2.%3")
	text = gsub(text, "ʊ([́̀̄])([aeɛiɪɔobdfɡhjklmnŋɾsʃtwɣ])","ʊ" .. "%1.%2")
	text = gsub(text, "ʊ([̃])([́̀̄])([aeɛiɪoɔubdfɡhjklmnŋɾsʃtwɣ])","ʊ" .. "%1" .. "%2.%3")
	text = gsub_repeatedly(text, "m([́̀̄])([aeɛiɪoɔuʊbdfɡhjklnŋɾsʃtwɣ])","m" .. "%1.%2")
	text = gsub_repeatedly(text, "ŋ([́̀̄])([aeɛiɪoɔuʊbdfɡhjklmnɾsʃtwɣ])","ŋ" .. "%1.%2")

	text = gsub(text, "x", "")
	
	-- Adds downstep ꜜ before provided syllable
	if downstep then
		downstep = tonumber(downstep)
		local i = 0
		local result = (text):gsub("[^.]+", function(syllable)
    		i = i + 1
    		if i == downstep then
        		return "ꜜ" .. syllable
    		end -- else leave it alone
		end)
		text = result
	end
		
	return toNFC(text)
end

function export.show(frame)
	local args = frame:getParent().args
	local p, results = {}, {}

	if args[1] then
		for _, item in ipairs(args) do
			table.insert(p, (item ~= "") and item or nil)
		end
	else
		error("Please provide a tone marked term.")
	end

	for _, text in ipairs(p) do
		if args["loan"] == "1" then
			table.insert(results, {pron = "/" .. export.IPA(text, true, args["downstep"]) .. "/", note = nil})
		else
			table.insert(results, {pron = "/" .. export.IPA(text, false, args["downstep"]) .. "/", note = nil})
		end
	end

	return m_IPA.format_IPA_full(lang, results)
end

return export