انتقل إلى المحتوى

وحدة:ar-verb-infobox

من ويكاموس، القاموس الحر
-- Module:ar-verb-infobox
-- By: Wael (User:ForzaGreen)
-- Creates an infobox for Arabic verbs with Wikidata integration

local p = {}

local ar_verb = require("Module:ar-verb")

-------------------------------------------------------------------------------
-- Constants and Mappings
-------------------------------------------------------------------------------

-- Map Wikidata QIDs to Arabic conjugation class names
-- Each entry has: [1] = Arabic display, [2] = internal code for ar-verb.lua
local CONJUGATION_CLASS_MAP = {
	-- Form-I variants (6 vowel patterns)
	["Q56070813"] = {"فعَل يفعُل", "I/u~u"},   -- ضرب يضرُب
	["Q56070814"] = {"فعَل يفعِل", "I/a~i"},   -- فتح يفتِح
	["Q56070815"] = {"فعَل يفعَل", "I/a~a"},   -- ذهب يذهَب
	["Q56070816"] = {"فعِل يفعَل", "I/i~a"},   -- علم يعلَم
	["Q136942429"] = {"فعَل يفعُل", "I/a~u"},  -- كتب يكتُب
	["Q136942765"] = {"فعِل يفعِل", "I/i~i"},  -- حسب يحسِب

	-- Forms II-XV
	["Q56071242"] = {"فعّل", "II"},
	["Q56071243"] = {"فاعل", "III"},
	["Q56071244"] = {"أفعل", "IV"},
	["Q56071245"] = {"تفعّل", "V"},
	["Q124709192"] = {"تفاعل", "VI"},
	["Q56071248"] = {"انفعل", "VII"},
	["Q56071247"] = {"افتعل", "VIII"},
	["Q136393994"] = {"افعلّ", "IX"},
	["Q56071246"] = {"استفعل", "X"},
	["Q56071249"] = {"افعالّ", "XI"},
	["Q56071250"] = {"افعوعل", "XII"},
	["Q56071251"] = {"افعوّل", "XIII"},

	-- Quadriliteral
	["Q135840786"] = {"فعلل", "Iq"},
	["Q135840787"] = {"تفعلل", "IIq"},
	["Q135840788"] = {"افعنلل", "IIIq"},
	["Q135840789"] = {"افعللّ", "IVq"},
}

-- Special case: Ignore generic Form-I (must use specific variants)
local FORM_I_GENERIC = "Q56070812"

-- Arabic labels for fields
local FIELD_LABELS = {
	root = "الجذر",
	conjugation_class = "الوزن الصرفي",
	transitivity = "التعدية",
	verbal_noun = "المصدر",
	active_participle = "اسم الفاعل",
	passive_participle = "اسم المفعول",
}

-- Wikidata property IDs
local PROPERTIES = {
	root = "P5920",              -- جذر عربي
	conjugation_class = "P5186", -- صنف التصريف
	transitivity = "P9295",      -- التعدية
}

-------------------------------------------------------------------------------
-- Helper Functions
-------------------------------------------------------------------------------

-- Map conjugation class QIDs to Arabic labels
-- Returns: display_string, first_arabic_wazn, first_internal_code
local function format_conjugation_classes(qids_string, add_links)
	if not qids_string or qids_string == "" then
		return nil, nil, nil
	end

	-- Parse QIDs (may be separated by <br/> or commas)
	local qids = {}
	for qid in qids_string:gmatch("(Q%d+)") do
		table.insert(qids, qid)
	end

	local arabic_labels = {}
	local internal_codes = {}

	for _, qid in ipairs(qids) do
		if qid ~= FORM_I_GENERIC then
			local mapped = CONJUGATION_CLASS_MAP[qid]
			if mapped then
				local label = mapped[1]
				if add_links then
					label = "[[d:" .. qid .. "|" .. label .. "]]"
				end
				table.insert(arabic_labels, label)
				table.insert(internal_codes, mapped[2])
			end
		end
	end

	if #arabic_labels == 0 then
		return nil, nil, nil
	end

	return table.concat(arabic_labels, "، "), arabic_labels[1], internal_codes[1]
end

-- Generate derived forms (verbal noun, participles) using ar-verb module
local function generate_derived_forms(root_string, conj_wazn)
	-- Remove spaces from root (Wikidata uses "ك ت ب", ar-verb needs "كتب")
	local clean_root = root_string:gsub("%s+", "")

	local word_spec = ar_verb.do_generate_forms({["جذر"] = clean_root, ["وزن"] = conj_wazn})

	local vn = word_spec.forms.vn and word_spec.forms.vn[1] and word_spec.forms.vn[1].form
	local ap = word_spec.forms.ap and word_spec.forms.ap[1] and word_spec.forms.ap[1].form
	local pp = word_spec.forms.pp and word_spec.forms.pp[1] and word_spec.forms.pp[1].form

	-- Convert empty strings or "?" to nil
	if vn == "" or vn == "?" or vn == "؟" then vn = nil end
	if ap == "" or ap == "?" or ap == "؟" then ap = nil end
	if pp == "" or pp == "?" or pp == "؟" then pp = nil end

	return vn, ap, pp
