Module:szy-pron

--[=[ This module implements the templates.

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'] = 'i', ['u'] = 'u', ['e'] = 'ə', ['o'] = 'o', ['a'] = 'a', ['w'] = 'w', ['y'] = 'j', ['p'] = 'p', ['t'] = 't', ['k'] = 'k', ["'"] = 'ʡ', ["’"] = 'ʡ', ['b'] = 'b', ['d'] = 'd', ['s'] = 's', ['h'] = 'h', ['z'] = 'z', ['c'] = 'ʦ', ['m'] = 'm', ['ŋ'] = 'ŋ', ['n'] = 'n', ['g'] = 'g', ['l'] = '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[i], -1, -1), 1, true) and    --        (vowels:find(usub(syllables[i + 1], 1, 1), 1, true)) or    --         glides:find(usub(syllables[i + 1], 1, 1), 1, true)) then --        syllables[i + 1] = usub(syllables[i], -1, -1) .. syllables[i + 1] --        syllables[i] = usub(syllables[i], 1, -2) --    end -- end for i = 1, #syllables - 1 do   local last_char_of_current_syllable = usub(syllables[i], -1, -1) local first_char_of_next_syllable = usub(syllables[i + 1], 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[i + 1] = last_char_of_current_syllable .. syllables[i + 1] syllables[i] = usub(syllables[i], 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[i] = 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[i], c1) then syllables[i] = ugsub(syllables[i], c1, combs_ap[j]) end end -- /u/ tongue position lowering for j, c1 in ipairs(combs_du) do           if ufind(syllables[i], c1) then syllables[i] = ugsub(syllables[i], c1, combs_do[j]) end end -- /e/ voicelessness, rules should be checked further if ulen(syllables[i]) == 2 and not ufind(glides, usub(syllables[i], 1, 1)) and usub(syllables[i], 2, 2) == 'ə' and i ~= ulen(syllables[i]) - stress_idx + 1 then syllables[i] = usub(syllables[i], 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 - stress_idx + 1] = "ˈ" .. broad[#broad - stress_idx + 1] end if #narrow > 1 then narrow[#narrow - stress_idx + 1] = "ˈ" .. narrow[#narrow - stress_idx + 1] 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 text = ulower(word) local puncs = '[%.%,%;“”\"%?!%(%)%[%]]'   text = ugsub(text, puncs, ' ')

-- 拆分為多個單詞 local words = tsplit(text, ' ') local ipa_results, n_ipa_results = {}, {}

for _, word in ipairs(words) do       if word ~= "" then 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) table.insert(ipa_results, broad_str) table.insert(n_ipa_results, narrow_str) end end

local IPA_result = { ["broad"] = table.concat(ipa_results, ' '), ["narrow"] = table.concat(n_ipa_results, ' ') }   return IPA_result end

-- 更新後的 show 函數 function export.show(frame) local params = { [1] = {},       ["stress"] = {type = "number", default = 1}, ["pre"] = {}, ["bullets"] = {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 text = args[1] or mw.title.getCurrentTitle.text

local IPA_result = export.to_ipa(text, stress)

table.insert(results, { pron = "/" .. IPA_result["broad"] .. "/" }) table.insert(results, { pron = "[" .. IPA_result["narrow"] .. "]" })

return bullet .. pre .. m_IPA.format_IPA_full { lang = lang, items = results } end

return export