Module:se-IPA

Hello, you have come here looking for the meaning of the word Module:se-IPA. In DICTIOUS you will not only get to know all the dictionary meanings for the word Module:se-IPA, but we will also tell you about its etymology, its characteristics and you will know how to say Module:se-IPA in singular and plural. Everything you need to know about the word Module:se-IPA you have here. The definition of the word Module:se-IPA will help you to be more precise and correct when speaking or writing your texts. Knowing the definition ofModule:se-IPA, as well as those of other words, enriches your vocabulary and provides you with more and better linguistic resources.

This module implements {{se-IPA}}.


local export = {}

local lang = require("Module:languages").getByCode("se")

local m_str_utils = require("Module:string utilities")
local find = m_str_utils.find
local gmatch = m_str_utils.gmatch
local gsub = m_str_utils.gsub
local len = m_str_utils.len
local lower = m_str_utils.lower
local sub = m_str_utils.sub

local u = require("Module:string/char")
local BREVE = u(0x0306)


local letters_phonemes = {
	 = "ː",

	 = "a",  = "a",
	 = "aː",  = "aˑ",  = "a",
	 = "b",
	 = "t͡s",
	 = "t͡ʃ",
	 = "d",
	 = "ð",
	 = "e",  = "eː",
	 = "ɡ",
	 = "iː",
	 = "kʰ",
	 = "o",  = "oː",
	 = "pʰ",
	 = "ʃ",
	 = "tʰ",
	 = "θ",
	 = "uː",
	 = "d͡z",
	 = "d͡ʒ",

	 = "ea̯",  = "e̯a",  = "ĕă̯",
	 = "ie̯",  = "i̯e",  = "ĭĕ̯",
	 = "oɑ̯",  = "o̯ɑ",  = "ŏɑ̯̆",
	 = "uo̯",  = "u̯o",  = "ŭŏ̯",

	 = "ɟ",
	 = "ʎ",
	 = "ɲ",

	 = "j̥",  = "j̥.j̥",  = "j̥ː.j̥",
	 = "l̥",  = "l̥.l̥",  = "l̥ː.l̥",
	 = "m̥",  = "m̥.m̥",  = "m̥ː.m̥",
	 = "n̥",  = "n̥.n̥",  = "n̥ː.n̥",
	 = "r̥",  = "r̥.r̥",  = "r̥ː.r̥",
}


--	This adds letters_phonemes = "e", letters_phonemes = "i", etc.
for letter in gmatch("efhijklmnŋoprstuv", ".") do
	letters_phonemes = letter
end

-- Preaspirated
for letter in gmatch("ptcčk", ".") do
	letters_phonemes = "h" .. letters_phonemes
	letters_phonemes = "hː" .. letters_phonemes
end


local function get_phoneme(remainder)
	-- Find the longest string of letters that matches a recognised sequence in the list
	local longestmatch = ""

	for letter, _ in pairs(letters_phonemes) do
		if sub(remainder, 1, len(letter)) == letter and len(letter) > len(longestmatch) then
			longestmatch = letter
		end
	end

	if len(longestmatch) > 0 then
		return longestmatch, sub(remainder, len(longestmatch) + 1)
	else
		return sub(remainder, 1, 1), sub(remainder, 2)
	end
end


local function get_syllable(remainder)
	local syll = {cons = {}, vowel = ""}
	local cons

	while find(remainder, "^(+)") do
		cons, remainder = get_phoneme(remainder)

		if cons == "nˈnj" then
			require("Module:debug").track("se-IPA/nnj")
		end

		if cons == "ˈ" then
			syll.cons.quantity = 3
		else
			if cons == "dj" or cons == "lj" then
				if syll.cons == string.sub(cons, 1, 1) then
					syll.cons = cons
					syll.cons.quantity = 3
				else
					table.insert(syll.cons, cons)
				end
			elseif cons == "nj" and syll.cons == "n" then
				syll.cons = "nj"
			end

			table.insert(syll.cons, cons)
		end
	end

	if find(remainder, "^(+)") then
		syll.vowel, remainder = get_phoneme(remainder)
	end

	if remainder == "" then
		remainder = nil
	end

	-- Determine consonant quantity
	if not syll.cons.quantity then
		if not syll.cons then
			syll.cons.quantity = 1
		else
			if find(syll.cons, "(.)%1$") or (syll.cons == syll.cons and not find(syll.cons, "^$")) or (syll.cons == "p" and syll.cons == "m") or (syll.cons == "t" and syll.cons == "n") or (syll.cons == "t" and syll.cons == "nj") or (syll.cons == "k" and syll.cons == "ŋ") then
				syll.cons.quantity = 2
			else
				syll.cons.quantity = 3
			end
		end
	end

	return syll, remainder
