Mazmuna geçiň

Module:ar-pronunciation

Wikisözlük saýtyndan

Bu modul üçin resminamalar Module:ar-pronunciation/doc sahypasynda döredilip bilner

local export = {}

local m_str_utils = require("Module:string utilities")
local m_table = require("Module:table")
local audio_module = "Module:audio"
local parse_utilities_module = "Module:parse utilities"

local rfind = m_str_utils.find
local rsplit = m_str_utils.split
local ugsub = m_str_utils.gsub
local ulen = m_str_utils.len
local ulower = m_str_utils.lower
local usub = m_str_utils.sub

local concat = table.concat
local insert = table.insert

local lang = require("Module:languages").getByCode("ar")
local sc = require("Module:scripts").getByCode("Arab")

local correspondences = {
	["ʾ"] = "ʔ",
	["ṯ"] = "θ",
	["j"] = "d͡ʒ",
	["ḥ"] = "ħ",
	["ḵ"] = "x",
	["ḏ"] = "ð",
	["š"] = "ʃ",
	["ṣ"] = "sˤ",
	["ḍ"] = "dˤ",
	["ṭ"] = "tˤ",
	["ẓ"] = "ðˤ",
	["ž"] = "ʒ",
	["ʿ"] = "ʕ",
	["ḡ"] = "ɣ",
	["ḷ"] = "lˤ",
	["ū"] = "uː",
	["ī"] = "iː",
	["ā"] = "aː",
	["y"] = "j",
	["g"] = "ɡ",
	["ē"] = "eː",
	["ō"] = "oː",
	[""] = "",
}

local vowels = "aāeēiīoōuū"
local vowel = "[" .. vowels .. "]"
local long_vowels = "āēīōū"
local long_vowel = "[" .. long_vowels .. "]"
local consonant = "[^" .. vowels .. ". -]"
local syllabify_pattern = "(" .. vowel .. ")(" .. consonant .. "?)(" .. consonant .. "?)(" .. vowel .. ")"
local tie = "‿"
local closed_syllable_shortening_pattern = "(" .. long_vowel .. ")(" .. tie .. ")" .. "(" .. consonant .. ")"

local function rsub(term, foo, bar)
	local retval = ugsub(term, foo, bar)
	return retval
end

local function generate_obj(respelling)
	return { respelling = respelling }
end

local function combine_qualifiers(qual1, qual2)
	if not qual1 then
		return qual2
	end
	if not qual2 then
		return qual1
	end
	local qualifiers = m_table.deepCopy(qual1)
	for _, qual in ipairs(qual2) do
		m_table.insertIfNot(qualifiers, qual)
	end
	return qualifiers
end

local function split_on_comma(term)
	if not term then
		return nil
	end
	if term:find(",%s") or term:find("\\") then
		return require(parse_utilities_module).split_on_comma(term)
	else
		return rsplit(term, ",")
	end
end

local function parse_respellings_with_modifiers(respelling, paramname)
	if respelling:find("[<%[]") then
		local put = require(parse_utilities_module)
		local segments = put.parse_multi_delimiter_balanced_segment_run(respelling, { { "<", ">" }, { "[", "]" } })
		local comma_separated_groups = put.split_alternating_runs_on_comma(segments)

		local retval = {}
		for _, group in ipairs(comma_separated_groups) do
			local j = 2
			while j <= #group do
				if not group[j]:find("^<.*>$") then
					group[j - 1] = group[j - 1] .. group[j] .. group[j + 1]
					table.remove(group, j)
					table.remove(group, j)
				else
					j = j + 2
				end
			end

			local param_mods = {
				q = { type = "qualifier" },
				qq = { type = "qualifier" },
				a = { type = "labels" },
				aa = { type = "labels" },
				ref = { item_dest = "refs", type = "references" },
			}

			table.insert(retval, put.parse_inline_modifiers_from_segments {
				group = group,
				arg = respelling,
				props = {
					paramname = paramname,
					param_mods = param_mods,
					generate_obj = generate_obj,
				},
			})
		end
		return retval
	else
		local retval = {}
		for _, item in ipairs(split_on_comma(respelling)) do
			table.insert(retval, generate_obj(item))
		end
		return retval
	end
