Implements {{kpv-IPA}}
.
local export = {}
local langcode = "kpv"
local vowel = ""
local vowel_soft = ""
local vowel_prej = ""
local vowel_accent = "́"
local vowel_phonemic = {
= "a", = "e", = "o", = "i",
= "i", = "o", = "ɘ", = "u",
= "ɯ", = "e", = "u", = "a"
}
local vowel_phonetic = {
= "ä", = "o̞", = "o̞", = "ɯ̈", = "ä"
}
local consonant = ""
local consonant_voiced = ""
local consonant_unvoiced = ""
local consonant_devoice = {
= "п",
= "т",
}
-- normal, soft
local consonant_phonemic = {
= { "b", "b" },
= { "ʋ", "ʋ" },
= { "ɡ", "ɡ" },
= { "d", "ɟ" },
= { "d͡ʑ", "d͡ʑ" },
= { "d͡ʒ", "d͡ʒ" },
= { "ʒ", "ʒ" },
= { "z", "ʑ" },
= { "j", "j" },
= { "k", "k" },
= { "l", "ʎ" },
= { "m", "m" },
= { "n", "ɲ" },
= { "p", "p" },
= { "r", "r" },
= { "s", "ɕ" },
= { "t", "c" },
= { "t͡ʃ", "t͡ʃ" },
= { "f", "f" },
= { "x", "x" },
= { "t͡s", "t͡s" },
= { "t͡ɕ", "t͡ɕ" },
= { "ʃ", "ʃ" },
= { "ʃː", "ʃː" },
}
-- normal, soft, voiced, voiced+soft
local consonant_phonetic = {
= { "d͡ʒ̺", "d͡ʒ̺", "d͡ʒ̺", "d͡ʒ̺" },
= { "ʒ̺", "ʒ̺", "ʒ̺", "ʒ̺" },
= { "k", "k", "ɡ", "ɡ" },
= { "ɫ", "ʎ", "ɫ", "ʎ" },
= { "p", "p", "b", "b" },
= { "s", "ɕ", "z", "ʑ" },
= { "t", "c", "d", "ɟ" },
= { "t͡ʃ̺", "t͡ʃ̺", "d͡ʒ̺", "d͡ʒ̺" },
= { "t͡s", "t͡s", "d͡z", "d͡z" },
= { "t͡ɕ", "t͡ɕ", "d͡ʑ", "d͡ʑ" },
= { "ʃ̺", "ʃ̺", "ʃ̺", "ʃ̺" },
= { "ʃ̺ː", "ʃ̺ː", "ʃ̺ː", "ʃ̺ː" },
}
local vowl = ""
local vowld = ""
local cons = ""
local consd = ""
local affricate1 = ""
local affricate2b = ""
local affricate2 = "͡" .. affricate2b
local postalveolar = {
= "ʃ̺",
= "ʒ̺",
= "ʒ̺",
= "ʒ̺",
}
local function convert_vowel(c, is_phonetic)
if is_phonetic and vowel_phonetic then
return vowel_phonetic
end
return vowel_phonemic
end
local function convert_consonant(c, is_phonetic, is_soft, is_voiced)
local num = is_soft and 2 or 1
if is_phonetic and consonant_phonetic then
if is_voiced then
num = num + 2
end
return consonant_phonetic
end
return consonant_phonemic
end
local digraphs = {
= "зж",
= "ш"
}
local function split_phonemes(s)
local phonemes = { }
local index = 1
local len = mw.ustring.len(s)
local stress_at = 1
if mw.ustring.match(s, "^-") then
table.insert(phonemes, { nil, "-" })
stress_at = nil
index = 2
end
while index <= len do
if mw.ustring.match(s, "^" .. vowel .. vowel_accent .. "?", index) then
local v = mw.ustring.match(s, "^(" .. vowel .. vowel_accent .. "?)", index)
table.insert(phonemes, { "v", v })
if mw.ustring.find(v, vowel_accent) then
stress_at = nil
end
index = index + mw.ustring.len(v)
elseif mw.ustring.match(s, "^" .. consonant, index) then
local c = mw.ustring.match(s, "^" .. consonant, index)
-- digraphs
if digraphs then
local cc = mw.ustring.match(s, "^" .. c .. " .. "]", index)
if cc then c = cc end
end
table.insert(phonemes, { "c", c })
index = index + mw.ustring.len(c)
elseif mw.ustring.match(s, "^ь", index) then
table.insert(phonemes, { "s", nil })
index = index + 1
elseif mw.ustring.match(s, "^ъ", index) then
table.insert(phonemes, { "h", nil})
index = index + 1
elseif mw.ustring.match(s, "^-", index) then
if index < len then
table.insert(phonemes, { nil, "." })
else
table.insert(phonemes, { nil, "-" })
end
index = index + 1
elseif mw.ustring.match(s, "^%s", index) then
if stress_at then
table.insert(phonemes, stress_at, { nil, "ˈ" })
end
table.insert(phonemes, { "w", mw.ustring.sub(s, index, index) })
stress_at = #phonemes + 1
index = index + 1
else -- something else...
table.insert(phonemes, { nil, mw.ustring.sub(s, index, index) })
index = index + 1
end
end
if stress_at then
table.insert(phonemes, stress_at, { nil, "ˈ" })
end
return phonemes
end
local function is_next_consonant(phonemes, i, consonant)
i = i + 1
while i <= #phonemes do
local type, x = phonemes, phonemes
if type == "v" then return false end
if type == "c" then return mw.ustring.match(x, consonant) end
i = i + 1
end
return false
end
local function has_next_consonant(phonemes, i, consonant)
i = i + 1
while i <= #phonemes do
local type, x = phonemes, phonemes
if type == "v" then return false end
if type == "c" then
if mw.ustring.match(x, consonant) then
return true
end
end
i = i + 1
end
return false
end
local function handle_long_digraphs(s)
s = mw.ustring.gsub(s, "()%1()", "%1ь%1%2")
for k, v in pairs(digraphs) do
s = mw.ustring.gsub(s, k .. k .. "()", k .. "%1" .. k .. "%1")
end
return s
end
function export.convert(s, is_phonetic)
local phonemes = split_phonemes(handle_long_digraphs(s))
local result = ""
local stress_preinserted = false
for i, phoneme in ipairs(phonemes) do
local type, x = phoneme, phoneme
if type == "v" then
-- vowel
local v, s = mw.ustring.match(x, "(" .. vowel .. ")(" .. vowel_accent .. "?)", index)
if #s > 0 and not stress_preinserted then
result = result .. "ˈ"
end
stress_preinserted = false
if (i < 2 or phonemes ~= "c") and mw.ustring.match(v, vowel_prej) then
result = result .. "j"
end
result = result .. convert_vowel(v, is_phonetic)
elseif type == "c" then
-- consonant
local c = x
local soft = false
local voiced = false
if i < #phonemes then
soft = (phonemes == "v" and mw.ustring.match(phonemes, "^" .. vowel_soft)) or phonemes == "s"
if is_phonetic then
if has_next_consonant(phonemes, i, "^" .. consonant_voiced) then
voiced = true
elseif consonant_devoice and is_next_consonant(phonemes, i, "^" .. consonant_unvoiced) then
c = consonant_devoice
end
end
if phonemes == "v" and mw.ustring.find(phonemes, vowel_accent) then
result = result .. "ˈ"
stress_preinserted = true
end
end
result = result .. convert_consonant(c, is_phonetic, soft, voiced)
elseif type == "s" then
-- soft sign, ignore here
elseif type == "h" then
-- hard sign, ignore here
elseif type == "w" then
-- whitespace
result = result .. x
elseif not type then
-- anything else
result = result .. x
end
end
if is_phonetic then
-- assimilation of /s/ and /z/ to following /ʃ/, /ʒ/ or affricate with either
result = mw.ustring.gsub(result, "(ʲ?)(*)(" .. consd .. "*ʲ?)",
function (orig, space, palatal)
return postalveolar .. space .. palatal
end)
result = mw.ustring.gsub(result, "(ʲ?)(*)(" .. affricate1 .. "͡)(" .. affricate2b .. consd .. "*ʲ?)",
function (orig, space, plosive, palatal)
return postalveolar .. space .. plosive .. palatal
end)
end
-- long consonants
result = mw.ustring.gsub(result, "(" .. affricate1 .. affricate2 .. consd .. "*ʲ?)%1", "%1ː")
if is_phonetic then
result = mw.ustring.gsub(result, "(" .. affricate1 .. ")%1(" .. affricate2 .. consd .. "*ʲ?)", "%1%2ː")
end
result = mw.ustring.gsub(result, "(" .. cons .. ")%1()", "%1ː%2")
result = mw.ustring.gsub(result, "(" .. cons .. ")%1$", "%1ː")
result = mw.ustring.gsub(result, "(" .. vowl .. vowld .. "*)%1", "%1ː")
return result
end
function export.main(frame)
local title = mw.title.getCurrentTitle().text
if type(frame) == "table" then
title = frame:getParent().args or title
end
local phonemic = export.convert(mw.ustring.lower(title), false)
local phonetic = export.convert(mw.ustring.lower(title), true)
return require("Module:IPA").format_IPA_full {
lang = require("Module:languages").getByCode(langcode),
items = {
{pron = "/" .. phonemic .. "/"},
{pron = ""}
},
}
end
return export