end


-- Split the word into syllables of C(C)V shape
local function split_syllables(remainder)
	remainder = lower(remainder)
	remainder = gsub(remainder, "()i", "%1j")

	local syllables = {}
	local syll

	while remainder do
		syll, remainder = get_syllable(remainder)
		table.insert(syllables, syll)
	end

	syllables.count = #syllables

	if syllables.vowel == "" then
		syllables.count = syllables.count - 1
	end

	return syllables
end


local function shorten(vowel)
	vowel = gsub(vowel, "^$", { = "e",  = "i",  = "o",  = "u"})

	for _, v in ipairs({"á", "ea", "ie", "oa", "uo"}) do
		vowel = gsub(vowel, v, v .. BREVE)
	end

	return vowel
end


local function shift(vowel)
	for _, v in ipairs({"á", "ea", "ie", "oa", "uo"}) do
		vowel = gsub(vowel, v, v .. "ˈ")
	end

	return vowel
end


local function lengthen(vowel)
	vowel = gsub(vowel, "^$", { = "ē",  = "ī",  = "ō",  = "ū"})
	vowel = gsub(vowel, BREVE, "")

	return vowel
end

-- Determine whether long vowels should be shortened before certain consonants
local function should_shorten(syll, nextsyll)
	if nextsyll.cons then
		if find(nextsyll.cons, "^h()%1$") then
			-- Long preaspirate
			return true
		elseif find(nextsyll.cons, "^()ˈ%1$") then
			-- Overlong vowel
			return true
		elseif (syll.vowel == "ie" or syll.vowel == "uo") and find(nextsyll.vowel, "^$") then
			if find(nextsyll.cons, "^()%1$") then
				-- Geminate stop
				return true
			elseif nextsyll.cons == "pm" or nextsyll.cons == "tn" or nextsyll.cons == "tnj" or nextsyll.cons == "kŋ" then
				-- Glottalised nasal
				return true
			elseif nextsyll.cons and not find(nextsyll.cons, "^h$") then
				-- Clusters, except when the second element is a strong-grade preaspirate
				return true
			end
		elseif (syll.vowel == "ie" or syll.vowel == "uo") and nextsyll.vowel == "a" then
			if find(nextsyll.cons, "^()%1$") then
				-- Geminate voiced stop
				return true
			elseif nextsyll.cons and not find(nextsyll.cons, "(.)%1$") and not find(nextsyll.cons, "^h$") and not (nextsyll.cons == "pm" or nextsyll.cons == "tn" or nextsyll.cons == "tnj" or nextsyll.cons == "kŋ") then
				-- Clusters, except when the second element is long, or a preaspirate, or a preglottalised nasal
				return true
			end
		end
	end

	return false
end