end

local function parse_pron_modifier(arg, paramname, generate_obj, param_mods, splitchar)
	splitchar = splitchar or ","
	if arg:find("<") then
		param_mods.q = { type = "qualifier" }
		param_mods.qq = { type = "qualifier" }
		param_mods.a = { type = "labels" }
		param_mods.aa = { type = "labels" }
		param_mods.ref = { item_dest = "refs", type = "references" }
		return require(parse_utilities_module).parse_inline_modifiers(arg, {
			param_mods = param_mods,
			generate_obj = generate_obj,
			paramname = paramname,
			splitchar = splitchar,
		})
	else
		local retval = {}
		local split_arg = splitchar == "," and split_on_comma(arg) or rsplit(arg, splitchar)
		for _, term in ipairs(split_arg) do
			table.insert(retval, generate_obj(term))
		end
		return retval
	end
end

local function parse_audio(lang, arg, pagename, paramname)
	local param_mods = {
		IPA = { sublist = true },
		text = {},
		t = { item_dest = "gloss" },
		gloss = {},
		pos = {},
		lit = {},
		g = { item_dest = "genders", sublist = true },
		bad = {},
		cap = { item_dest = "caption" },
	}

	local function process_special_chars(val)
		if not val then
			return val
		end
		return (val:gsub("#", pagename))
	end

	local function generate_audio_obj(arg)
		return { file = process_special_chars(arg) }
	end

	local retvals = parse_pron_modifier(arg, paramname, generate_audio_obj, param_mods, "%s*;%s*")
	for _, retval in ipairs(retvals) do
		retval.lang = lang
		retval.text = process_special_chars(retval.text)
		retval.caption = process_special_chars(retval.caption)
		local textobj = require(audio_module).construct_audio_textobj(retval)
		retval.text = textobj
		retval.gloss = nil
		retval.pos = nil
		retval.lit = nil
		retval.genders = nil
	end
	return retvals
end

local function parse_regional_phonetics(ph_arg, pagename)
	if not ph_arg or ph_arg == "" then
		return {}
	end

	local regionals = {}
	for _, item in ipairs(rsplit(ph_arg, "%s*;%s*")) do
		local audio = nil
		local item_no_mod = item:gsub("<a:([^>]+)>", function(a)
			audio = a:gsub("#", pagename)
			return ""
		end)

		local region, ipa = item_no_mod:match("^([^:]+):(.+)$")
		if region and ipa then
			local regions = rsplit(region, "%s*,%s*")
			table.insert(regionals, { regions = regions, ipa = ipa, audio = audio })
		end
	end
	return regionals
end

local function syllabify(text)
	text = ugsub(text, "%-(" .. consonant .. ")%-(" .. consonant .. ")", "%1.%2")
	text = ugsub(text, "%-", ".")

	for _ = 1, 2 do
		text = ugsub(
			text,
			syllabify_pattern,
			function(a, b, c, d)
				if c == "" and b ~= "" then
					c, b = b, ""
				end
				return a .. b .. "." .. c .. d
			end
		)
	end

	text = ugsub(text, "(" .. vowel .. ") (" .. consonant .. ")%.?(" ..
		consonant .. ")", "%1" .. tie .. "%2.%3")

	return text
end

local function closed_syllable_shortening(text)
	local shorten = {
		["ā"] = "a",
		["ē"] = "e",
		["ī"] = "i",
		["ō"] = "o",
		["ū"] = "u",
	}

	text = ugsub(text,
		closed_syllable_shortening_pattern,
		function(vowel, tie, consonant)
			return shorten[vowel] .. tie .. consonant
		end)

	return text
