Модул:be-pronunciation

Документацију овог модула можете да направите на страници Модул:be-pronunciation/док

local export = {}

local gsub = mw.ustring.gsub
local sub = mw.ustring.sub
local match = mw.ustring.match
local U = mw.ustring.char

local grave = U(0x300)
local acute = U(0x301)
local stress = U(0x2C8)
local secondary_stress = U(0x2CC)
local tie = U(0x361)

local correspondences = {
	["а"] = "a",
	["б"] = "b",
	["в"] = "v",
	["г"] = "ɣ",
	["ґ"] = "ɡ",
	["д"] = "d",
	["дз"] = "d" .. tie .. "z",
	["дж"] = "d" .. tie .. "ʐ",
	["е"] = "ʲe",	-- or ɛ
	["ё"] = "ʲo",
	["ж"] = "ʐ",
	["з"] = "z",
	["і"] = "ʲi",
	["й"] = "j",
	["к"] = "k",
	["л"] = "l",
	["м"] = "m",
	["н"] = "n",
	["о"] = "o",	-- or ɔ
	["п"] = "p",
	["р"] = "r",
	["с"] = "s",
	["т"] = "t",
	["у"] = "u",
	["ў"] = "w",
	["ф"] = "f",
	["х"] = "x",
	["ц"] = "t" .. tie .. "s",
	["ч"] = "t" .. tie .. "ʂ",
	["ш"] = "ʂ",
	["ы"] = "ɨ",
	["ь"] = "ʲ",
	["э"] = "e",
	["ю"] = "ʲu",
	["я"] = "ʲa",
	[acute] = stress,
	[grave] = secondary_stress,
	-- Space
	[" "] = " ",
	-- Apostrophes
	[U(0x27)] = "j",
	[U(0x2019)] = "j",
	[U(0x2BC)] = "j"
}

local devoicing = {
	['b'] = 'p', ['d'] = 't', ['ɡ'] = 'k',
	['z'] = 's', ['ʐ'] = 'ʂ', ['ɣ'] = 'x'
}

local voicing = {
	['p'] = 'b', ['t'] = 'd', ['k'] = 'ɡ',
	['s'] = 'z', ['ʂ'] = 'ʐ', ['x'] = 'ɣ',
	['f'] = 'v'
}

local vowels = "aeiɨou"
local vowel = "[" .. vowels .. "]"

local accent = "[" .. stress .. secondary_stress .. "]"

local function move_stress(transcription)
	transcription = gsub(transcription, "(j?" .. vowel .. ")(" .. accent .. ")", "%2%1")
	local new_text = transcription
	repeat
		transcription = new_text
		new_text = gsub(transcription, "([mnlrvw]ʲ?)(" .. accent .. ")", "%2%1")
	until new_text == transcription
	repeat
		transcription = new_text
		new_text = gsub(transcription, "([bdzʐɡɣpftskxʂ" .. tie .. "]ʲ?)(" .. accent .. ")", "%2%1")
	until new_text == transcription
	transcription = gsub(transcription, "#([^#" .. vowels .. "])(" .. accent .. ")", "#%2%1")
	return transcription
end

local function assimilate_voicing(transcription)
	while true do
		local new_text = gsub(transcription, "([bdɡɣzʐ])([ʲː" .. tie .. "]*[ptkfxsʂ#])", function(a, b)
			return devoicing[a] .. b end)
		new_text = gsub(new_text, "([ptkfxsʂ])([ʲː" .. tie .. "]*v?[ʲː" .. tie .. "]*[bdɡɣzʐ])", function(a, b)
			return voicing[a] .. b end)
		if new_text == transcription then
			break
		end
		transcription = new_text
	end
	return transcription
end

local function assimilate_sibilants(transcription)
	transcription = gsub(transcription, "[sʂzʐ]([td]?" .. tie .. "?)([sʂzʐ])", "%2%1%2")
	return transcription
end

