local export = {}
local m_IPA = require("Module:IPA")
local lang = require("Module:languages").getByCode("sjd")
local rsub = mw.ustring.gsub
local rlower = mw.ustring.lower
local macron = mw.ustring.char(0x0304)
local V = "[aɒeɛiuo]ː?" -- vowels
local C = "[bvɡdžzjklʎmnɲŋprstfxhʃɕ]ʲ?" -- consonants
local phon = {
-- consonants
["б"]="b", ["в"]="v", ["г"]="ɡ", ["д"]="d", ["ж"]="ʒ", ["з"]="z",
["й"]="j", ["ҋ"]="j̥", ["ј"]="j̥", ["һ"]="h", ["'"]="h", ["к"]="k",
["л"]="l", ["ӆ"]="l̥", ["м"]="m", ["ӎ"]="m̥", ["н"]="n", ["ӊ"]="n̥",
["ӈ"]="ŋ", ["п"]="p", ["р"]="r", ["ҏ"]="r̥", ["с"]="s", ["т"]="t",
["ф"]="f", ["х"]="x", ["ц"]="ts", ["ч"]="tʃ", ["ш"]="ʃ", ["щ"]="ɕ",
-- vowels
["оа"]="ɒ", ["а"]="a", ["и"]="i", ["о"]="o", ["у"]="u", ["ӯ"]="uː",
["э"]="ɛ", ["ы"]="ɨ", ["ъ"]="j", ["ӣ"]="iː",
}
local function phonemic(text)
text = rlower(text)
-- general phonology
text = rsub(text, ".", phon)
-- palatalization
text = mw.ustring.gsub(text, "([Nn])%1ь", "ɲː")
text = mw.ustring.gsub(text, "([Nn])ь", "ɲ")
text = mw.ustring.gsub(text, "([bvɡdʒzklmnŋprstfxһʒʃ])ь", "%1ʲ")
text = mw.ustring.gsub(text, "([bvɡdʒzklmnn̥ŋprstfxһʒʃ])ҍ", "%1ʲ")
-- Some consonants are affected if the preceding one is palatalized:
text = mw.ustring.gsub(text, "([bɡdvlmnŋɲps])ʲ([vlnprst])", "%1ʲ%2ʲ")
text = mw.ustring.gsub(text, "h([ptk])ʲ", "hʲ%1ʲ")
text = mw.ustring.gsub(text, "xxʲ([ptk])", "xxʲ%1ʲ")
text = mw.ustring.gsub(text, "([bdɡ])([ptk])ʲ", "%1ʲ%2ʲ") --semi-voiced geminates bp, dt, gk
-- n,d,t preceding "semi-soft" ӓ and ӭ
text = mw.ustring.gsub(text, "([NnDdTt])%1ӓ", "%1ːʲa")
text = mw.ustring.gsub(text, "([NnDdTt])ӓ", "%1ʲa")
text = mw.ustring.gsub(text, "([NnDdTt])%1ӭ", "%1ːʲɛ")
text = mw.ustring.gsub(text, "([NnDdTt])ӭ", "%1ʲɛ")
-- palatal н/ɲ + vowels
text = mw.ustring.gsub(text, "([Nn])%1я", "ɲːa")
text = mw.ustring.gsub(text, "([Nn])я", "ɲa")
text = mw.ustring.gsub(text, "([Nn])%1е", "ɲːe")
text = mw.ustring.gsub(text, "([Nn])е", "ɲe")
text = mw.ustring.gsub(text, "([Nn])%1ё", "ɲːo")
text = mw.ustring.gsub(text, "([Nn])ё", "ɲo")
text = mw.ustring.gsub(text, "([Nn])%1и", "ɲːi")
text = mw.ustring.gsub(text, "([Nn])и", "ɲi")
text = mw.ustring.gsub(text, "([Nn])%1у", "ɲːu")
text = mw.ustring.gsub(text, "([Nn])ю", "ɲu")
text = mw.ustring.gsub(text, "llʲj", "ʎː") -- palatal ʎ
text = mw.ustring.gsub(text, "lʲj", "ʎ")
text = mw.ustring.gsub(text, "llʲ", "lʲː") -- palatalized l
text = mw.ustring.gsub(text, "ll", "lː")
-- consonant-ъ-consonant (creates a syllable boundary)
text = mw.ustring.gsub(text, "([bvlmnst])j%1", "%1.%1") -- CjC → C.C
-- j + vowels
--е̄/е
text = mw.ustring.gsub(text, "^" .. "([Ее])" .. macron, "ji̯e") -- initial е̄
text = mw.ustring.gsub(text, "(" .. C .. ")([Ее])" .. macron, "%1i̯e") -- е̄ following a consonant
text = mw.ustring.gsub(text, "^" .. "([Ее])", "je")
text = mw.ustring.gsub(text, "jе", "jje") -- replaces cyrillic е after j with je
text = mw.ustring.gsub(text, "(" .. C .. ")([Ее])", "%1ʲe")
--я̄/я
text = mw.ustring.gsub(text, "^" .. "([Яя])" .. macron, "je̯a")
text = mw.ustring.gsub(text, "([Яя])" .. macron, "e̯a")
text = mw.ustring.gsub(text, "^" .. "([Яя])", "ja")
text = mw.ustring.gsub(text, "([Яя])", "ʲa")
-- ӣ, ё, ю̄, ю
text = mw.ustring.gsub(text, "^" .. "([Ӣӣ])", "jiː")
text = mw.ustring.gsub(text, "^" .. "([Ёё])", "jo")
text = mw.ustring.gsub(text, "([Ёё])", "ʲo")
text = mw.ustring.gsub(text, "^" .. "([Юю])" .. macron, "juː")
text = mw.ustring.gsub(text, "^" .. "([Юю])", "ju")
text = mw.ustring.gsub(text, "([Юю])", "ʲu")
-- long vowels
text = rsub(text, "([aɒeɛiuo])̄" .. macron, "%1ː")
text = rsub(text, "([iu])M", "%1ː")
-- long consonants
text = mw.ustring.gsub(text, "([bvɡdʒzjklmnŋrstfxʃɕ])%1ʲ", "%1ʲː")
text = mw.ustring.gsub(text, "([bvɡdʒzjklmnŋrstfxʃɕ])%1", "%1ː")
text = mw.ustring.gsub(text, "(j̥)%1", "%1ː")
text = mw.ustring.gsub(text, "(l̥)%1", "%1ː")
text = mw.ustring.gsub(text, "(m̥)%1", "%1ː")
text = mw.ustring.gsub(text, "(n̥)%1", "%1ː")
text = mw.ustring.gsub(text, "(r̥)%1", "%1ː")
-- bringing everything into the proper form
-- affricates
text = rsub(text, "ts", "t͡s")
text = rsub(text, "t͡st͡s", "t͡sː")
text = rsub(text, "t͡sʲt͡sʲ", "t͡sʲː")
text = rsub(text, "tʃ", "t͡ʃʲ")
text = rsub(text, "t͡ʃʲt͡ʃʲ", "t͡ʃʲː")
text = rsub(text, "dz", "d͡z")
text = rsub(text, "dž", "d͡ʒ")
text = rsub(text, "dʒʲ", "d͡ʒʲ")
-- diphtongs
text = rsub(text, "ua", "u̯a")
text = rsub(text, "uɛ", "u̯ɛ")
text = rsub(text, "uo", "u̯o")
-- fixing possible mistakes
text = rsub(text, "oa", "ɒ") -- oa → ɒ
text = rsub(text, "oa" .. macron, "ɒː")
text = rsub(text, "е", "e") -- replacing the remaining cyrillic е's with latin
text = rsub(text, "(".. macron ..")", "ː") -- replacing possible remaining macrons
text = rsub(text, "ːʲ", "ʲː")
text = rsub(text, "jʲ", "j")
text = rsub(text, "ɲʲ", "ɲ")
text = rsub(text, "ʎʲ", "ʎ")
text = rsub(text, "lʲʲ", "ʎː")
text = rsub(text, "tʲs", "t͡s")
-- stress (used in words with 2+ syllables only, this needs to be replaced with something decent – it looks awful (and works too)
--CVCCV
text = rsub(text, "^" .. "(" .. C .. ")(" .. V .. ")(" .. C .. ").(" .. C .. ")(" .. V .. ")", "ˈ%1%2%3%4%5")
--CVVCCV (for diphtongs)
text = rsub(text, "^" .. "(" .. C .. ")(" .. V .. ")(" .. V .. ")(" .. C .. ")(" .. C .. ")(" .. V .. ")", "ˈ%1%2%3%4%5%6")
--VCV
text = rsub(text, "^" .. "(" .. V .. ")(" .. C .. ")(" .. V .. ")", "ˈ%1%2%3")
text = rsub(text, "^" .. "(" .. V .. ")(" .. C .. ")ː(" .. V .. ")", "ˈ%1%2ː%3")
--VCCV
text = rsub(text, "^" .. "(" .. V .. ")(" .. C .. ")(" .. C .. ")(" .. V .. ")", "ˈ%1%2%3%4")
text = rsub(text, "^" .. "(" .. V .. ")(" .. C .. ")ː(" .. V .. ")", "ˈ%1%2ː%3")
--VCCCV
text = rsub(text, "^" .. "(" .. V .. ")(" .. C .. ")(" .. C .. ")(" .. C .. ")(" .. V .. ")", "ˈ%1%2%3%4%5")
text = rsub(text, "^" .. "(" .. V .. ")(" .. C .. ")(" .. C .. ")(" .. C .. ")ː(" .. V .. ")", "ˈ%1%2%3%4ː%5")
--VVCCV
text = rsub(text, "^" .. "(" .. V .. ")(" .. V .. ")(" .. C .. ")(" .. C .. ")(" .. V .. ")", "ˈ%1%2%3%4%5")
text = rsub(text, "ˈ%-", "-")
-- (secondary stress should be implemented later for more complex words)
return text
end
function export.IPA(frame)
local words = {}
for _, word in ipairs(frame:getParent().args) do
table.insert(words, word)
end
if #words == 0 then
words = {mw.title.getCurrentTitle().text}
end
local IPA_results = {}
for _, word in ipairs(words) do
table.insert(IPA_results, { pron = "/" .. phonemic(word) .. "/" })
end
return m_IPA.format_IPA_full(lang, IPA_results)
end
return export