end

function export.link(term)
	return require("Module:links").full_link { term = term, lang = lang, sc = sc }
end

function export.toIPA(list, silent_error)
	local translit

	if list.tr then
		translit = list.tr
	elseif list.term then
		require("Module:script utilities").checkScript(list.term, "Arab")
		translit = lang:transliterate(list.term)

		if not translit then
			if silent_error then
				return ''
			else
				error('Module:ar-translit failed to generate a transliteration from "' .. list.term .. '".')
			end
		end
	else
		if silent_error then
			return ''
		else
			error('No Arabic text or transliteration was provided to the function "toIPA".')
		end
	end

	translit = ugsub(translit, "llāh", "ḷḷāh")
	translit = ugsub(translit, "([iī] ?)ḷḷ", "%1ll")
	translit = ugsub(translit, "%(t%)", "")
	translit = ugsub(translit, "(" .. vowel .. ") " .. vowel, "%1 ")
	translit = ugsub(translit, "%-?l%-?", "l")

	translit = syllabify(translit)
	translit = closed_syllable_shortening(translit)

	local output = ugsub(translit, ".", correspondences)
	output = ugsub(output, "%-", "")

	return output
end

function export.get_pron_info(terms, pagename, paramname)
	if #terms == 1 and terms[1].respelling == "-" then
		return { pron_list = nil }
	end

	local pron_list = {}
	local brackets = "/%s/"

	for _, term in ipairs(terms) do
		local respelling = term.respelling
		local ar_term, tr

		if not respelling or respelling == "" or respelling == "#" then
			ar_term = pagename
		elseif rfind(respelling, "[a-zA-Z]") then
			tr = respelling
		elseif respelling:find("[ء-ي]") then
			ar_term = respelling
		else
			tr = respelling
		end

		local pron = export.toIPA({ term = ar_term, tr = tr }, false)

		if pron and pron ~= "" then
			local bracketed_pron = brackets:format(pron)
			table.insert(pron_list, {
				pron = bracketed_pron,
				q = term.q,
				qq = term.qq,
				a = term.a,
				aa = term.aa,
				refs = term.refs,
			})
		end
	end

	return { pron_list = pron_list }
end

function export.show_old(frame)
	local params = {
		[1] = { list = true, allow_holes = true },
		["tr"] = { list = true, allow_holes = true },
		["qual"] = { list = true, allow_holes = true },
		["nl"] = { type = "boolean" },
		["ann"] = {},
	}

	local args = require("Module:parameters").process(frame:getParent().args, params)
	local ar_terms = args[1]
	local transliterations = args.tr
	local qualifiers = args.qual
	local nl = args.nl

	if not (ar_terms.maxindex > 0 or transliterations.maxindex > 0) then
		if mw.title.getCurrentTitle().nsText == "Template" then
			ar_terms[1] = "كَلِمَة"
			ar_terms.maxindex = 1
		else
			error(
				'Please provide vocalized Arabic in the first parameter of {{[[Template:ar-IPA|ar-IPA]]}}, or transliteration in the "tr" parameter.')
		end
	end

	local pronunciations = {}
	for i = 1, math.max(ar_terms.maxindex, transliterations.maxindex) do
		local ar_term = ar_terms[i]
		local tr = transliterations[i]
		local qual = qualifiers[i]

		if not (ar_term or tr) then
			error("There is a gap in the parameters. Provide either |" .. i .. "= or |tr" .. i .. "=.")
		elseif ar_term and tr then
			mw.logObject("Duplicate parameters |" .. i .. "= and |tr" .. i .. "= in {{ar-IPA}},")
		end

		local pron = export.toIPA { term = ar_term, tr = tr }
		table.insert(pronunciations, { pron = "/" .. pron .. "/", qualifiers = qual and { qual } or nil })
	end

	local anntext = ""
	if args.ann then
		anntext = args.ann
		if args.ann:find("%+") then
			local anndefs = {}
			for i = 1, ar_terms.maxindex do
				local ar_term = ar_terms[i]
				if ar_term then
					table.insert(anndefs, "'''" .. ar_term .. "'''")
				end
			end
			if anndefs[1] then
				anndefs = table.concat(anndefs, ", ")
				anntext = anntext:gsub("%+", require("Module:string utilities").replacement_escape(anndefs))
			end
		end
		anntext = require("Module:qualifier").format_qualifier(anntext, "", "") .. ":&#32;"
	end

	if nl then
		return anntext .. require("Module:IPA").format_IPA_multiple(lang, pronunciations)
	else
		return anntext .. require("Module:IPA").format_IPA_full { lang = lang, items = pronunciations }
	end
