বিষয়বস্তুতে চলুন

মডিউল:sem-arb-utilities

উইকিঅভিধান, মুক্ত অভিধান থেকে

এই মডিউলের জন্য মডিউল:sem-arb-utilities/নথি-এ নথিপত্র তৈরি করা হয়ে থাকতে পারে

local export = {}

local m_str_utils = require("Module:string utilities")
local m_utilities = require("Module:utilities")
local m_links = require("Module:links")
local m_headword = require("Module:headword")
local m_langs = require("Module:languages")
local m_params = require("Module:parameters")
local m_parse_utils = require("Module:parse utilities")
local m_affix = require("Module:affix")
local m_sc_utils = require("Module:script utilities")

local pluralize = require("Module:en-utilities").pluralize

local lg_ar = m_langs.getByCode("ar")
local lg_sem_arb = lg_ar:getFamily():getCode()

local rsplit = m_str_utils.split
local rsubn = m_str_utils.gsub

local unpack = unpack or table.unpack -- Lua 5.2 compatibility

local separator_langs = { ["mt"] = true, ["acy"] = true }
local color_langs = { ["mt"] = "red", ["ary"] = "red", ["ar"] = "green", ["shu"] = "yellow" }
local template_preview_per_langcode = { ["mt"] = "k-t-b", ["acy"] = "k-t-p" }
local lang
local sc

local function ifelse(cond, yes, no)
	if cond then
		return yes
	end
	return no
end

local function ucfirst(str)
	if str == nil then
		return str
	end
	return mw.language.getContentLanguage():ucfirst(str)
end

local function link(term, alt, id)
	if term == "" or term == "—" then
		return term
	else
		return m_links.full_link({
			term = term,
			alt = alt,
			lang = lang,
			id = id,
		})
	end
end

local function parse_inlines(term)
	return m_parse_utils.parse_inline_modifiers(
		term,
		{
			param_mods = {tr = {}, t = {}, pos = {}},
			generate_obj = function(term) return {term} end,
		}
	)
end

local function make_part(noninline, lang)
	local keys = {"tr", "t", "pos"}
	local inline
	if type(noninline) == "string" then
		inline = parse_inlines(noninline)
	else
		inline = parse_inlines(noninline[1])
	end
	local return_value = {
		term = m_sc_utils.tag_text(inline[1], lang),
	}
	for i, key in ipairs(keys) do
		if inline[key] and noninline[key] then
			error(
				key .. " specified twice: "
				.. "<" .. key .. ":" .. inline[key] .. ">"
				.. " and "
				.. "|" .. key .. "=" .. nonline[key]
			)
		end
		return_value[key] = inline[key] or noninline[key]
	end
	if not return_value.tr then
		return_value.tr = lang:transliterate(inline[1])
	end
	return return_value
end

