--[=[
This module implements the templates {{szy-pron}}.
Author: TongcyDai
]=]
local export = {}
local m_IPA = require("Module:IPA")
local lang = require("Module:languages").getByCode("szy")
local u = mw.ustring.char
local ufind = mw.ustring.find
local ugsub = mw.ustring.gsub
local tsplit = mw.text.split
local ulower = mw.ustring.lower
local usub = mw.ustring.sub
local ulen = mw.ustring.len
local ugmatch = mw.ustring.gmatch
local ulower = mw.ustring.lower
local vowels = "aiuoeə"
local glides = "jw"
local consonants = "ptkʡbdshzʦmlŋng"
local phoneme_map = {
= 'i', = 'u', = 'ə', = 'o', = 'a',
= 'w', = 'j',
= 'p', = 't', = 'k', = 'ʡ', = 'ʡ',
= 'b', = 'd', = 's', = 'h', = 'z',
= 'ʦ', = 'm', = 'ŋ', = 'n', = 'g', = 'l'
}
function export.mapping(word)
word = ugsub(word, 'ng', 'ŋ')
local ipa_word = ugsub(word, '.', phoneme_map)
return ipa_word
end
function export.to_broad_ipa(word)
local syllables = {}
local i = 1
local len = ulen(word)
while i <= len do
local syllable = ''
-- 'Consonant + Glide + Vowel'
if i + 2 <= len and consonants:find(usub(word, i, i), 1, true) and
glides:find(usub(word, i + 1, i + 1), 1, true) and
vowels:find(usub(word, i + 2, i + 2), 1, true) then
syllable = usub(word, i, i + 2)
i = i + 3
-- 'Consonant + Vowel + Glide'
elseif i + 2 <= len and consonants:find(usub(word, i, i), 1, true) and
vowels:find(usub(word, i + 1, i + 1), 1, true) and
glides:find(usub(word, i + 2, i + 2), 1, true) then
syllable = usub(word, i, i + 2)
i = i + 3
-- 'Consonant + Vowel + Consonant'
elseif i + 2 <= len and consonants:find(usub(word, i, i), 1, true) and
vowels:find(usub(word, i + 1, i + 1), 1, true) and
consonants:find(usub(word, i + 2, i + 2), 1, true) then
syllable = usub(word, i, i + 2)
i = i + 3
-- 'Glide + Vowel'
elseif i + 1 <= len and glides:find(usub(word, i, i), 1, true) and
vowels:find(usub(word, i + 1, i + 1), 1, true) then
syllable = usub(word, i, i + 1)
i = i + 2
-- 'Consonant + Vowel'
elseif i + 1 <= len and consonants:find(usub(word, i, i), 1, true) and
vowels:find(usub(word, i + 1, i + 1), 1, true) then
syllable = usub(word, i, i + 1)
i = i + 2
-- 'Vowel + Glide'
elseif i + 1 <= len and vowels:find(usub(word, i, i), 1, true) and
glides:find(usub(word, i + 1, i + 1), 1, true) then
syllable = usub(word, i, i + 1)
i = i + 2
-- 'Vowel + Consonant'
elseif i + 1 <= len and vowels:find(usub(word, i, i), 1, true) and
(i == len or consonants:find(usub(word, i + 1, i + 1), 1, true)) then
syllable = usub(word, i, i + 1)
i = i + 2
-- 'Vowel'
elseif vowels:find(usub(word, i, i), 1, true) then
syllable = usub(word, i, i)
i = i + 1
end
if syllable ~= '' then
table.insert(syllables, syllable)
else
-- If no rule applies, just move to the next character
i = i + 1
mw.log('Error: No matching rule for syllable at position ' .. i)
end
end
-- Rearrange syllables to accommodate the position of consonants
-- for i = 1, #syllables - 1 do
-- if (consonants:find(usub(syllables, -1, -1), 1, true) and
-- (vowels:find(usub(syllables, 1, 1), 1, true)) or
-- glides:find(usub(syllables, 1, 1), 1, true)) then
-- syllables = usub(syllables, -1, -1) .. syllables
-- syllables = usub(syllables, 1, -2)
-- end
-- end
for i = 1, #syllables - 1 do
local last_char_of_current_syllable = usub(syllables, -1, -1)
local first_char_of_next_syllable = usub(syllables, 1, 1)
if consonants:find(last_char_of_current_syllable, 1, true) and
(vowels:find(first_char_of_next_syllable, 1, true) or glides:find(first_char_of_next_syllable, 1, true)) or
glides:find(last_char_of_current_syllable, 1, true) and vowels:find(first_char_of_next_syllable, 1, true) then
syllables = last_char_of_current_syllable .. syllables
syllables = usub(syllables, 1, -2)
end
end
return syllables
end
function export.fix_ipa_symbol(ipa_str)
ipa_str = ugsub(ipa_str, 'ʨ', 't͡ɕ')
ipa_str = ugsub(ipa_str, 'ʦ', 't͡s')
ipa_str = ugsub(ipa_str, 'g', 'ɡ')
return ipa_str
end
function export.to_narrow_ipa(old_syllables, stress_idx)
local syllables = {}
for i, v in ipairs(old_syllables) do
syllables = v
end
local stress_idx = stress_idx or 1
local alveolars = 'szʦ'
local alveolo_palatal = 'ɕʑʨ'
local dorsal_guttural = 'hkʡ'
local fronts = 'ij'
local glides = 'jw'
local combs_al = {}
local combs_ap = {}
local combs_du = {}
local combs_do = {}
for a in ugmatch(alveolars, '.') do
for f in ugmatch(fronts, '.') do
table.insert(combs_al, a .. f)
if a == 's' then
table.insert(combs_ap, 'ɕ' .. f)
elseif a == 'z' then
table.insert(combs_ap, 'ʑ' .. f)
elseif a == 'ʦ' then
table.insert(combs_ap, 'ʨ' .. f)
end
end
end
for d in ugmatch(dorsal_guttural, ".") do
table.insert(combs_du, 'u' .. d)
table.insert(combs_do, 'o' .. d)
end
for i = 1, #syllables do
-- palatalization
for j, c1 in ipairs(combs_al) do
if ufind(syllables, c1) then
syllables = ugsub(syllables, c1, combs_ap)
end
end
-- /u/ tongue position lowering
for j, c1 in ipairs(combs_du) do
if ufind(syllables, c1) then
syllables = ugsub(syllables, c1, combs_do)
end
end
-- /e/ voicelessness, rules should be checked further
if ulen(syllables) == 2 and not ufind(glides, usub(syllables, 1, 1)) and usub(syllables, 2, 2) == 'ə' and i ~= ulen(syllables) - stress_idx + 1 then
syllables = usub(syllables, 1, 1) .. '(ə)'
end
-- /i, u/ + V (not /a/) = /j, w/ + V, already shown in orthography
-- /i, u/ + /a/ = /ija, uwa/, already shown in orthography
end
return syllables
end
function export.stress_and_format(broad, narrow, stress_idx)
stress_idx = stress_idx or 1
if #broad > 1 then
broad = "ˈ" .. broad
end
if #narrow > 1 then
narrow = "ˈ" .. narrow
end
local broad_str = export.fix_ipa_symbol(table.concat(broad, '.'))
local narrow_str = export.fix_ipa_symbol(table.concat(narrow, '.'))
return broad_str, narrow_str
end
function export.to_ipa(word, stress)
local ipa = export.mapping(word)
local broad_ipa = export.to_broad_ipa(ipa)
local narrow_ipa = export.to_narrow_ipa(broad_ipa, stress)
local broad_str, narrow_str = export.stress_and_format(broad_ipa, narrow_ipa, stress)
return broad_str, narrow_str
end
function export.show(frame)
local params = {
= {},
= {type = "number", default = 1},
= {},
= {type = "number", default = 1},
}
local parargs = frame:getParent().args
local args = require("Module:parameters").process(parargs, params)
local pre = args.pre and args.pre .. " " or ""
local bullet = (args.bullets ~= 0) and "* " or ""
local stress = args.stress
local results = {}
local ipa_results, n_ipa_results = {}, {}
local text = ulower(args or mw.title.getCurrentTitle().text)
local puncs = ']'
text = ugsub(text, puncs, ' ')
local words = tsplit(text, ' ')
for _, word in ipairs(words) do
if word ~= "" then
local ipa, n_ipa = export.to_ipa(word, stress)
table.insert(ipa_results, ipa)
table.insert(n_ipa_results, n_ipa)
end
end
local ipa_str = "/" .. table.concat(ipa_results, ' ') .. "/"
local n_ipa_str = ""
table.insert(results, { pron = ipa_str })
table.insert(results, { pron = n_ipa_str })
return bullet .. pre .. m_IPA.format_IPA_full { lang = lang, items = results }
end
return export