end

function export.show(frame)
	local parent_args = frame:getParent().args
	local process = require("Module:parameters").process

	local params = {
		[1] = {},
		["audios"] = {},
		["a"] = { alias_of = "audios" },
		["ph"] = {},
		["pagename"] = {},
		["indent"] = {},
		["ann"] = {},
	}

	local args = process(parent_args, params)
	local pagename = args.pagename or mw.loadData("Module:headword/data").pagename
	local indent = args.indent or "*"

	local termspec = args[1] or "#"
	local terms = parse_respellings_with_modifiers(termspec, 1)
	local pronobj = export.get_pron_info(terms, pagename, 1)

	local regional_phonetics = parse_regional_phonetics(args.ph, pagename)

	local parts = {}
	local function ins(text)
		table.insert(parts, text)
	end

	local anntext = ""
	if args.ann then
		anntext = args.ann
		if args.ann:find("%+") then
			local anndefs = {}
			for _, term in ipairs(terms) do
				local respelling = term.respelling
				if respelling and respelling:find("[ء-ي]") then
					table.insert(anndefs, "'''" .. respelling .. "'''")
				end
			end
			if anndefs[1] then
				anndefs = table.concat(anndefs, ", ")
				anntext = anntext:gsub("%+", require("Module:string utilities").replacement_escape(anndefs))
			end
		end
		anntext = require("Module:qualifier").format_qualifier(anntext, "", "") .. ":&#32;"
	end

	if pronobj.pron_list and #pronobj.pron_list > 0 then
		local formatted = require("Module:IPA").format_IPA_full { lang = lang, items = pronobj.pron_list }
		ins(indent .. anntext .. mw.ustring.toNFC(formatted))
	end

	if args.audios then
		local format_audio = require("Module:audio").format_audio
		local audio_objs = parse_audio(lang, args.audios, pagename, "audios")
		for i, audio_obj in ipairs(audio_objs) do
			if #audio_objs > 1 and not audio_obj.caption then
				audio_obj.caption = "Audio " .. i
			end
			ins("\n" .. indent .. " " .. format_audio(audio_obj))
		end
	end

	if #regional_phonetics > 0 then
		local m_IPA = require("Module:IPA")
		local m_accent = require("Module:accent qualifier")

		for _, regional in ipairs(regional_phonetics) do
			local regions = regional.regions
			local ipa = regional.ipa

			local pron_item = { pron = "[" .. ipa .. "]" }
			local formatted_ipa = m_IPA.format_IPA_full { lang = lang, items = { pron_item } }
			local formatted_region = m_accent.format_qualifiers(lang, regions)

			local line = "\n" .. indent .. indent .. " " .. formatted_region .. " " .. mw.ustring.toNFC(formatted_ipa)

			if regional.audio then
				local audio_obj = {
					lang = lang,
					file = regional.audio,
				}
				local textobj = require(audio_module).construct_audio_textobj(audio_obj)
				audio_obj.text = textobj
				line = line .. " " .. require("Module:audio").format_audio(audio_obj)
			end

			ins(line)
		end
	end

	return concat(parts)
end

return export