Module:szy-pron
- The following documentation is located at Module:szy-pron/documentation. [edit] Categories were auto-generated by Module:module categorization. [edit]
- Useful links: subpage list • links • transclusions • testcases • sandbox
Sakizaya pronunciation module. See Template:szy-IPA for usage and examples.
--[=[
This module implements the templates {{szy-IPA}}.
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