-- Can probably be simplified
local function assimilate_palatals(transcription)
	local new_text = transcription
	repeat
		transcription = new_text
		new_text = gsub(new_text, "([bzɡɣpfskxmnlv])%1ʲ", "%1ʲ%1ʲ")
		new_text = gsub(new_text, "([szn])j", "%1ʲj")
		new_text = gsub(new_text, "([sn])(" .. accent .. "?[td]" .. tie .. "[sz]ʲ)", "%1ʲ%2")
		new_text = gsub(new_text, "([sz])([nl])ʲ", "%1ʲ%2ʲ")

		-- No assimilation in a final, non-initial syllable
		new_text = gsub(new_text, "([sz])([bmpfv])ʲ([^#]*" .. vowel .. "[^#]*" .. vowel .. ")", "%1ʲ%2ʲ%3")
		new_text = gsub(new_text, "#([^#" .. vowels .. "]*)([sz])([bmpfv])ʲ", "%1%2ʲ%3ʲ")

		new_text = gsub(new_text, "([td]" .. tie .. "[sz])vʲ", "%1ʲvʲ")
		new_text = gsub(new_text, "tsʲ", "t" .. tie .. "sʲsʲ")
		new_text = gsub(new_text, "dzʲ", "d" .. tie .. "zʲzʲ")
		new_text = gsub(new_text, "tt" .. tie .. "sʲ", "t" .. tie .. "sʲt" .. tie .. "sʲ")
		new_text = gsub(new_text, "dd" .. tie .. "zʲ", "d" .. tie .. "zʲd" .. tie .. "zʲ")
	until new_text == transcription
	return transcription
end

local function convert(text)
	local working_string = mw.ustring.lower(text)
	local IPA = {}
	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 correspondences[twoletters] then
			IPA_letter = correspondences[twoletters]
			working_string = sub(working_string, 3)
		else
			IPA_letter = correspondences[letter]
			working_string = sub(working_string, 2)
		end
		
		table.insert(IPA, IPA_letter)
	end
	IPA = table.concat(IPA)

	-- Mark word boundaries
	IPA = gsub(IPA, "(%s+)", "#%1#")
	IPA = "#" .. IPA .. "#"

	-- Syllable-final /в/ is [u̯]
	IPA = gsub(IPA, "([" .. vowels .. stress .. secondary_stress .. "]+)w([^" .. vowels .. "])", "%1u̯%2")

	-- Change ʲ to j between vowels.
	IPA = gsub(IPA, "([#u̯" .. vowels .. "])ʲ(" .. vowel .. ")", "%1j%2")
	IPA = gsub(IPA, "[jʲ]ʲ", "j")

	-- /г/ is a stop in /зг/, /жг/
	IPA = gsub(IPA, "([sʂzʐ])ɣ", "%1ɡ")

	-- Mark stress
	IPA = mw.ustring.gsub(IPA, "(#[^#o" .. stress .. "]*)o([^#o" .. stress .. "]*[aeiɨu][^#o" .. stress .. "]*#)", "%1o" .. stress .. "%2")
	IPA = mw.ustring.gsub(IPA, "(#[^#o" .. stress .. "]*[aeiɨu][^#o" .. stress .. "]*)o([^#o" .. stress .. "]*#)", "%1o" .. stress .. "%2")
	IPA = move_stress(IPA)

	return IPA
end

function export.toIPA(term)
	--	Returns an error if the word contains alphabetic characters that are not Cyrillic.
	require("Модул:script utilities").checkScript(term, "Cyrl")
	
	IPA = convert(term)

	-- Voicing assimilation
	IPA = assimilate_voicing(IPA)

	-- Sibilant assimilation
	IPA = assimilate_sibilants(IPA)

	-- Palatal assimilation
	IPA = assimilate_palatals(IPA)
	
	-- Soft and hard /л/
	IPA = gsub(IPA, "l([^ʲ])", "ɫ%1")

	-- Convert identical consonant sequences to geminates
	IPA = gsub(IPA, "([td]" .. tie .. "[szʂʐ]ʲ?)%1", "%1ː")
	IPA = gsub(IPA, "([^" .. tie .. "])([bdzʐɡɣpftskxʂmnlrjvw]ʲ?)%2", "%1%2ː")

	-- Remove #s
	IPA = gsub(IPA, "#", "")

	return IPA
end

function export.show(frame)
	local params = {
		[1] = {}
	}
	
	local title = mw.title.getCurrentTitle()
	
	local args = require("Модул:parameters").process(frame:getParent().args, params)
	local term = args[1] or title.nsText == "Шаблон" and "пры́клад" or title.text
	
	local IPA = export.toIPA(term)
	
	IPA = "[" .. IPA .. "]"
	IPA = require("Модул:IPA").format_IPA_full(require("Модул:languages").getByCode("be"), { { pron = IPA } } )
	
	return IPA
end

return export