local function make_parts(lang, raw_parts)
	local parts = {}
	for i, part in ipairs(raw_parts) do
		parts[#parts + 1] = make_part(part, lang)
	end
	return {
		parts = parts,
		lang = lang,
		sc = lang:findBestScript(parts[1][1]),
	}
end

local function show_affix(lang, raw_parts)
	return m_affix.show_affix(
		make_parts(lang, raw_parts),
		{},
		lang
	)
end

local appendices = {
	["active participle"] = {
		-- participles have verbal force in (most?) vernaculars
		function(args, lang)
			return ifelse(lang:getCode() == lg_ar:getCode(), "nominals", "verbs")
		end,
		derived = true,
	},
	["characteristic adjective"] = "nominals",
	["color/defect adjective"] = {
		"nominals",
		fragment = "Color or defect adjectives",
	},
	["diminutive"] = "nominals",
	["elative"] = "nominals",
	["relative"] = {
		"nominals",
		params = function(lang)
			return {
				[1] = {
					required = true,
				},
				[2] = {
					alias_of = "t",
				},
				[3] = {
					alias_of = "suffix",
				},
				["id"] = {},
				["id1"] = {
					alias_of = "id",
				},
				["tr"] = {},
				["pl"] = {
					type = "boolean",
				},
			
				["t"] = {
					required = true,
				},
				["suffix"] = {
					default = ifelse(lang:getCode() == lg_ar:getCode(), "ـِيَّة", "ـية"),
				},
			}
		end,
		title = function(args)
			if args.pl then
				return "relative nouns (nisba)"
			end
			return "relative noun (nisba)"
		end,
		desc = function(args, lang)
			if not args[1] then
				return ""
			end
			return (
				"composed from "
				.. show_affix(
					lang,
					{
						args,
						{args.suffix, pos="feminine nisba"},
					}
				)
			)
		end,
	},
	["relative-a"] = {
		"nominals",
		params = function(lang)
			return {
				[1] = {
					required = true,
				},
				[2] = {
					alias_of = "t",
				},
				["tr"] = {},
				["pl"] = {
					type = "boolean",
				},
				["suffix"] = {
					default = ifelse(lang:getCode() == lg_ar:getCode(), "ـَة", "ـة"),
				},
				
				["t"] = {
					required = true,
				},
			}
		end,
		title = function(args)
			if args.pl then
				return "relative nouns (nisba)"
			end
			return "relative noun (nisba)"
		end,
		desc = function(args, lang)
			if not args[1] then
				return ""
			end
			return (
				"composed from "
				.. show_affix(
					lang,
					{
						args,
						{args.suffix, pos="feminine ending"},
					}
				)
			)
		end,
	},
	["relative-linking"] = {
		"nominals",
		params = function(lang)
			return {
				[1] = {
					required = true,
				},
				[2] = {
					alias_of = "t",
				},
				[3] = {
					alias_of = "linking",
				},
				["tr"] = {},
				["pl"] = {
					type = "boolean",
				},
				["suffix"] = {
					default = ifelse(lang:getCode() == lg_ar:getCode(), "ـِيّ", "ـي"),
				},
			
				["t"] = {
					required = true,
				},
				["linking"] = {
					required = true,
				}
			}
		end,
		title = function(args)
			if args.pl then
				return "relative adjectives (nisba)"
			end
			return "relative adjective (nisba)"
		end,
		desc = function(args, lang)
			if not args[1] then
				return ""
			end
			return (
				"composed from "
				.. show_affix(
					lang,
					{
						args,
						args.linking,
						{args.suffix, pos = "nisba"},
					}
				)
			)
		end,
	},
	["relative-linking-noun"] = {
		"nominals",
		params = function(lang)
			return {
				[1] = {
					required = true,
				},
				[2] = {
					alias_of = "t",
				},
				[3] = {
					alias_of = "linking",
				},
				["tr"] = {},
				["pl"] = {
					type = "boolean",
				},
			
				["t"] = {
					required = true,
				},
				["linking"] = {
					required = true,
				},
				["suffix"] = {
					default = ifelse(lang:getCode() == lg_ar:getCode(), "ـِيّ", "ـي"),
				}
			}
		end,
		title = function(args)
			if args.pl then
				return "relative nouns (nisba)"
			end
			return "relative noun (nisba)"
		end,
		desc = function(args, lang)
			if not args[1] then
				return ""
			end
			return (
				"composed from "
				.. show_affix(
					lang,
					{args, args.linking, args.suffix}
				)
			)
		end,
	},
	["form"] = {
		"verbs",
		params = {
			[1] = {
				alias_of = "wazn",
			},
			["wazn"] = {
				required = true,
			},
		},
		fragment = function(args) return "Form_" .. args.wazn end,
		title = function(args) return "form " .. args.wazn end,
	},
	["instance noun"] = "nominals",
	["noun of place"] = "nominals",
	["occupational noun"] = "nominals",
	["passive participle"] = {
		"nominals",
		derived = true,
	},
	["reduplicated"] = {
		glossary = "reduplication",
	},
	["singulative noun"] = "nominals",
	["tool noun"] = "nominals",
	["verbal noun"] = "nominals",
}

local radicals = {
	["Arab"] = {
		["ء"] = true,
		["ب"] = true,
		["ت"] = true,
		["ث"] = true,
		["ج"] = true,
		["ح"] = true,
		["خ"] = true,
		["د"] = true,
		["ذ"] = true,
		["ر"] = true,
		["ز"] = true,
		["س"] = true,
		["ش"] = true,
		["ص"] = true,
		["ض"] = true,
		["ط"] = true,
		["ظ"] = true,
		["ع"] = true,
		["غ"] = true,
		["ف"] = true,
		["ق"] = true,
		["ك"] = true,
		["ل"] = true,
		["م"] = true,
		["ن"] = true,
		["ه"] = true,
		["و"] = true,
		["ي"] = true,
		["گ"] = true,
		["چ"] = true,
		["پ"] = true,
		["ڭ"] = true,
	},
	["Latn"] = {
		["'"] = true,
		["b"] = true,
		["t"] = true,
		["θ"] = true,
		["d"] = true,
		["δ"] = true,
		["f"] = true,
		["ġ"] = true,
		["g"] = true,
		["għ"] = true,
		["h"] = true,
		["ħ"] = true,
		["j"] = true,
		["k"] = true,
		["l"] = true,
		["m"] = true,
		["n"] = true,
		["p"] = true,
		["q"] = true,
		["r"] = true,
		["s"] = true,
		["ş"] = true,
		["t"] = true,
		["v"] = true,
		["w"] = true,
		["x"] = true,
		["y"] = true,
		["ż"] = true,
		["z"] = true,
		["θ"] = true,
	}
}

local function validateRoot(rootTable, joined_root)
	if type(rootTable) ~= "table" then
		error("rootTable is not a table", 2)
	end

	local len = #rootTable

	if len < 3 then
		error("Root must have at least three radicals.")
	end
	
	if sc == nil then
		 sc = lang:findBestScript(joined_root):getCode()
	end

	for i, radical in ipairs(rootTable) do
		if not radicals[sc][radical] then
			error("Unrecognized radical " .. radical .. " in " .. joined_root)
		end
	end
end

function export.root(frame)
	local output = {}
	local categories = {}
	local title = mw.title.getCurrentTitle()
	local namespace = title.nsText
	local fulltitle = title.fullText

	if frame.args["lang"] then
		lang = require("Module:languages").getByCode(frame.args["lang"])
	else
		error("Please provide a language code.")
	end

	local subpage = "Appendix:" .. lang:getCanonicalName() .. " roots/"
	local fulltitle = rsubn(fulltitle, rsubn(subpage, "([^%w])", "%%%1"), "")

	local params = {
		[1] = { list = true },
		["nocat"] = { type = "boolean" },
		["plain"] = { type = "boolean" },
		["notext"] = { type = "boolean" },
		["sense"] = {}
	}

	local args = require("Module:parameters").process(frame:getParent().args, params)
	local rootLetters = {}
	local roots = args[1]

	local plain = args["plain"]
	if frame.args["plain"] then
		plain = true
	end

	local langCode = lang:getCode()

	local separator = " "
	if separator_langs[langCode] then
		separator = "-"
	else
		separator = " "
	end

	local roots_len = #roots

	if #roots == 0 and namespace == "Template" then
		if template_preview_per_langcode[langCode] ~= nil then
			table.insert(rootLetters, rsplit(template_preview_per_langcode[langCode], separator))
		else
			table.insert(rootLetters, rsplit("ك ت ب", separator))
		end
	elseif #roots ~= 0 then
		for _, root in ipairs(roots) do
			table.insert(rootLetters, rsplit(root, separator))
		end
	else
		table.insert(rootLetters, rsplit(fulltitle, separator))
	end

	local joined_roots = {}
	for i, rootLetter in ipairs(rootLetters) do
		table.insert(joined_roots, table.concat(rootLetter, separator))
		validateRoot(rootLetter, joined_roots[i])
	end

	local sense = args["sense"]
	local sense_formatted = ""
	if sense ~= nil then
		sense_formatted = " (" .. sense .. ") "
	end

	if fulltitle == joined_roots[1] then
		if namespace == "" then
			error("The root page should be in the Appendix namespace. Please move it to : [[" ..
				subpage .. joined_roots[1] .. "]]")
		end

		if roots_len > 1 then
			error("There should be only one root.")
		end

		table.insert(output,
			m_headword.full_headword({ lang = lang, pos_category = "roots", categories = {}, heads = { fulltitle }, nomultiwordcat = true, noposcat = true }))

		if args["nocat"] then
			return table.concat(output)
		else
			return table.concat(output) .. table.concat(categories)
		end
	else
		local link_texts = {}
		local term_counts = {}

		for i, joined_root in ipairs(joined_roots) do
			local link_text = subpage .. joined_root
			table.insert(link_texts, link(link_text, joined_root .. sense_formatted, sense))
			table.insert(
				categories,
				m_utilities.format_categories(
					{ lang:getCanonicalName() .. " terms belonging to the root " .. joined_root .. sense_formatted },
					lang)
			)
			table.insert(term_counts,
				mw.site.stats.pagesInCategory(
					lang:getCanonicalName() .. " terms belonging to the root " .. joined_root .. sense_formatted, "pages")
			)
		end

		if args["nocat"] or plain then
			if args["nocat"] then
				return table.concat(link_texts, ", ")
			else
				return table.concat(link_texts, ", ") .. table.concat(categories)
			end
		else
			local link_text_output = ""
			for i, link_text in ipairs(link_texts) do
				link_text_output = link_text_output ..
					"\n|-\n| " .. link_text ..
					"\n|-\n| [[:Category:" ..
					lang:getCanonicalName() ..
					" terms belonging to the root " ..
					joined_roots[i] ..
					sense_formatted .. "|" .. term_counts[i] .. " term" .. (term_counts[i] == 1 and "" or "s") .. "]]\n"
			end
			
			local color = "grey"
			
			if color_langs[langCode] ~= nil then
				color = color_langs[langCode]
			end

			local wikicode = mw.getCurrentFrame():expandTemplate {
				title = 'inflection-table-top',
				args = {
					title = "-",
					palette = color,
					class = "floatright tr-alongside"
				}
			}

			wikicode = wikicode .. [=[
! [[w:Semitic root|Root]=] .. (#term_counts == 1 and "" or "s") .. [=[]]]=]

			wikicode = wikicode .. link_text_output

			wikicode = wikicode .. mw.getCurrentFrame():expandTemplate {
				title = 'inflection-table-bottom',
			}
			return wikicode .. table.concat(categories)
		end
	end
end

local function iffn(val, ...)
	if type(val) == "function" then
		return val(unpack(arg))
	end
	return val
end

function export.etym(frame)
	local params = {
		[1] = {
			alias_of = "lang",
		},
		[2] = {
			alias_of = "class"
		},
		["fragment"] = {},
		["nocat"] = {
			type = boolean,
		},

		["lang"] = {
			type = "language",
			replaced_by = false,
			required = true,
		},
		["class"] = {
			required = true,
		},
	}
	
	local args, extra = m_params.process(frame:getParent().args, params, true)
	local fixed_indices = {}
	for k, v in pairs(extra) do
		if type(k) == "number" then
			k = k - 2
		end
		fixed_indices[k] = v
	end
	extra = fixed_indices
	
	if args.lang:getFamily():getCode() ~= lg_sem_arb then
		error(
			args.lang:getCode()
			.. "'s family is  "
			.. args.lang:getFamily():getCode()
			.. ", not "
			.. lg_sem_arb
		)
	end
	
	local lookup = appendices[mw.ustring.lower(args.class)]
	local lookup_args = {}
	if not lookup then
		error("Unrecognized word type " .. mw.ustring.lower(args.class))
	end
	if lookup.glossary then
		return "[[Appendix:Glossary#" .. lookup.glossary .. "]]"
	end
	if lookup.params then
		lookup_args = m_params.process(extra, iffn(lookup.params, args.lang))
	end

	local appendix = nil
	if lookup.glossary then
		appendix = "Glossary"
	else
		local appendix_lang = args.lang:getCanonicalName()
		local appendix_title = ifelse(type(lookup) == "string", lookup, iffn(lookup[1], args.lang))
		appendix = appendix_lang .. " " .. appendix_title
		if not mw.title.new(appendix, "Appendix").exists then
			appendix_lang = lg_ar:getCanonicalName()
			appendix_title = ifelse(type(lookup) == "string", lookup, iffn(lookup[1], lg_ar))
			appendix = appendix_lang .. " " .. appendix_title
		end
	end
	
	local title = args.class
	local desc = ""
	local intro = ""
	if lookup.derived then
		intro = "derived from the "
	end
	if type(lookup) ~= "string" then
		title = iffn(lookup.title, lookup_args, args.lang) or ""
		desc = iffn(lookup.desc, lookup_args, args.lang) or ""
		
		if mw.ustring.match(args.class, "^%u.*") then
			if intro == "" then
				title = ucfirst(title) or ""
			else
				intro = ucfirst(intro) or ""
			end
		end
	end
	local fragment = (
		iffn(lookup.fragment, lookup_args, args.lang)
		or ucfirst(iffn(lookup.title, {pl=true}, args.lang))
		or pluralize(ucfirst(args.class))
	) or ""

	return (
		intro
		.. "[[Appendix:"
		.. appendix
		.. ifelse(fragment, "#" .. fragment, "")
		.. "|"
		.. title
		.. "]] "
		.. desc
	)
end

return export