وحدة:Requested move

-- This module implements {{requested move}}.

-- Load necessary modules
local getArgs = require('Module:Arguments').getArgs
local tableTools = require('Module:TableTools')
local yesno = require('Module:Yesno')
local mRedirect = require('Module:Redirect')

-- Set static values
local defaultNewPagename = '?' -- Name of new pages that haven't been specified

local p = {}

--------------------------------------------------------------------------------
-- Helper functions
--------------------------------------------------------------------------------
 
local function err(msg, numargs, reason, count)
	-- Generates a wikitext error message
	local commented = '<!-- {{نسخ:نقل|'
	if count ~= 1 then
	   commented = commented .. 'إلى1='
	end
	commented = commented .. numargs[1]['إلى']
	for i = 2,count do
		commented = commented .. string.format('|من%i=%s', i, (numargs[i]['من'] or ''))
		commented = commented .. string.format('|إلى%i=%s', i, (numargs[i]['إلى'] or ''))
	end
	if reason then 
	    commented = commented .. '|السبب=' .. reason
	end
	commented = commented .. '}} -->'
	return string.format('{{خطأ|%s}}', msg) .. commented
end


local function validateTitle(page, paramName, paramNum) 
	-- Validates a page name, and if it is valid, returns true and the title
	-- object for that page. If it is not valid, returns false and the
	-- appropriate error message.

	-- Check for a small subset of characters that cannot be used in MediaWiki
	-- titles. For the full set of restrictions, see
	-- [[Wikipedia:Page name#Technical restrictions and limitations]]. This is
	-- also covered by the invalid title check, but with this check we can give
	-- a more specific error message.
	local invalidChar = page:match('[#<>%[%]|{}]')
	if invalidChar then
		local msg = 'حرف غير صالح "'
			.. invalidChar
			.. '" في الوسيط "'
			.. paramName
			.. paramNum
		return false, msg
	end

	-- Get the title object. This also checks for invalid titles that aren't
	-- covered by the previous check.
	local titleObj = mw.title.new(page)
	if not titleObj then
		local msg = 'عنوان غير صالح في الوسيط  "'
			.. paramName
			.. paramNum 
			.. '"; افحص [[:en:Wikipedia:Page name#'
			.. 'Technical restrictions and limitations|الأحرف غير المسموح به]]'
		return false, msg
	end

	-- Check for interwiki links. Titles with interwikis make valid title
	-- objects, but cannot be created on the local wiki.
	local interwiki = titleObj.interwiki
	if interwiki and interwiki ~= '' then
		local msg = 'عنوان غير صالح في الوسيط  "'
			.. paramName
			.. paramNum 
			.. '"; has [[مساعدة:وصلات إنترويكي|بادئة انترويكي]] "'
			.. titleObj.interwiki
			.. ':"'
		return false, msg
	end

	return true, titleObj
end

--------------------------------------------------------------------------------
-- Validate title entry point (used at [[قالب:RMassist/core]])
--------------------------------------------------------------------------------
function p.validateTitle(frame)
	local value = frame.args[1]
	local validTitle, currentTitle = validateTitle(value or '', '1', '')
	if not validTitle then
		-- If invalid, the second parameter is the error message.
		return currentTitle
	end
	return 'yes'
end

--------------------------------------------------------------------------------
-- Confirm protection levels (used at [[قالب:Requested move/dated]])
--------------------------------------------------------------------------------
local function _protected(pagetitle)
	local levels = mw.title.new(pagetitle).protectionLevels
	local levelMove = levels['move'] and levels['move'][1]
	local levelEdit = levels['edit'] and levels['edit'][1]
	local levelCreate = levels['create'] and levels['create'][1]
	if levelMove == 'sysop' 
	or levelEdit == 'sysop' 
	or levelEdit == 'editprotected' 
	or levelCreate == 'sysop' then
		return 'sysop'
	elseif levelMove == 'editeditorprotected' 
	or levelEdit == 'editeditorprotected' 
	or levelCreate == 'editeditorprotected' then
		return 'editor'
	end
end

function p.protected(frame)
	local args = getArgs(frame, {parentOnly = true})
	if args.protected then
		return _protected(args.protected)
	end
end

--------------------------------------------------------------------------------
-- Main function
--------------------------------------------------------------------------------

function p.main(frame)
	----------------------------------------------------------------------------
	-- Initialise variables and preprocess the arguments
	----------------------------------------------------------------------------
	
	local args = getArgs(frame, {parentOnly = true})
	local title = mw.title.getCurrentTitle()

	--[[
	-- To iterate over the current1, new1, current2, new2, ... arguments
	-- we get an array of tables sorted by number and compressed so that
	-- it can be traversed with ipairs.	The table format looks like this:
	-- {
	--  {current = x, new = y, num = 1},
	--  {current = z, new = q, num = 2},
	--  ...
	-- }
	-- The "num" field is used to correctly preserve the number of the parameter
	-- that was used, in case users skip any numbers in the invocation.
	--
	-- The current1 parameter is a special case, as it does not need to be
	-- specified. To avoid clashes with later current parameters, we need to
	-- add it to the args table manually.
	--
	-- Also, we allow the first positional parameter to be an alias for the
	-- new1 parameter, so that the syntax for the old templates
	-- {{requested move}} and {{move-multi}} will both be supported.
	--
	-- The "multi" variable tracks whether we are using the syntax previously
	-- produced by {{requested move}}, or the syntax previously produced by
	-- {{move-multi}}. For the former, multi is false, and for the latter it is
	-- true.
	--]]
	if not args["من1"] then
		args["من1"] = title.subjectPageTitle.prefixedText
	end

	-- Find the first new page title, if specified, and keep a record of the
	-- prefix used to make it; the prefix will be used later to make error
	-- messages.
	local firstNewParam
	if args["إلى1"] then
		firstNewParamPrefix = 'إلى'
	elseif args[1] then
		args["إلى1"] = args[1]
		firstNewParamPrefix = ''
	else
		firstNewParamPrefix = ''
	end

	-- Build the sorted argument table.
	local argsByNum = {}
	for k, v in pairs(args) do
		k = tostring(k)
		local prefix, num = mw.ustring.match(k, '^(%a*)([1-9][0-9]*)$')
        if prefix == 'من' or prefix == 'إلى' then
			num = tonumber(num)
			local subtable = argsByNum[num] or {}
			subtable[prefix] = v
			subtable.num = num
			argsByNum[num] = subtable
		end
	end
	argsByNum = tableTools.compressSparseArray(argsByNum)
    
	-- Calculate the number of arguments and whether we are dealing with a
	-- multiple nomination.
	local argsByNumCount = #argsByNum
	local multi = (argsByNumCount >= 2)

	--[[
	-- Validate new params.
	-- This check ensures we don't have any absent new parameters, and that
	-- users haven't simply copied in the values from the documentation page.
	--]]
	if multi then
		for i, t in ipairs(argsByNum) do
			local new = t["إلى"]
			local num = t.num
			if not new or new == 'عنوان جديد لـ ' .. tostring(num) then
				argsByNum[i]["إلى"] = defaultNewPagename
			end
		end
	else
		local new = argsByNum[1]["إلى"]
		if not new or new == 'عنوان جديد' then
			argsByNum[1]["إلى"] = defaultNewPagename
		end
	end
	
	----------------------------------------------------------------------------
	-- Error checks
	----------------------------------------------------------------------------
	
	-- Subst check
	if not mw.isSubsting() then
		local lb = mw.text.nowiki('{{')
		local rb = mw.text.nowiki('}}')
		local msg = '<strong class="error">'
			.. 'هذا القالب يجب أن [[:en:Wikipedia:Template substitution|يُنسخ]];'
			.. ' استبدل بـ%sنقل%s  %sنسخ:نقل%s'
			.. '</strong>'
		msg = string.format(msg, lb, rb, lb, rb)
		return msg
	end
	
	-- Check we are on a talk page
	if not title.isTalkPage then
		local msg = '[[قالب:نقل]] يجب أن يستعمل في صفحة نقاش, مثلا [[%s:%s]]'
		msg = string.format(msg, mw.site.namespaces[title.namespace].talk.name, title.text)
		return err(msg, argsByNum, args["السبب"], argsByNumCount)
	end
	
	-- Check the arguments
	local currentDupes, newDupes = {}, {}
	for i, t in ipairs(argsByNum) do
		local current = t["من"]
		local new = t["إلى"]
		local num = t.num
		local validCurrent
		local currentTitle
		local subjectSpace

		-- Check for invalid or missing currentn parameters
		-- This check must come first, as mw.title.new will give an error if
		-- it is given invalid input.
		if not current then
			local msg = 'وسيط "من%d" مفقود;'
				.. ' أضفه أو أزل الوسيط "إلى%d"'
			msg = string.format(msg, num, num)
			return err(msg, argsByNum, args["السبب"], argsByNumCount)
		end

		-- Get the currentn title object, and check for invalid titles. This check
		-- must come before the namespace and existence checks, as they will
		-- produce script errors if the title object doesn't exist.
		validCurrent, currentTitle = validateTitle(current, 'من', num)
		if not validCurrent then
			-- If invalid, the second parameter is the error message.
			local msg = currentTitle 
			return err(msg, argsByNum, args["السبب"], argsByNumCount)
		end

		-- Category namespace check
		subjectSpace = mw.site.namespaces[currentTitle.namespace].subject.id
		if subjectSpace == 14 then
			local msg = '[[قالب:نقل]] is not for categories,'
				.. ' see [[Wikipedia:Categories for discussion]]'
			return err(msg, argsByNum, args["السبب"], argsByNumCount)
		
		-- File namespace check
		elseif subjectSpace == 6 then
			local msg = '[[قالب:نقل]] is not for files;'
				.. ' see [[Wikipedia:Moving a page#Moving a file page]]'
				.. ' (use [[قالب:Rename media]] instead)'
			return err(msg, argsByNum, args["السبب"], argsByNumCount)

		-- Draft and User namespace check
		elseif subjectSpace == 2 or subjectSpace == 118 then
			local msg = '[[قالب:نقل]] is not for moves from draft or user space.'
				.. '<br>If you would like to submit your draft for review, add <code>{{tlf|subst:submit}}</code>'
				    .. 'to the top of the page.'
				.. '<br>Otherwise, see [[مساعدة:How to move a page]] for instructions.'
				.. '<br>If you cannot move it yourself, see [[Wikipedia:Requested moves#Requesting technical moves|Requesting technical moves]].'
			return err(msg, argsByNum, args["السبب"], argsByNumCount)
		end

		-- Request to move a single page must be placed on that page's talk, or the page it redirects to
		if not multi and args["من1"] ~= title.subjectPageTitle.prefixedText then
			local idealpage = mw.title.new(args["من1"]).talkPageTitle
			local rtarget = mRedirect.getTarget(idealpage)
			if rtarget == title.prefixedText then
				multi = true
			else
				local msg = 'Request to move a single page must be placed on that page\'s talk or the page its talk redirects to'
				return err(msg, argsByNum, args["السبب"], argsByNumCount)
			end
		end

		-- Check for non-existent titles.
		if not currentTitle.exists then
			local msg = 'يجب إنشاء [[:%s]] قبل طلب نقلها'
			msg = string.format(msg, current)
			return err(msg, argsByNum, args["السبب"], argsByNumCount)
		end

		-- Check for duplicate current titles
		-- We know the id isn't zero because we have already checked for
		-- existence.
		local currentId = currentTitle.id
		if currentDupes[currentId] then
			local msg = 'وُجد عنوان مكرر ("'
				.. currentTitle.prefixedText
				.. '"); لا يمكن نقل نفص الصفحة إلى وجهتين مختلفتين'
			return err(msg, argsByNum, args["السبب"], argsByNumCount)
		else
			currentDupes[currentId] = true
		end

		-- Check for invalid new titles. This check must come before the
		-- duplicate title check for new titles, as it will produce a script
		-- error if the title object doesn't exist.
		local validNew, newTitle = validateTitle(
			new,
			multi and 'إلى' or firstNewParamPrefix,
			num
		)
		if not validNew then
			-- If invalid, the second parameter is the error message.
			local msg = newTitle
			return err(msg, argsByNum, args["السبب"], argsByNumCount)
		end

		-- Check for duplicate new titles.
		-- We can't use the page_id, as new pages might not exist, and therefore
		-- multiple pages may have an id of 0. Use the prefixedText as a
		-- reasonable fallback. We also need to check that we aren't using the
		-- default new page name, as we don't want it to be treated as a duplicate
		-- page if more than one new page name has been omitted.
		local newPrefixedText = newTitle.prefixedText
		if newPrefixedText ~= defaultNewPagename then
			if newDupes[newPrefixedText] then
				local msg = 'وُجد عنوان مكرر ("'
					.. newTitle.prefixedText
					.. '"); لا يمكن نقل صفحتين إلى نفس الوجهة'
				return err(msg, argsByNum, args["السبب"], argsByNumCount)
			else
				newDupes[newPrefixedText] = true
			end
		end
	end
	
	----------------------------------------------------------------------------
	-- Check for page protection
	----------------------------------------------------------------------------
	
	local highestProtection = ''
	local protectedTitle = ''
	
	-- Checking page protection requires use of .protectionLevels(), one of the 
	-- "expensive" parser functions, which stop working after 500 uses total.
	-- Without some limit set, this starts breaking near 250 distinct titles.
	local titleLimit = 80
	local titlesChecked = 0
	local titles = {}
	-- Consolidate duplicate titles (i.e., when moving A to B and B to C)
	for i = 1,argsByNumCount do
		titles[mw.title.new(argsByNum[i]['من'])] = true
		titles[mw.title.new(argsByNum[i]['إلى'])] = true
	end
	-- Check each title t, while ignoring the "true" value
	for t, _ in pairs(titles) do
		if titlesChecked < titleLimit then
			local levels = t.protectionLevels
			titlesChecked = titlesChecked + 1
			local levelMove = levels['move'] and levels['move'][1]
			local levelEdit = levels['edit'] and levels['edit'][1]
			local levelCreate = levels['create'] and levels['create'][1]
			if levelMove == 'sysop' 
			or levelEdit == 'sysop' 
			or levelEdit == 'editprotected' 
			or levelCreate == 'sysop' then
				highestProtection = 'sysop'
				protectedTitle = tostring(t)
				break
			elseif levelMove == 'editeditorprotected' 
			or levelEdit == 'editeditorprotected' 
			or levelCreate == 'editeditorprotected' then
				highestProtection = 'editeditorprotected'
				protectedTitle = tostring(t)
			end
		else
		-- End the "for" loop if the titleLimit is reached
			break
		end
	end

	----------------------------------------------------------------------------
	-- Generate the heading
	----------------------------------------------------------------------------

	-- For custom values of |heading=, use those.
	-- For |heading=no, |heading=n, etc., don't include a heading.
	-- Otherwise use the current date as a heading.
	local heading = args['عنونة'] or args.header
	local useHeading = yesno(heading, heading)
    local lang = mw.language.getContentLanguage()
	if heading and useHeading == heading then
		heading = '== ' .. heading .. ' ==\n\n'
	elseif useHeading == false then
		heading = ''
	else
		local headingDate = lang:formatDate('j F Y')
		heading = '== طلب نقل ' .. headingDate .. ' ==\n\n'
	end
	
	----------------------------------------------------------------------------
	-- Build the {{requested move/dated}} invocation
	----------------------------------------------------------------------------

	local rmd = {}
	rmd[#rmd + 1] = '{{نقل/مؤرخ'

	if multi then
		rmd[#rmd + 1] = '|متعددة=1\n'
	end
	rmd[#rmd + 1] = '|من1=' .. argsByNum[1]["من"]

	--[[
	-- The first new title. This is used both by single and by multi; for single
	-- it is the only parameter used. For single the parameter name is the first
	-- positional parameter, and for multi the parameter name is "new1".
	--]]
	local new1param = multi and 'إلى1=' or ''
	rmd[#rmd + 1] = '|' .. new1param .. argsByNum[1]["إلى"]

	-- Add more arguments for multi.
	if multi then
		for i = 2, argsByNumCount do
			local t = argsByNum[i]
			local numString = tostring(i)
			local current = t["من"]
			local new = t["إلى"]
			rmd[#rmd + 1] = '|من' .. numString .. '=' .. current
			rmd[#rmd + 1] = '|إلى' .. numString .. '=' .. new
		end
	end

    -- date
    rmd[#rmd + 1] = '|تاريخ=' .. lang:formatDate('Y-m-d')
    rmd[#rmd + 1] = '|حالة=مفتوح'
    rmd[#rmd + 1] = '|الخلاصة='
	
	-- Highest page protection (if admin or template-editor)
	if highestProtection == 'sysop' or highestProtection == 'editor' then
		rmd[#rmd + 1] = '|protected=' .. protectedTitle
	end
	
	-- Pass through demo=yes to the 
	if args.demo ~= nil then
		rmd[#rmd + 1] = '|demo='
		rmd[#rmd + 1] = args.demo
	end
	
	-- The old multi template always has a bar before the closing curly
	-- braces, so we will do that too.
	if multi then
		rmd[#rmd + 1] = '|'
	end
	
	rmd[#rmd + 1] = '}}'
	rmd = table.concat(rmd)

	----------------------------------------------------------------------------
	-- Generate the list of links to the pages to be moved
	----------------------------------------------------------------------------

	local linkList = {}
	for i, t in ipairs(argsByNum) do
		local current = t["من"]
		local new = t["إلى"]
		local msg = '\n%s[[:%s]] ← '
		if new ~= defaultNewPagename then
			msg = msg .. '{{no redirect|%s}}'
		else
			msg = msg .. '%s'
		end
		local item = string.format(
			msg,
			multi and '* ' or '', -- Don't make a list for single page moves.
			current,
			new
		)
		linkList[#linkList + 1] = item
	end
	linkList = table.concat(linkList)

	----------------------------------------------------------------------------
	-- Reason and talk blurb
	----------------------------------------------------------------------------

	-- Reason
	local reason = args["السبب"] or args[2] or 'اكتب سبب طلب النقل.'
	reason = '– ' .. reason
	if yesno(args.sign or args.sig or args.signature or 'unspecified', not reason:match("~~~$")) then
		reason = reason .. '--~~~~'
	end

	-- Talk blurb
	local talk = ''
	if yesno(args.talk, true) then
		talk = frame:expandTemplate{title = 'Requested move/talk'}
	end

	----------------------------------------------------------------------------
	-- Assemble the output
	----------------------------------------------------------------------------

	-- The old templates start with a line break, so we will do that too.
	local ret = string.format(
		'\n%s%s\n%s%s%s%s',
		heading,
		rmd,
		linkList,
		multi and '\n' or ' ',
		reason,
		talk
	)
	return ret
end

function p.message(frame)
	local args = getArgs(frame, {parentOnly = true})
	local title = mw.title.getCurrentTitle()
	local targetpage = args['إلى1']	or args[1]
	local sourcepage = args['من1']
	local subjectpage =	title.subjectPageTitle.prefixedText
	local spage = sourcepage or subjectpage
    local state = args["حالة"] or args["الحالة"] or "مفتوح"
	local protected = args["protected"] or "no"
	local multi = args["متعددة"] and args["متعددة"] == "1" or false
	
	local ret = ""
	
	if state ~= "مفتوح" then
		ret = "هنا نقاش مقترح مغلق لنقل اسم الصفحة " .. (sourcepage and ("من [[" .. sourcepage .. "]]") or "") .. " إلى [[" .. targetpage .. "]]. <span style=\"color:red\">'''رجاءً لا تغير النص التالي '''</span>\n\n"
		local closer = args['خلاصة'] or args['الخلاصة']
		if closer then
			ret = ret .. "[[ملف:Cheese.svg|وصلة=|36بك]]&#32;'''خلاصة:''' " .. closer .. "\n\n"
			if state == "مغلق لما ينفذ" then
				ret = ret .."(التنفيذ يحتاج إلى صلاحيات إدارية)"
			end
		end
	else
		local function ns_name(ns_num)
			return ns_num == 0 and "المقالات" or mw.site.namespaces[ns_num].name
		end

		if protected ~= "no" then
			ret = "[[تصنيف:نقل عناوين المقالات المحمية]]<div style=\"float:left\">"
			local protectionlvl = _protected(protected)
			if protectionlvl == 'sysop' then
				ret =ret .. "[[ملف:Move-protection-shackle.svg|20px|link=Wikipedia:Move protection]]"
			elseif protectionlvl == 'editor' then
				ret =ret .. "[[ملف:Template-protection-shackle.svg|20px|link=Wikipedia:Template protection]]"
			end
			ret = ret .. "</div>"			
		end
		
		ret=ret .. "'''اقتُرح في هذا القسم [[ويكيبيديا:نقل صفحة|نقل]] "
		
		if multi and args["من2"] then
			ret = ret .. "عدة صفحات'''"
			
		else
			ret = ret .. "[[:" .. (spage) .. "]]''' إلى "
		end
		
		if targetpage == "?" then
			ret = ret .. "&#32;وأسماء أخرى، بالأسماء المنصوص عليها بالأسفل"
		elseif targetpage then
			local target_title = mw.title.new(targetpage)
			if target_title.exists and target_title.isRedirect then
				ret = ret .. "[" .. target_title:fullUrl("redirect=no") .. " " .. targetpage .. "]"
			else
				ret = ret .. "[[:" .. targetpage .. "]]"
			end
		end
		ret=ret .. "."

		if args["تاريخ"] then
			ret = ret .. '<div class="floatleft"><small style="line-height:1.2em;">' .. args["تاريخ"] .. "</small></div>"
		end
		ret=ret .. "<br>"
		
		if spage and targetpage then
			local source_ns = spage and mw.title.new(spage).namespace or nil
			local target_ns = targetpage and mw.title.new(targetpage).namespace or nil
			if not multi and source_ns ~= target_ns then
				ret = ret .. [[<small style="line-height:1.2em;">''هذا مقترح نقل عابر للنطاقات من ]] .. ns_name(source_ns) .. " إلى " .. ns_name(target_ns) .. " [[ويكيبيديا:نطاق]].''</small>"
			end
		end
		ret = ret .. "ربما يغلق النقاش بعد 7 أيام من فتحه إذا حصل التوافق .  الرجاء أن تكون العناوين موافقة [[ويكيبيديا:عناوين المقالات#Deciding on an article title|لسياسة عناوين المقالات]]، والحفاظ على نقاش  موضوعي و[[ويكيبيديا:أدب|مؤدب]].\n----\n"
		ret=ret .. "<small style=\"line-height:1.2em;\">''استخدم {{[[قالب:نقل|نسخ:نقل]]}}. و'''لا''' تستخدم {{[[قالب:نقل/مؤرخ|نقل/مؤرخ]]}} مباشرة.''  </small>"
		-- if multi then
			ret = ret .. "<div class=\"floatleft\"><small style=\"line-height:1.2em;\">''وصلات:'' [" .. tostring(mw.uri.fullUrl("Special:Log/move", "page=" .. spage)) .. " سجل الحالية] "
			if targetpage and targetpage ~= "?" then
				ret= ret .. " • [" .. tostring(mw.uri.fullUrl("Special:Log/move", "page=" .. targetpage))  .. " سجل الوجهة] • [" .. tostring(mw.uri.fullUrl("Special:MovePage", "wpOldTitle=" .. spage .. "&wpNewTitle=" .. targetpage .. "&wpReason=" .. "[[ويكيبيديا:طلبات النقل|نقاش النقل]]، انظر [[" .. mw.title.new(targetpage).talkPageTitle.prefixedText .. "]]&wpMovetalk=1")) .. " تنفيذ النقل]"
			end
		-- end
		ret= ret .. "</small></div>"

	end
	return ret
end

function p.catit(frame)
	local args = getArgs(frame, {parentOnly = true})
    local title = mw.title.getCurrentTitle()
    local ret = {}
    local state = args["حالة"] or args["الحالة"] or "مفتوح"
    if not title.isTalkPage then
        return ''
    end
	if state == "مغلق" then
		ret[1] = "[[تصنيف:مقترحات نقل مغلقة]]"
	elseif state == "مغلق لما ينفذ" then
		ret[1] = "[[تصنيف:صفحات للنقل]]"
	else
	    local content = mw.title.new(title.subjectPageTitle.prefixedText):getContent() or '';
	    if args["تاريخ"] then
	        local lang = mw.language.getContentLanguage()
			ret[#ret+1] = "[[تصنيف:مقترحات نقل منذ " .. lang:formatDate('F Y',args["تاريخ"]) .. "]]"
	    end
	
	    if not content then
	        return table.concat(ret,'');
	    end
	    
	    local start = content:find('{{ *شريط بوابات[%s\n]*[|}]');
	    if start then
	        local config_template = content:match ('%b{}', start);
	    
	        if config_template then
	            local params_t = mw.text.split (config_template:gsub ('^{{%s*', ''):gsub ('[%s\n]*}}$', ''), '[%s\n]*|[%s\n]*');
	            table.remove (params_t, 1);
	            for _, param in ipairs (params_t) do
	                ret[#ret+1] = '[[تصنيف:مقترحات نقل لمقالات بوابة ' .. param .. ']]'
	            end
	        end
	    end
	end
    return table.concat(ret,'');
end

return p