|
|
Line 1: |
Line 1: |
| local export = {}
| | (''Standard Zemljask'') [[w:IPA chart|IPA]]<sup>([[IPA chart|key]])</sup>: {{IPA|[{{{1}}}]}}<noinclude>[[Category:Contionary templates]][[Category:Zemljask Table Templates|I]][[Category:Templates]]</noinclude> |
| | |
| local m_params = require("Module:parameters")
| |
| local m_IPA = require("Module:IPA")
| |
| local m_syllables = require("Module:syllables")
| |
| local m_template_link = require("Module:template link")
| |
| | |
| local lang = require("Module:languages").getByCode("cs")
| |
| local sc = require("Module:scripts").getByCode("Latn")
| |
| | |
| function export.tag_text(text, face)
| |
| return require("Module:script utilities").tag_text(text, lang, sc, face)
| |
| end
| |
| | |
| function export.link(term, face)
| |
| return require("Module:links").full_link(
| |
| { term = term, lang = lang, sc = sc }, face
| |
| )
| |
| end
| |
| | |
| local U = mw.ustring.char
| |
| local sub = mw.ustring.sub
| |
| local gsub = mw.ustring.gsub
| |
| local match = mw.ustring.match
| |
| local gmatch = mw.ustring.gmatch
| |
| local find = mw.ustring.find
| |
| | |
| local long = "ː"
| |
| local nonsyllabic = U(0x32F) -- inverted breve below
| |
| local syllabic = U(0x0329)
| |
| local syllabic_below = U(0x030D)
| |
| local raised = U(0x31D) -- uptack below
| |
| local voiceless = U(0x30A) -- ring above
| |
| local caron = U(0x30C) -- combining caron
| |
| local tie = U(0x361) -- combining double inverted breve
| |
| local primary_stress = "ˈ"
| |
| local secondary_stress = "ˌ"
| |
| | |
| local data = {
| |
| ["c"] = "t" .. tie .. "s",
| |
| ["č"] = "t" .. tie .. "ʃ",
| |
| ["dź"] = "d" .. tie .. "ʑ",
| |
| ["e"] = "e",
| |
| ["è"] = "ɛ",
| |
| ["g"] = "ɡ",
| |
| ["h"] = "x",
| |
| ["i"] = "i",
| |
| ["nj"] = "ɲ",
| |
| ["q"] = "k",
| |
| ["š"] = "ʃ",
| |
| ["t"] = "t",
| |
| ["ć"] = "t" .. tie .. "ɕ",
| |
| ["x"] = "ks",
| |
| ["y"] = "ɪ",
| |
| ["ž"] = "ʒ",
| |
| ["ai"] = "ɛ" .. long,
| |
| ["au"] = "ɔ" .. long,
| |
| ["\""] = primary_stress,
| |
| ["%"] = secondary_stress,
| |
| ["?"] = "ʔ",
| |
| }
| |
| | |
| -- Add data["a"] = "a", data["b"] = "b", etc.
| |
| for character in gmatch("abdfjklmnoprstuvz ", ".") do
| |
| data[character] = character
| |
| end
| |
| | |
| --[[ This allows multiple-character sounds to be replaced
| |
| with single characters to make them easier to process. ]]
| |
| | |
| local multiple_to_single = {
| |
| ["t" .. tie .. "s" ] = "ʦ",
| |
| ["t" .. tie .. "ɕ" ] = "ʨ",
| |
| ["d" .. tie .. "ʑ" ] = "ʥ",
| |
| ["t" .. tie .. "ʃ" ] = "ʧ",
| |
| ["d" .. tie .. "z" ] = "ʣ",
| |
| ["d" .. tie .. "ʒ" ] = "ʤ",
| |
| }
| |
| | |
| --[[ "voiceless" and "voiced" are obstruents only;
| |
| sonorants are not involved in voicing assimilation. ]]
| |
| | |
| -- ʦ, ʧ, "ṙ" replace t͡s, t͡ʃ, r̝̊
| |
| local voiceless = { "p", "t", "k", "f", "s", "ʃ", "x", "ʦ", "ʧ", "ʨ", "ʔ" }
| |
| -- "ʣ", ʤ, ř replace d͡z, d͡ʒ, r̝
| |
| local voiced = { "b", "d", "ʥ", "ɡ", "v", "z", "ʒ", "ʣ", "ʤ" }
| |
| local sonorants = { "m", "n", "ɲ", "r", "l", "j", }
| |
| local consonant = "[" .. table.concat(sonorants) .. "ŋ"
| |
| .. table.concat(voiceless) .. table.concat(voiced) .. "]"
| |
| assimil_consonants = {}
| |
| assimil_consonants.voiceless = voiceless
| |
| assimil_consonants.voiced = voiced
| |
| | |
| local features = {}
| |
| local indices = {}
| |
| for index, consonant in pairs(voiceless) do
| |
| if not features[consonant] then
| |
| features[consonant] = {}
| |
| end
| |
| features[consonant]["voicing"] = "voiceless"
| |
| indices[consonant] = index
| |
| end
| |
| | |
| for index, consonant in pairs (voiced) do
| |
| if not features[consonant] then
| |
| features[consonant] = {}
| |
| end
| |
| features[consonant]["voicing"] = "voiced"
| |
| indices[consonant] = index
| |
| end
| |
|
| |
| local short_vowel = "[aeɛiɪou]"
| |
| local long_vowel = "[ɛɔ]" .. long
| |
| local syllabic_consonant = "[mnrl]" .. syllabic
| |
| | |
| -- all but v and r̝
| |
| local causing_assimilation =
| |
| gsub(
| |
| "[" .. table.concat(voiceless) .. table.concat(voiced) .. "ʔ]",
| |
| "[vř]",
| |
| ""
| |
| )
| |
| | |
| local assimilable = "[" .. table.concat(voiceless):gsub("ʔ", "") .. table.concat(voiced) .. "]"
| |
| | |
| local function regressively_assimilate(IPA)
| |
| IPA = gsub(
| |
| IPA,
| |
| "(" .. assimilable .. "+)(" .. causing_assimilation .. ")",
| |
| function (assimilated, assimilator)
| |
| local voicing = features[assimilator] and features[assimilator].voicing
| |
| or error('The consonant "' .. consonant
| |
| .. '" is not recognized by the function "regressively_assimilate".')
| |
| return gsub(
| |
| assimilated,
| |
| ".",
| |
| function (consonant)
| |
| return assimil_consonants[voicing][indices[consonant]]
| |
| end)
| |
| .. assimilator
| |
| end)
| |
|
| |
| IPA = gsub(IPA, "smus", "zmus")
| |
|
| |
| return IPA
| |
| end
| |
| | |
| local function devoice_finally(IPA)
| |
| local obstruent = "[" .. table.concat(voiced) .. table.concat(voiceless) .. "]"
| |
|
| |
| IPA = gsub(
| |
| IPA,
| |
| "(" .. obstruent .. "+)#",
| |
| function (final_obstruents)
| |
| return gsub(
| |
| final_obstruents,
| |
| ".",
| |
| function (obstruent)
| |
| return voiceless[indices[obstruent]]
| |
| end)
| |
| .. "#"
| |
| end)
| |
|
| |
| return IPA
| |
| end
| |
| | |
| local function devoice_fricative_r(IPA)
| |
| -- all but r̝̊, which is added by this function
| |
| local voiceless = gsub("[" .. table.concat(voiceless) .. "]", "ṙ", "")
| |
|
| |
| -- ř represents r̝, "ṙ" represents r̝̊
| |
| IPA = gsub(IPA, "(" .. voiceless .. ")" .. "ř", "%1ṙ")
| |
| IPA = gsub(IPA, "ř" .. "(" .. voiceless .. ")", "ṙ%1")
| |
|
| |
| return IPA
| |
| end
| |
| | |
| local function syllabicize_sonorants(IPA)
| |
| -- all except ɲ and j
| |
| local sonorant = gsub("[" .. table.concat(sonorants) .. "]", "[ɲj]", "")
| |
| local obstruent = "[" .. table.concat(voiced) .. table.concat(voiceless) .. "]"
| |
|
| |
| -- between a consonant and an obstruent
| |
| IPA = gsub(
| |
| IPA,
| |
| "(" .. consonant .. "+" .. sonorant .. ")(" .. consonant .. ")",
| |
| "%1" .. syllabic .. "%2"
| |
| )
| |
|
| |
| -- at the end of a word after an obstruent
| |
| IPA = gsub(IPA, "(" .. obstruent .. sonorant .. ")#", "%1" .. syllabic)
| |
|
| |
| return IPA
| |
| end
| |
| | |
| local function assimilate_nasal(IPA)
| |
| local velar = "[ɡk]"
| |
|
| |
| IPA = gsub(IPA, "n(" .. velar .. ")", "ŋ%1")
| |
|
| |
| return IPA
| |
| end
| |
| | |
| local function add_stress(IPA)
| |
| local syllable_count = m_syllables.getVowels(IPA, lang)
| |
|
| |
| if not ( nostress or find(IPA, ".#.") or find(IPA, primary_stress) ) then
| |
| IPA = primary_stress .. IPA
| |
| end
| |
|
| |
| return IPA
| |
| end
| |
| | |
| local function syllabify(IPA)
| |
| local syllables = {}
| |
|
| |
| local working_string = IPA
| |
|
| |
| local noninitial_cluster = match(working_string, ".(" .. consonant .. consonant .. ").")
| |
| local has_cluster = noninitial_cluster and not find(noninitial_cluster, "(.)%1")
| |
|
| |
| if not ( has_cluster or find(working_string, " ") ) then
| |
| while #working_string > 0 do
| |
| local syllable = match(working_string, "^" .. consonant .. "*" .. diphthong)
| |
| or match(working_string, "^" .. consonant .. "*" .. long_vowel)
| |
| or match(working_string, "^" .. consonant .. "*" .. short_vowel)
| |
| or match(working_string, "^" .. consonant .. "*" .. syllabic_consonant)
| |
| if syllable then
| |
| table.insert(syllables, syllable)
| |
| working_string = gsub(working_string, syllable, "", 1)
| |
| elseif find(working_string, "^" .. consonant .. "+$")
| |
| or find(working_string, primary_stress)
| |
| then
| |
|
| |
| syllables[#syllables] = syllables[#syllables] .. working_string
| |
| working_string = ""
| |
| else
| |
| error('The function "syllabify" could not find a syllable '
| |
| .. 'in the IPA transcription "' .. working_string .. '".')
| |
| end
| |
| end
| |
| end
| |
|
| |
| if #syllables > 0 then
| |
| IPA = table.concat(syllables, ".")
| |
| end
| |
|
| |
| return IPA
| |
| end
| |
| | |
| local function apply_rules(IPA)
| |
| --[[ Adds # at word boundaries and in place of spaces, to
| |
| unify treatment of initial and final conditions.
| |
| # is commonly used in phonological rule notation
| |
| to represent word boundaries. ]]
| |
| IPA = "#" .. IPA .. "#"
| |
| IPA = gsub(IPA, "%s+", "#")
| |
|
| |
| -- Handle consonantal prepositions: v, z.
| |
| IPA = gsub(
| |
| IPA,
| |
| "(#[vz])#(.)",
| |
| function (preposition, initial_sound)
| |
| if find(initial_sound, short_vowel) then
| |
| return preposition .. "ʔ" .. initial_sound
| |
| else
| |
| return preposition .. initial_sound
| |
| end
| |
| end)
| |
|
| |
| for sound, character in pairs(multiple_to_single) do
| |
| IPA = gsub(IPA, sound, character)
| |
| end
| |
|
| |
| IPA = regressively_assimilate(IPA)
| |
| IPA = devoice_finally(IPA)
| |
| IPA = devoice_fricative_r(IPA)
| |
| IPA = syllabicize_sonorants(IPA)
| |
| IPA = assimilate_nasal(IPA)
| |
| IPA = add_stress(IPA, nostress)
| |
|
| |
| for sound, character in pairs(multiple_to_single) do
| |
| IPA = gsub(IPA, character, sound)
| |
| end
| |
|
| |
| --[[ This replaces double (geminate) with single consonants,
| |
| and changes a stop plus affricate to affricate:
| |
| for instance, [tt͡s] to [t͡s]. ]]
| |
| IPA = gsub(IPA, "(" .. consonant .. ")%1", "%1")
| |
|
| |
| -- Replace # with space or remove it.
| |
| IPA = gsub(IPA, "([^" .. primary_stress .. secondary_stress .. "])#(.)", "%1 %2")
| |
| IPA = gsub(IPA, "#", "")
| |
|
| |
|
| |
| return IPA
| |
| end
| |
| | |
| function export.toIPA(term, nostress)
| |
| local IPA = {}
| |
|
| |
| local transcription = mw.ustring.lower(term)
| |
| transcription = gsub(transcription, "^%-", "")
| |
| transcription = gsub(transcription, "%-?$", "")
| |
| transcription = gsub(transcription, "nn", "n") -- similar operation is applied to IPA above
| |
|
| |
| for regex, replacement in pairs(replacements) do
| |
| transcription = gsub(transcription, regex, replacement)
| |
| end
| |
| transcription = mw.ustring.toNFC(transcription) -- Recompose combining caron.
| |
|
| |
| local working_string = transcription
| |
|
| |
| while mw.ustring.len(working_string) > 0 do
| |
| local IPA_letter
| |
|
| |
| local letter = sub(working_string, 1, 1)
| |
| local twoletters = sub(working_string, 1, 2) or ""
| |
|
| |
| if data[twoletters] then
| |
| IPA_letter = data[twoletters]
| |
| working_string = sub(working_string, 3)
| |
| else
| |
| IPA_letter = data[letter]
| |
| or error('The letter "' .. tostring(letter)
| |
| .. '" is not a member of the Czech alphabet.')
| |
| working_string = sub(working_string, 2)
| |
| end
| |
|
| |
| table.insert(IPA, IPA_letter)
| |
| end
| |
|
| |
| IPA = table.concat(IPA)
| |
| IPA = apply_rules(IPA, nostress)
| |
|
| |
| return IPA, transcription
| |
| end
| |
| | |
| function export.show(frame)
| |
| local params = {
| |
| [1] = {},
| |
| ["nostress"] = { type = "boolean" },
| |
| }
| |
|
| |
| local args = m_params.process(frame:getParent().args, params)
| |
| local title = mw.title.getCurrentTitle()
| |
| local namespace = title.nsText
| |
| local term = args[1] or namespace == "Template" and "příklad" or title.text
| |
|
| |
| local IPA = export.toIPA(term, nostress)
| |
|
| |
| IPA = "[" .. IPA .. "]"
| |
| IPA = m_IPA.format_IPA_full(lang, { { pron = IPA } } )
| |
|
| |
| return IPA
| |
| end
| |
| | |
| function export.example(frame)
| |
| local output = {
| |
| [[ | |
| {| class="wikitable"
| |
| ]]
| |
| }
| |
| local row
| |
|
| |
| local namespace = mw.title.getCurrentTitle().nsText
| |
|
| |
| if namespace == "Template" then
| |
| table.insert(
| |
| output,
| |
| [[
| |
| ! headword !! code !! result
| |
| ]] | |
| )
| |
| row =
| |
| [[ | |
| |-
| |
| | link || template_code || IPA
| |
| ]] | |
| else
| |
| table.insert(
| |
| output,
| |
| [[
| |
| ! headword !! result
| |
| ]]
| |
| )
| |
| row =
| |
| [[ | |
| |-
| |
| | link || IPA
| |
| ]]
| |
| end
| |
|
| |
| local params = {
| |
| [1] = { required = true },
| |
| }
| |
|
| |
| local args = m_params.process(frame:getParent().args, params)
| |
| local terms = mw.text.split(args[1] or "příklad", ", ")
| |
|
| |
| for _, term in ipairs(terms) do
| |
| local template_parameter
| |
| local respelling_regex = "[%a\"%?%% ]+"
| |
| local respelling = match(term, "(" .. respelling_regex .. ") %(")
| |
| or match(term, respelling_regex)
| |
| local entry = match(term, "%(([%a ]+)%)") or respelling
| |
| local link = export.link(entry)
| |
|
| |
| local IPA, transcribable = export.toIPA(respelling)
| |
| IPA = m_IPA.format_IPA_full(lang, { { pron = "[" .. IPA .. "]" } } )
| |
|
| |
| if term ~= respelling then
| |
| template_parameter = respelling
| |
| end
| |
|
| |
| if term ~= transcribable then
| |
| link = link .. " (" .. export.tag_text(transcribable) .. ")"
| |
| end
| |
|
| |
| template_code = m_template_link.format_link{ "cs-IPA", template_parameter }
| |
|
| |
| local content = {
| |
| link = link,
| |
| template_code = template_code,
| |
| IPA = IPA
| |
| }
| |
|
| |
| local function add_content(name)
| |
| if content[name] then
| |
| return content[name]
| |
| else
| |
| error('No content for "' .. name .. '".')
| |
| end
| |
| end
| |
|
| |
| local current_row = gsub(row, "[%a_]+", add_content)
| |
|
| |
| table.insert(output, current_row)
| |
| end
| |
|
| |
| table.insert(output, "|}")
| |
|
| |
| return table.concat(output)
| |
| end
| |
| | |
| return export
| |