local function convert_spelling(syllables)
	local foot = 0

	for i, syll in ipairs(syllables) do
		if syll.vowel == "" then
			if syll.cons == "t" then
				syll.cons = "ht"
			elseif syll.cons == "d" then
				syll.cons = "t"
			end

			break
		end

		local nextsyll = syllables or {cons = {}, vowel = ""}

		foot = foot + 1

		if foot == 3 and i ~= syllables.count then
			foot = 1
		end

		-- Make i and u long in even syllables
		if foot == 2 and (syll.vowel == "i" or syll.vowel == "u") and nextsyll.cons ~= "j" then
			syll.vowel = lengthen(syll.vowel)
		end

		if #syll.cons == 1 then
			if foot == 1 then
				-- Postaspiration
				syll.cons = gsub(syll.cons, "^()$", "%1h")
			elseif foot == 3 then
				-- d is đ between two unstressed vowels
				syll.cons = gsub(syll.cons, "d", "đ")
			end
		elseif #syll.cons > 1 then
			if syll.cons == syll.cons and syll.cons and find(syll.cons, "$") then
				-- Ungeminate last consonant after voiceless
				syll.cons = nil
			elseif find(syll.cons, "$") then
				-- Ungeminate last consonant after voiceless
				syll.cons = gsub(syll.cons, "(.)%1$", "%1")
			else
				-- Preaspirate final voiceless consonant after voiced
				syll.cons = gsub(syll.cons, "^()$", "h%1")
				syll.cons = gsub(syll.cons, "^()%1$", "h%1%1")
			end

			-- Devoice final geminates
			if syll.cons == "bb" then
				syll.cons = "pp"
			elseif syll.cons == "dd" then
				syll.cons = "tt"
			elseif syll.cons == "gg" then
				syll.cons = "kk"
			elseif syll.cons == "zz" then
				syll.cons = "cc"
			elseif syll.cons == "žž" then
				syll.cons = "čč"
			end
		end

		-- Devoice remaining single voiced consonants
		for j, cons in ipairs(syll.cons) do
			if cons == "b" and syll.cons ~= "b" and (j ~= 1 or syll.cons ~= "b" and syll.cons ~= "m") then
				syll.cons = "p"
			elseif cons == "d" and syll.cons ~= "d" and (j ~= 1 or syll.cons ~= "d" and syll.cons ~= "n" and syll.cons ~= "nj") then
				syll.cons = "t"
			elseif cons == "g" and syll.cons ~= "g" and (j ~= 1 or syll.cons ~= "g" and syll.cons ~= "ŋ") then
				syll.cons = "k"
			elseif cons == "z" and syll.cons ~= "z" and (j ~= 1 or syll.cons ~= "z") then
				syll.cons = "c"
			elseif cons == "ž" and syll.cons ~= "ž" and (j ~= 1 or syll.cons ~= "ž") then
				syll.cons = "č"
			end
		end

		-- Regularise divergent spellings in clusters
		--if #syll.cons > 2 then
		--	error("Clusters with more than 2 consonants are not yet supported.")
		--end

		if foot == 2 and syll.cons.quantity == 3 then
			-- Lengthen initial sonorant in quantity 3
			table.insert(syll.cons, 2, "ˈ")
		end

		-- Secondary stress
		if foot == 1 and i > 1 then
			if #syll.cons == 1 then
				table.insert(syll.cons, 1, "ˌ")
			elseif #syll.cons == 2 then
				table.insert(syll.cons, 2, "ˌ")
			end
		end
	end

	-- This needs to be a separate pass because otherwise unstressed ī and ū won't have been lengthened yet
	for i, syll in ipairs(syllables) do
		local nextsyll = syllables or {cons = {}, vowel = ""}

	--	if should_shorten(syll, nextsyll) then
	--		syll.vowel = shorten(syll.vowel)
		if find(nextsyll.vowel, "^$") then
			syll.vowel = shift(syll.vowel)
		end
	end
end


-- Dialect-specific conversions
local function dialect(syllables)
	for i, syll in ipairs(syllables) do
		-- Western Finnmark dialect
		if syll.cons then
			if syll.cons == "ŋ" then
				syll.cons = "nj"

				if syll.cons == "ˈ" then
					if syll.cons then
						syll.cons = gsub(syll.cons, "^$", { = "d",  = "t",  = "nj"})
					end
				else
					if syll.cons then
						syll.cons = gsub(syll.cons, "^$", { = "d",  = "t",  = "nj"})
					end
				end
			end
		end
	end
end


-- Convert word to IPA
local function to_IPA(syllables)
	for i, syll in ipairs(syllables) do
		for j, cons in ipairs(syll.cons) do
			if syll.vowel == "" and cons == "ht" then
				syll.cons = "h(t)"
			elseif letters_phonemes then
				-- Drop the final part after the tie bar
				if string.find(letters_phonemes, "͡", nil, true) and syll.cons == syll.cons == "ˈ" and 2 or 1)] then
					syll.cons = gsub(letters_phonemes, "͡.*$", "")
				else
					syll.cons = letters_phonemes
				end
			end
		end

		syll.vowel = letters_phonemes or syll.vowel

		syllables = table.concat(syll.cons) .. syll.vowel
	end

	return "ˈ" .. table.concat(syllables)
end


function export.IPA(frame)
	local params = {
		 = {default = mw.title.getCurrentTitle().text},
	}

	local args = require("Module:parameters").process(frame:getParent().args, params)

	local syllables = split_syllables(args)
	convert_spelling(syllables)
	dialect(syllables)

	return
		require("Module:accent qualifier").format_qualifiers(lang, {"Kautokeino"}) .. " " ..
		require("Module:IPA").format_IPA_full { lang = lang, items = {{pron = "/" .. to_IPA(syllables) .. "/"}} } ..
		require("Module:utilities").format_categories(lang:getCanonicalName() .. " " .. tostring(syllables.count) .. "-syllable words", lang)
end

return export