end

function p.do_generate_forms(params)
	return generate_derived_forms(params["جذر"], params["وزن"])
end

function p.arverb_generate_forms(clean_root, conj_wazn)
	return ar_verb.do_generate_forms({["جذر"] = clean_root, ["وزن"] = conj_wazn})
end

-- Debug functions:
p.format_conjugation_classes = format_conjugation_classes
p.generate_derived_forms = generate_derived_forms

-------------------------------------------------------------------------------
-- Main Function (called by template)
-------------------------------------------------------------------------------
function p.main(frame)
	-- Get arguments
	local args = frame.args
	if frame.getParent then
		local parent = frame:getParent()
		if parent and parent.args then
			for k, v in pairs(parent.args) do
				if v and v ~= "" then
					args[k] = v
				end
			end
		end
	end

	local lid = args.wikidata or args["معرف ويكي بيانات"] or args[1]

	if not lid or lid == "" then
		return "خطأ: يجب توفير معرف ويكي بيانات"
	end

	-- Get entity directly
	local entity = mw.wikibase.getEntity(lid)
	if not entity then
		return "خطأ: لا يمكن العثور على المدخل " .. lid
	end

	-- Get lemma
	local lemma = "غير متوفر"
	if entity.lemmas and entity.lemmas.ar then
		lemma = entity.lemmas.ar.value
	end

	-- Get root directly from entity
	local root_raw = nil
	local root_display = "غير متوفر"
	if entity.claims and entity.claims[PROPERTIES.root] then
		local root_claim = entity.claims[PROPERTIES.root][1]
		if root_claim and root_claim.mainsnak and root_claim.mainsnak.datavalue then
			local root_id = root_claim.mainsnak.datavalue.value.id
			-- Fetch the root entity and get its lemma
			local root_entity = mw.wikibase.getEntity(root_id)
			if root_entity and root_entity.lemmas and root_entity.lemmas.ar then
				root_raw = root_entity.lemmas.ar.value
				root_display = root_raw
			end
		end
	end

	-- Get conjugation classes directly from entity
	local conj_qids = {}
	if entity.claims and entity.claims[PROPERTIES.conjugation_class] then
		for _, claim in ipairs(entity.claims[PROPERTIES.conjugation_class]) do
			if claim.mainsnak and claim.mainsnak.datavalue then
				local qid = claim.mainsnak.datavalue.value.id
				if qid ~= FORM_I_GENERIC then
					table.insert(conj_qids, qid)
				end
			end
		end
	end

	-- Map conjugation classes - get plain text first for internal use
	local conj_qids_string = table.concat(conj_qids, " ")
	local conj_display_plain, conj_arabic, conj_code = format_conjugation_classes(conj_qids_string, false)

	-- Then get version with Wikidata links for display
	local conj_display_linked, _, _ = format_conjugation_classes(conj_qids_string, true)

	-- Build conjugation display with edit icon
	local conj_display_with_icon = nil
	if conj_display_linked and conj_display_linked ~= "" then
		-- Add edit icon manually
		local edit_icon = ' <span class="penicon">'
			.. "[[ملف:Arbcom ru editing.svg|10px|baseline|"
			.. "تعديل في ويكي بيانات"
			.. "|link=https://www.wikidata.org/wiki/Lexeme:" .. lid .. "?uselang=ar#" .. PROPERTIES.conjugation_class .. "]]"
			.. "</span>"
		conj_display_with_icon = conj_display_linked .. edit_icon
	end

	-- Get transitivity
	local wikidata = require("Module:Wikidata.Ca")
	local transitivity = wikidata.claim{
		item = lid,
		property = PROPERTIES.transitivity,
		editicon = "no"
	} or "غير متوفر"

	-- Use plain Arabic wazn (not the linked version) for ar_verb functions
	local verb_type = ar_verb.get_verb_type({["جذر"] = root_raw, ["وزن"] = conj_arabic})

	-- Generate derived forms using the plain Arabic wazn from CONJUGATION_CLASS_MAP
	local vn, ap, pp = generate_derived_forms(root_raw, conj_arabic)

	-- Build simple infobox table using mw.html
	local html = mw.html.create()

	local infobox = html:tag('table')
		:addClass('infobox')
		:css('width', '22em')
		:css('margin', '0.5em 0 0.5em 1em')
		:css('float', 'left')
		:css('clear', 'left')
		:css('border', '1px solid')
		:css('border-color', 'var(--border-color-base, #aaa)')

	-- Title (increased from 120% to 150%)
	-- Use inline style to let site CSS override for dark mode
	infobox:tag('tr')
		:tag('th')
		:attr('colspan', '2')
		:attr('style', 'text-align: center; background-color: #CEDEFF; font-size: 150%; font-weight: bold; padding: 0.5em;')
		:wikitext(lemma)

	-- Section header (increased from default to 115%)
	infobox:tag('tr')
		:tag('th')
		:attr('colspan', '2')
		:attr('style', 'text-align: center; background-color: #CEDEFF; font-size: 115%; padding: 0.3em;')
		:wikitext(verb_type)

	-- Helper function to get verbal nouns from Wikidata lexeme forms
	local function get_verbal_nouns_from_wikidata()
		if not entity.forms then
			return nil, nil
		end

		local verbal_nouns = {}
		local form_ids = {}

		for _, form in ipairs(entity.forms) do
			if form.grammaticalFeatures then
				for _, feature in ipairs(form.grammaticalFeatures) do
					if feature == "Q1350145" then  -- Q1350145 = verbal noun
						if form.representations and form.representations.ar then
							table.insert(verbal_nouns, form.representations.ar.value)
							table.insert(form_ids, form.id)
						end
					end
				end
			end
		end

		if #verbal_nouns == 0 then
			return nil, nil
		end
		return verbal_nouns, form_ids
	end

	-- Helper function to add row
	local function add_row(label, value, property_id, make_link, custom_value_with_icon, is_verbal_noun)
		local row = infobox:tag('tr')
		row:tag('th')
			:css('text-align', 'right')
			:css('vertical-align', 'top')
			:css('padding', '0.3em 0.5em')
			:css('font-weight', 'bold')
			:wikitext(label)

		local data_cell = row:tag('td')
			:css('text-align', 'right')
			:css('padding', '0.3em 0.5em')

		-- If custom_value_with_icon is provided, use it directly (for conjugation class)
		if custom_value_with_icon then
			data_cell:wikitext(custom_value_with_icon)
		-- If we have a property, get value from Wikidata with edit link
		elseif property_id then
			local full_value = wikidata.claim{
				item = lid,
				property = property_id,
				editicon = "yes"
			}
			-- Use Wikidata value if available, otherwise use our computed value
			if full_value and full_value ~= "" then
				data_cell:wikitext(full_value)
			elseif value and value ~= "" and value ~= "غير متوفر" then
				if make_link then
					data_cell:wikitext("[[" .. value .. "]]")
				else
					data_cell:wikitext(value)
				end
			else
				data_cell:wikitext("؟")
			end
		else
			-- No property, just use the value we computed
			if value and value ~= "" and value ~= "غير متوفر" then
				if make_link then
					data_cell:wikitext("[[" .. value .. "]]")
				else
					data_cell:wikitext(value)
				end
			else
				-- For verbal noun, try to fetch from Wikidata lexeme forms
				if is_verbal_noun then
					local vn_from_wds, form_ids = get_verbal_nouns_from_wikidata()
					if vn_from_wds and #vn_from_wds > 0 then
						-- Surround each verbal noun with [[ ]] and concatenate with Arabic comma
						local linked_vns = {}
						for _, vn in ipairs(vn_from_wds) do
							table.insert(linked_vns, "[[" .. vn .. "]]")
						end
						local vn_wds_wikitext = table.concat(linked_vns, "، ")

						local form_id = form_ids[1]
						local wikidata_icon = ' <span class="penicon">'
							.. "[[ملف:Arbcom ru editing.svg|10px|baseline|"
							.. "تعديل في ويكي بيانات"
							.. "|link=https://www.wikidata.org/entity/" .. form_id .. "?uselang=ar]]"
							.. "</span>"
						data_cell:wikitext(vn_wds_wikitext .. wikidata_icon)
					else
						data_cell:wikitext("؟")
					end
				else
					data_cell:wikitext("؟")
				end
			end
		end
	end

	-- Add rows
	add_row(FIELD_LABELS.root, root_display, PROPERTIES.root)
	add_row(FIELD_LABELS.conjugation_class, nil, nil, nil, conj_display_with_icon)
	add_row(FIELD_LABELS.transitivity, transitivity, PROPERTIES.transitivity)
	add_row(FIELD_LABELS.verbal_noun, vn, nil, true, nil, true)  -- is_verbal_noun = true
	add_row(FIELD_LABELS.active_participle, ap, nil, true)
	add_row(FIELD_LABELS.passive_participle, pp, nil, true)

	-- Footer with Wikidata link
	local footer = infobox:tag('tr')
	local footer_cell = footer:tag('td')
		:attr('colspan', '2')
		:css('text-align', 'left')
		:css('border-top', '1px dotted #aaa')
		:css('padding', '0.3em 0.5em')
		:css('font-size', '85%')

	-- Create Wikidata link that wraps both icon and ID
	local wikidata_link = '[https://www.wikidata.org/wiki/Lexeme:' .. lid .. '?uselang=ar '
		.. '[[ملف:Wikidata-logo.svg|15px|class=skin-invert|ويكي بيانات|link=]]'
		.. ' <small>' .. lid .. '</small>]'

	footer_cell:wikitext(wikidata_link)

	-- Add category for pages using Wikidata
	local output = tostring(html) .. '[[Category:صفحات تستخدم ويكي بيانات]]'

	return output
end

return p

-- Debug examples:
-- =p.arverb_generate_forms("كتب", "I/a~u")
-- =p.main(mw.getCurrentFrame():newChild{args={[1]="L12100"}})