پودمان:Article history/config: تفاوت میان نسخه‌ها

از اسلامیکال
پرش به ناوبری پرش به جستجو
(اسلامیزه)
(اسلامیزه2)
 
خط ۲۴۲: خط ۲۴۲:
local text = "'''%s''' یک [[اسلامیکال:مقاله‌های برگزیده|مقالهٔ برگزیده]] است. " ..
local text = "'''%s''' یک [[اسلامیکال:مقاله‌های برگزیده|مقالهٔ برگزیده]] است. " ..
"این مقاله یا یک نسخهٔ قبلی آن " ..
"این مقاله یا یک نسخهٔ قبلی آن " ..
"به عنوان یکی از بهترین مقاله‌های اسلامیکالی فارسی '''''[[%s|انتخاب شده‌است]]'''''. " ..
"به عنوان یکی از بهترین مقاله‌های اسلامیکال فارسی '''''[[%s|انتخاب شده‌است]]'''''. " ..
"با وجود این، اگر مقاله هنوز جای بهبود دارد، [[اسلامیکال:جسور باشید|لطفاً ویرایشش کنید]]."
"با وجود این، اگر مقاله هنوز جای بهبود دارد، [[اسلامیکال:جسور باشید|لطفاً ویرایشش کنید]]."
return string.format(text, articlePage, link)
return string.format(text, articlePage, link)
خط ۲۸۶: خط ۲۸۶:
local text = "'''%s''' یک [[اسلامیکال:فهرست‌های برگزیده|فهرست برگزیده]] است، " ..
local text = "'''%s''' یک [[اسلامیکال:فهرست‌های برگزیده|فهرست برگزیده]] است، " ..
"این مقاله یا یک نسخهٔ قبلی آن " ..
"این مقاله یا یک نسخهٔ قبلی آن " ..
"به عنوان یکی از بهترین فهرست‌های اسلامیکالی فارسی '''''[[%s|انتخاب شده‌است]]'''''. " ..
"به عنوان یکی از بهترین فهرست‌های اسلامیکال فارسی '''''[[%s|انتخاب شده‌است]]'''''. " ..
"با این وجود اگر می‌توانید آن را بهبود بخشید یا به‌روزرسانی کنید، [[اسلامیکال:جسور باشید|لطفا انجامش دهید]]."
"با این وجود اگر می‌توانید آن را بهبود بخشید یا به‌روزرسانی کنید، [[اسلامیکال:جسور باشید|لطفا انجامش دهید]]."
return string.format(text, articlePage, link)
return string.format(text, articlePage, link)
خط ۲۹۹: خط ۲۹۹:
"Please see the links under Article milestones below for its original " ..
"Please see the links under Article milestones below for its original " ..
"nomination page and why it was removed. If it has improved again to " ..
"nomination page and why it was removed. If it has improved again to " ..
"[[Wikipedia:Featured list criteria|featured list standard]], you may " ..
"[[Islamical:Featured list criteria|featured list standard]], you may " ..
"[[Wikipedia:Featured list candidates|renominate]] the article to " ..
"[[Islamical:Featured list candidates|renominate]] the article to " ..
"become a [[Wikipedia:Featured list|featured list]]."
"become a [[Islamical:Featured list|featured list]]."
},
},
FFLC = {
FFLC = {
خط ۴۰۹: خط ۴۰۹:
iconCaption = 'Former featured topic',
iconCaption = 'Former featured topic',
text = "This article is part of a " ..
text = "This article is part of a " ..
"''[[Wikipedia:Former featured topics|former featured topic]]'' series. " ..
"''[[Islamical:Former featured topics|former featured topic]]'' series. " ..
"If it has improved again to " ..
"If it has improved again to " ..
"[[Wikipedia:Featured topic criteria|featured topic standard]], " ..
"[[Islamical:Featured topic criteria|featured topic standard]], " ..
"you may [[Wikipedia:Featured topic candidates|renominate]] " ..
"you may [[Islamical:Featured topic candidates|renominate]] " ..
"the topic to become a [[Wikipedia:Featured topic|featured topic]]."
"the topic to become a [[Islamical:Featured topic|featured topic]]."
},
},
FFTC = {
FFTC = {
خط ۴۲۰: خط ۴۲۰:
icon = 'Cscr-former.svg',
icon = 'Cscr-former.svg',
text = "This article is part of a ''former'' " ..
text = "This article is part of a ''former'' " ..
"[[Wikipedia:Featured topic candidates|featured topic candidate]]. " ..
"[[Islamical:Featured topic candidates|featured topic candidate]]. " ..
"Please view the links under Article milestones below to see why " ..
"Please view the links under Article milestones below to see why " ..
"the nomination failed."
"the nomination failed."
خط ۴۴۵: خط ۴۴۵:
name = 'Former featured portal',
name = 'Former featured portal',
icon = 'Featured article star - cross.svg',
icon = 'Featured article star - cross.svg',
text = "This portal is a [[Wikipedia:Former featured portals|former featured portal]]. " ..
text = "This portal is a [[Islamical:Former featured portals|former featured portal]]. " ..
"Please see the links under Portal milestones below for its " ..
"Please see the links under Portal milestones below for its " ..
"original nomination page and why it was removed.",
"original nomination page and why it was removed.",
categories = function (articleHistoryObj)
categories = function (articleHistoryObj)
return {Category.new(
return {Category.new(
'Wikipedia former featured portals',
'Islamical former featured portals',
articleHistoryObj.currentTitle.text
articleHistoryObj.currentTitle.text
)}
)}
خط ۴۶۰: خط ۴۶۰:
icon = 'Cscr-former.svg',
icon = 'Cscr-former.svg',
text = "This portal is a '''''former''''' " ..
text = "This portal is a '''''former''''' " ..
"[[Wikipedia:Featured portal candidates|featured portal candidate]]. " ..
"[[Islamical:Featured portal candidates|featured portal candidate]]. " ..
"Please see the links under Portal milestones below for its " ..
"Please see the links under Portal milestones below for its " ..
"original nomination page and why the nomination failed.",
"original nomination page and why the nomination failed.",
خط ۷۲۵: خط ۷۲۵:
local otherBlurb = "این نوشتار همچنین %s سری '''[[اسلامیکال:موضوعات برگزیده/%s|%s]]'''، %s است."
local otherBlurb = "این نوشتار همچنین %s سری '''[[اسلامیکال:موضوعات برگزیده/%s|%s]]'''، %s است."
local finalBlurb = "%s به عنوان یکی از بهترین نوشتارهای " ..
local finalBlurb = "%s به عنوان یکی از بهترین نوشتارهای " ..
"ساختهٔ [[اسلامیکال:اسلامیکالیی‌ها|اجتماع اسلامیکال]] شناخته شده است. " ..
"ساختهٔ [[اسلامیکال:اسلامیکال‌ها|اجتماع اسلامیکال]] شناخته شده است. " ..
"اگر می‌توانید %s را به‌روز کنید یا آن را بهبود دهید، [[اسلامیکال:جسور باشید|لطفاً انجامش دهید]]."
"اگر می‌توانید %s را به‌روز کنید یا آن را بهبود دهید، [[اسلامیکال:جسور باشید|لطفاً انجامش دهید]]."
local main = 'نوشتار اصلی در'
local main = 'نوشتار اصلی در'
خط ۱٬۱۹۳: خط ۱٬۱۹۳:
if actionObj.resultId == 'not kept' then
if actionObj.resultId == 'not kept' then
ret[#ret + 1] = Category.new(
ret[#ret + 1] = Category.new(
'Wikipedia former brilliant prose',
'Islamical former brilliant prose',
articleHistoryObj.currentTitle.text
articleHistoryObj.currentTitle.text
)
)
خط ۱٬۹۷۴: خط ۱٬۹۷۴:
elseif t.date.Ymd >= 20090101 then
elseif t.date.Ymd >= 20090101 then
date.link = string.format(
date.link = string.format(
'Wikipedia:ITN archives/%s/%s',
'Islamical:ITN archives/%s/%s',
t.date.faY,
t.date.faY,
t.date.fam
t.date.fam
خط ۱٬۹۹۶: خط ۱٬۹۹۶:
end
end
local blurb = intro ..
local blurb = intro ..
" featured on Wikipedia's [[Main Page]] in the " ..
" featured on Islamical's [[Main Page]] in the " ..
"''\"[[Template:In the news|In the news]]\"'' column on $1."
"''\"[[Template:In the news|In the news]]\"'' column on $1."
return makeDateText(dates, blurb)
return makeDateText(dates, blurb)
خط ۲٬۱۴۵: خط ۲٬۱۴۵:
},
},


-- Wikipedia 1.0
-- Islamical 1.0
{
{
isActive = function (articleHistoryObj)
isActive = function (articleHistoryObj)

نسخهٔ کنونی تا ‏۱۶ سپتامبر ۲۰۲۳، ساعت ۱۳:۴۸

توضیحات این پودمان می‌تواند در پودمان:Article history/config/توضیحات قرار گیرد.

local date2en = require('Module:Date2en').convert
local numConv = require('Module:Numeral converter').convert
-------------------------------------------------------------------------------
--              Configuration data for [[Module:Article history]]
-------------------------------------------------------------------------------

local lang = mw.language.getContentLanguage()		
local Category = require('Module:Article history/Category')

-------------------------------------------------------------------------------
-- Helper functions
-------------------------------------------------------------------------------
local sub = mw.ustring.sub

-- Makes a link to a template page surrounded by double curly braces. A
-- workalike for the {{tl}} template.
local function makeTemplateLink(s)
	local openb = mw.text.nowiki('{{')
	local closeb = mw.text.nowiki('}}')
	return string.format('%s[[Template:%s|%s]]%s', openb, s, s, closeb)
end

-- Gets the Good Article topic for the given key. Uses
-- [[Module:Good article topics]].
local function getGoodArticleTopic(key)
	if not key then
		return nil
	end
	return require('Module:Good article topics')._main(key)
end

-- Returns the Good Article page link and display value for a given Good Article
-- key. If the key wasn't valid, the default Good Article page and display value
-- is returned instead.
local function getGoodArticleTopicLink(key)
	local topic = getGoodArticleTopic(key)
	local link, display
	if topic then
		link = ':رده:مقاله‌های خوب ' .. topic
		display = 'مقاله‌های خوب ' .. topic
	else
		link = 'اسلامیکال:مقاله‌های خوب'
		display = 'مقاله‌های خوب'
	end
	return link, display
end

-- Wrapper function for mw.language:formatDate, going through pcall to catch
-- invalid input errors.
local function getDate(date)
	local success, result = pcall(lang.formatDate, lang, 'YmdWoF', date2en(date or ''))
	if success then
		local faY, fam, fad, faW, fao
		faY = sub(result, 1, 4)
		fam = sub(result, 5, 6)
		fad = sub(result, 7, 8)
		faW = sub(result, 9, 10)
		fao = sub(result, 11, 14)
		return {
			faY=faY, fam=fam, fad=fad, faW=faW, fao=fao,
			Y=tonumber(numConv('en', faY)),  W=tonumber(numConv('en', faW)), o=tonumber(numConv('en', fao)),
			Ymd=tonumber(numConv('en', faY .. fam .. fad)),
			long=fad .. ' ' .. sub(result, 15, -1) .. ' ' .. faY
		}
	end
end

-- Returns true if the given page is an existing title, and false or nil
-- otherwise
local function titleExists(page)
	local success, title = pcall(mw.title.new, page)
	return success and title.exists
end

-- Returns a truthy value if a date parameter for the given prefix has been
-- provided by the user.
local function isActiveDatedObject(articleHistoryObj, prefix)
	local args = articleHistoryObj.args
	local prefixArgs = articleHistoryObj.prefixArgs
	return args[prefix .. 'date'] or prefixArgs[prefix]
end

-- Returns a date. If the date is invalid, it raises
-- an error using param as the parameter name containing the invalid date.
local function validateDate(param, date, articleHistoryObj)
	local longDate = getDate(date)
	if longDate then
		return longDate
	else
		articleHistoryObj:raiseError(
			string.format(
				"تاریخ نامعتبر '%s' در پارامتر '%s' شناسایی شد",
				tostring(date),
				param
			),
			'الگو:تاریخچه مقاله#Invalid date'
		)
	end
end

-- Generates a data table for a date-related notice such as DYK and ITN. prefix
-- is the parameter prefix for that notice type (e.g. "dyk"), and suffixes is
-- an array of parameter suffixes in addition to "date" that is used by that
-- notice type (e.g. "entry" for the "dykentry" and "dyk2entry" parameters).
local function makeDateData(articleHistoryObj, prefix, suffixes)
	local args = articleHistoryObj.args
	local prefixArgs = articleHistoryObj.prefixArgs

	-- Sanity checks
	if prefixArgs[prefix] then
		for _, t in ipairs(prefixArgs[prefix]) do
			if not t.date then
				articleHistoryObj:raiseError(
					string.format(
						"an argument starting with '%s%d' was detected, " ..
							"but no '%s%ddate' parameter was specified",
						prefix, t[1],
						prefix, t[1]
					),
					'الگو:تاریخچه مقاله#No date parameter'
				)
			end
		end
	end

	local data = {}

	-- Organise the input
	local function addData(sep)
		local t = {}
		local argPrefix = prefix .. sep
		do
			local key = argPrefix .. 'date'
			t.date = validateDate(key, args[key], articleHistoryObj)
		end
		for _, suffix in ipairs(suffixes) do
			local key = argPrefix .. suffix
			t[suffix] = args[key]
		end
		t.argPrefix = argPrefix
		data[#data + 1] = t
	end
	if args[prefix .. 'date'] then
		addData('')
	end
	if prefixArgs[prefix] then
		for _, prefixData in ipairs(prefixArgs[prefix]) do
			addData(tostring(prefixData[1]))
		end
	end
	if #data < 1 then
		error(string.format(
			"no data items found for prefix '%s' and parameter checks failed'",
			tostring(prefix)
		))
	end

	return data
end

-- This makes the text for Main Page features such as DYKs and ITNs for the
-- dates contained in dateData (made with the makeDateData function).
-- The parameter $1 in the blurb will be replaced with the list of dates.
local function makeDateText(dateData, blurb)
	local dates, doneLinks = {}, {}
	for i, t in ipairs(dateData) do
		if t.link and not doneLinks[t.link] then
			dates[i] = string.format('[[%s|%s]]', t.link, t.date.long)
			doneLinks[t.link] = true
		else
			dates[i] = string.format('%s', t.date.long)
		end
	end
	local dateList = mw.text.listToText(dates, ', ', ', and ')
	return mw.message.newRawMessage(blurb, dateList):plain()
end

return {
	
-------------------------------------------------------------------------------
--                             CONFIG TABLE START
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
-- Statuses
-- Configuration for possible current statuses of the article.
-------------------------------------------------------------------------------

-- The statuses table contain configuration tables for possible current statuses
-- of the article.
-- Each table can have the following fields:
--
-- id: the main ID for the status. This should be the same as the configuration
--    table key.
-- aliases: a table of ID aliases that can be used to access the config table.
-- icon: The status icon.
-- iconSize: The icon size, including "px" suffix. The default is defined in
--    defaultStatusIconSize.
-- iconSmallSize: The icon size if we are outputting a small template. The
--    default is defined in defaultSmallStatusIconSize.
-- iconMultiSize: The icon size if we are outputting multiple status rows. The
--    default is defaultSmallStatusIconSize.
-- text: The status text. This may be a string or a function. If it is a
--    function, it takes an article history object as input, and should return
--    the text string. If it is a string, it can have the following parameters:
--    $1 - The full page name of the article or subject page
--    $2 - The page name without the namespace name
-- categories: The categories set by the status. This may be an array of
--    category names, or a function. If it is a function, it takes an article
--    history object as the first parameter, and the current status object as
--    the second parameter, and should return an array of category objects.
-- noticeBarIcon: the icon to use for the notice bar. This can be a string, or
--    a function, or true. If it is a function it takes an article history
--    object as the first parameter, and should output the icon filename. If it
--    is true, it uses the value of icon. If it is nil then no notice bar icon
--    will be displayed.
-- noticeBarIconCaption: the caption to use for the notice bar icon. The status
--    name is used by default. This can be a string or a function. If it is a
--    function, it takes an article history object as its first parameter, and
--    should return the caption text. If this is absent, the icon caption is
--    used instead.
-- noticeBarIconSize: the size of the notice bar icon, including "px" suffix.
--    The default is set by defaultNoticeBarIconSize.

statuses = {
	FA = {
		id = 'FA',
		name = 'مقالهٔ برگزیده',
		icon = 'Symbol star gold.svg',
		text = function (articleHistoryObj)
			local articlePage = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
			local actions = articleHistoryObj:getActionObjects()
			local link
			for i = #actions, 1, -1 do
				local actionObj = actions[i]
				if actionObj.id == 'FAC' then
					link = actionObj.link
					break
				end
			end
			link = link or 'اسلامیکال:گزیدن مقاله‌های برگزیده/' .. articlePage
			local text = "'''%s''' یک [[اسلامیکال:مقاله‌های برگزیده|مقالهٔ برگزیده]] است. " ..
				"این مقاله یا یک نسخهٔ قبلی آن " ..
				"به عنوان یکی از بهترین مقاله‌های اسلامیکال فارسی '''''[[%s|انتخاب شده‌است]]'''''. " ..
				"با وجود این، اگر مقاله هنوز جای بهبود دارد، [[اسلامیکال:جسور باشید|لطفاً ویرایشش کنید]]."
			return string.format(text, articlePage, link)
		end,
		categories = {'مقاله‌های برگزیده اسلامیکال'}
	},
	FFA = {
		id = 'FFA',
		name = 'مقالهٔ برگزیده پیشین',
		icon = 'Symbol unsupport star gold.svg',
		iconSize = '48px',
		text = "'''$1''' یک [[اسلامیکال:مقاله‌های برگزیده پیشین|مقالهٔ برگزیده پیشین]] است. " ..
			"برای دیدن صفحه اصلی بحث که منجر به خروج از برگزیدگی شده است، پیوند پایین را ببینید. " ..
			"(برای دیدن مقاله‌هایی که با اجماع کاربران از حالت برگزیدگی خارج شده‌اند، [[اسلامیکال:مقاله‌های برگزیده پیشین|بایگانی]] را ببینید.)",
		categories = {'مقاله‌های برگزیده پیشین'}
	},
	FFAC = {
		id = 'FFAC',
		name = 'نامزد پیشین مقاله برگزیده',
		aliases = {'FACFAILED'},
		icon = 'FA candidate gold former.svg',
		text = "'''$1''' در گذشته [[اسلامیکال:گزیدن مقاله‌های برگزیده|نامزد برگزیدگی]] بوده‌است. " ..
			"برای دیدن دلیل برگزیده نشدن مقاله، " ..
			"قسمت رخدادهای برجسته‌ی مقاله در زیر را ببینید. "
	},
	FL = {
		id = 'FL',
		name = 'فهرست برگزیده',
		icon = 'Symbol star 660080.svg',
		iconSize = '48px',
		text = function (articleHistoryObj)
			local articlePage = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
			local actions = articleHistoryObj:getActionObjects()
			local link
			for i = #actions, 1, -1 do
				local actionObj = actions[i]
				if actionObj.id == 'FLC' then
					link = actionObj.link
					break
				end
			end
			link = link or 'اسلامیکال:گزیدن فهرست‌های برگزیده/' .. articlePage
			local text = "'''%s''' یک [[اسلامیکال:فهرست‌های برگزیده|فهرست برگزیده]] است، " ..
				"این مقاله یا یک نسخهٔ قبلی آن " ..
				"به عنوان یکی از بهترین فهرست‌های اسلامیکال فارسی '''''[[%s|انتخاب شده‌است]]'''''. " ..
				"با این وجود اگر می‌توانید آن را بهبود بخشید یا به‌روزرسانی کنید، [[اسلامیکال:جسور باشید|لطفا انجامش دهید]]."
			return string.format(text, articlePage, link)
		end,
		categories = {'مقاله‌های درجه فهرست برگزیده'}
	},
	FFL = {
		id = 'FFL',
		name = 'فهرست برگزیده پیشین',
		icon = 'Cscr-featured-strike.svg',
		text = "'''$1''' در گذشته [[اسلامیکال:بازبینی فهرست‌های برگزیده/بایگانی|فهرست برگزیده]] بوده‌است. " ..
			"Please see the links under Article milestones below for its original " ..
			"nomination page and why it was removed. If it has improved again to " ..
			"[[Islamical:Featured list criteria|featured list standard]], you may " ..
			"[[Islamical:Featured list candidates|renominate]] the article to " ..
			"become a [[Islamical:Featured list|featured list]]."
	},
	FFLC = {
		id = 'FFLC',
		name = 'نامزد پیشین فهرست برگزیده',
		icon = 'FA candidate gold former.svg',
		iconCaption = 'نامزد پیشین فهرست برگزیده',
		text = "'''$1''' یک نامزد پیشین برای [[اسلامیکال:گزیدن فهرست‌های برگزیده]] است. " ..
			"لطفاً پیوندی که در ادامه آمده را برای بررسی دلایل برگزیده نشدنش دنبال کنید.. " ..
			"اگر اشکالات مطرح شده رفع شوند می‌توانید این فهرست را  " ..
			"[[اسلامیکال:گزیدن فهرست‌های برگزیده|دوباره نامزد برگزیدگی کنید]] ",
		categories = {'نامزدهای ناموفق فهرست برگزیده در اسلامیکال'}
	},
	['FFA/GA'] = {
		id = 'FFA/GA',
		name = 'مقالهٔ برگزیده پیشین، مقالهٔ خوب کنونی',
		isMulti = true,
		statuses = {'FFA', 'GA'}
	},
	['FFAC/GA'] = {
		id = 'FFAC/GA',
		name = 'Former featured article candidate, current good article',
		isMulti = true,
		statuses = {'FFAC', 'GA'}
	},
	GA = {
		id = 'GA',
		name = 'مقالهٔ خوب',
		icon = 'Symbol star2.svg',
		iconSize = '40px',
		iconMultiSize = '25px',
		text = function (articleHistoryObj)
			local link, display = getGoodArticleTopicLink(articleHistoryObj.args.topic)
			local articlePage = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
			local text = "'''%s''' به عنوان یکی از '''''[[%s|%s]]''''' " ..
				"مطابق با [[اسلامیکال:مقاله‌های خوب/معیارها|معیارهای مقاله‌های خوب]] انتخاب شده‌است. " ..
				"اگر می‌توانید آن را بهبود بخشید، [[اسلامیکال:جسور باشید|لطفا این کار را انجام دهید]]. " ..
				"<small>''اگر فکر می‌کنید این مقاله شرایط خوب بودن را ندارد، می‌توانید درخواست " ..
				"'''[[اسلامیکال:بازبینی مقاله‌های خوب|بازنگری]]''' آن را بدهید''.</small>"
			return string.format(text, articlePage, link, display)
		end,
		categories = function (articleHistoryObj)
			local ret = {}
			local title = articleHistoryObj.currentTitle
			if title.namespace == 1 then
				ret[#ret + 1] = Category.new('مقاله‌های خوب اسلامیکال')
				local topic = getGoodArticleTopic(articleHistoryObj.args.topic)
				if topic then
					ret[#ret + 1] = Category.new(
						'مقاله‌های خوب ' .. topic,
						title.text
					)
				else
					ret[#ret + 1] = Category.new(
						'مقاله‌های خوب که پارامتر موضوع ندارند',
						title.text
					)
				end
			end
			return ret
		end
	},
	FGAN = {
		id = 'FGAN',
		name = 'نامزد پیشین مقالهٔ خوب',
		aliases = {'FAILEDGA'},
		icon = 'Symbol_unsupport_star_green.svg',
		text = function (articleHistoryObj)
			local articlePage = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
			local link, display = getGoodArticleTopicLink(articleHistoryObj.args.topic)
			local text = "'''%s''' یکی از نامزدهای '''''[[%s|%s]]''''' بوده است، " ..
				"اما در آن موفق به برآوردن [[اسلامیکال:مقاله‌های خوب/معیارها|معیارهای مقاله‌های خوب]] نشده است" ..
				". در زیر پیشنهادهایی برای بهبود مقاله وجود دارد. " ..
				"پس از حل شدن این مشکلات می‌توان مقاله را " ..
				"[[اسلامیکال:گزیدن مقاله‌های خوب|نامزد کرد]]. " ..
				"در صورتی که ویرایشگران معتقد باشند تصمیم قبلی درست نبوده است، " ..
				"می‌توانند درخواست '''[[اسلامیکال:بازبینی مقاله‌های خوب|بازبینی]]''' دهند."
			return string.format(text, articlePage, link, display)
		end,
		categories = {'مقاله‌های ناموفق در خوبیدگی'}
	},
	DGA = {
		id = 'DGA',
		name = 'مقالهٔ خوب پیشین',
		aliases = {'DELISTEDGA'},
		icon = 'Symbol unsupport star green.svg',
		iconCaption = 'مقالهٔ خوب پیشین',
		text = function (articleHistoryObj)
			local articlePage = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
			local link, display = getGoodArticleTopicLink(articleHistoryObj.args.topic)
			local text = "'''%s''' یکی از '''''[[%s|%s]]''''' بود " ..
				"اما از آن فهرست خارج شد. " ..
				"پیشنهادهایی در زیر برای بهبود کیفیت مقاله به منظور کسب " ..
				"[[اسلامیکال:مقاله‌های خوب/معیارها|معیارهای مقاله‌های خوب]] وجود دارد. " ..
				"پس از حل شدن این مشکلات، مقاله می‌تواند " ..
				"[[اسلامیکال:گزیدن مقاله‌های خوب|دوباره نامزد شود]]. " ..
				"در صورتی که ویرایشگران معتقد باشند تصمیم قبلی درست نبوده است، " ..
				"می‌توانند درخواست '''[[اسلامیکال:بازبینی مقاله‌های خوب|بازبینی]]''' دهند."
			return string.format(text, articlePage, link, display)
		end,
		categories = {'مقاله‌های خوب پیشین'}
	},
	FFT = {
		id = 'FFT',
		name = 'Part of former featured topic',
		icon = 'Cscr-featured-strike.svg',
		iconCaption = 'Former featured topic',
		text = "This article is part of a " ..
			"''[[Islamical:Former featured topics|former featured topic]]'' series. " ..
			"If it has improved again to " ..
			"[[Islamical:Featured topic criteria|featured topic standard]], " ..
			"you may [[Islamical:Featured topic candidates|renominate]] " ..
			"the topic to become a [[Islamical:Featured topic|featured topic]]."
	},
	FFTC = {
		id = 'FFTC',
		name = 'Former featured topic candidate',
		icon = 'Cscr-former.svg',
		text = "This article is part of a ''former'' " ..
			"[[Islamical:Featured topic candidates|featured topic candidate]]. " ..
			"Please view the links under Article milestones below to see why " ..
			"the nomination failed."
	},
	FPO = {
		id = 'FPO',
		name = 'درگاه برگزیده',
		icon = 'Symbol_star3.svg',
		text =  "'''درگاه $2''' یک [[اسلامیکال:درگاه‌های برگزیده|درگاه برگزیدهl]] است " ..
			"که یعنی " ..
			"به عنوان یکی از بهترین درگاه‌ها در [[اسلامیکال]] " ..
			"'''''[[اسلامیکال:گزیدن درگاه‌های برگزیده:$2|انتخاب شده‌است]]''''' " ..
			"اگر راهی سراغ دارید که این درگاه بدون به خطر افتادن محتوای قبلی‌اش " ..
			"به‌روز شود یا بهبود یابد، لطفاً آن را ویرایش کنید.",
		categories = function (articleHistoryObj)
			return {Category.new(
				'درگاه‌های برگزیده',
				articleHistoryObj.currentTitle.text
			)}
		end
	},
	FFPO = {
		id = 'FFPO',
		name = 'Former featured portal',
		icon = 'Featured article star - cross.svg',
		text = "This portal is a [[Islamical:Former featured portals|former featured portal]]. " ..
			"Please see the links under Portal milestones below for its " ..
			"original nomination page and why it was removed.",
		categories = function (articleHistoryObj)
			return {Category.new(
				'Islamical former featured portals',
				articleHistoryObj.currentTitle.text
			)}
		end
	},
	FFPOC = {
		id = 'FFPOC',
		name = 'نامزد پیشین درگاه برگزیده',
		icon = 'Cscr-former.svg',
		text = "This portal is a '''''former''''' " ..
			"[[Islamical:Featured portal candidates|featured portal candidate]]. " ..
			"Please see the links under Portal milestones below for its " ..
			"original nomination page and why the nomination failed.",
		categories = function (articleHistoryObj)
			return {Category.new(
				'درگاه‌های نامزد برگزیدگی',
				articleHistoryObj.currentTitle.text
			)}
		end
	},
	PR = {
		-- Peer review is a valid current status, but it doesn't trigger a
		-- header row.
		id = 'PR',
		name = 'داوری همتا شد',
		noticeBarIcon = 'Nuvola apps kedit.svg'
	},
	NA = {
		-- A valid current status, but doesn't trigger a header row.
		id = 'NA',
		noticeBarIcon = 'Nuvola apps kedit.svg'
	},
	-- The following are invalid statuses.
	FAC = {
		id = 'FAC',
		text = function (articleHistoryObj)
			articleHistoryObj:raiseError(
				string.format(
					'use the template %s to nominate an article for Featured article status',
					makeTemplateLink('fac')
				),
				'الگو:تاریخچه مقاله#Featured article candidates'
			)
		end
	},
	FAR = {
		id = 'FAR',
		text = function (articleHistoryObj)
			articleHistoryObj:raiseError(
				string.format(
					'use the template %s to nominate an article for Featured article review',
					makeTemplateLink('FAR')
				),
				'الگو:تاریخچه مقاله#Featured article review'
			)
		end
	},
	STUB = {
		id = 'STUB',
		aliases = {'START', 'B', 'A'},
		text = function (articleHistoryObj)
			local currentStatusParam = articleHistoryObj.cfg.currentStatusParam
			articleHistoryObj:raiseError(
				string.format(
					"do not use '%s' as value of the '%s' parameter; these " ..
						'assessments are the responsibility of individual ' ..
						'WikiProjects',
					articleHistoryObj.args[currentStatusParam],
					currentStatusParam
				),
				'الگو:تاریخچه مقاله#WikiProject assessments'
			)
		end
	},
},

-- This function allows the generation of custom status ID. It takes an
-- articleHistory object as the first parameter, and should output the status
-- ID.
getStatusIdFunction = function (articleHistoryObj)
	-- Get the status ID. The status code is the code passed in from the
	-- arguments, and the ID is the value contained in the config.
	local statuses = articleHistoryObj.cfg.statuses
	local statusCode = articleHistoryObj.args[articleHistoryObj.cfg.currentStatusParam]
	local statusId = articleHistoryObj:getStatusIdForCode(statusCode)

	-- Check for former featured articles.
	if statusId ~= 'FA'
		and statusId ~= 'FL'
		and statusId ~= 'FFA'
		and statusId ~= 'FFL'
		and statusId ~= 'FFA/GA'
	then
		local ffaObj
		local actions = articleHistoryObj:getActionObjects()
		for i = #actions, 1, -1 do
			local actionObj = actions[i]
			if actionObj.id == 'FAR' and actionObj.resultId == 'demoted' then
				ffaObj = actionObj
				break
			end
		end
		if ffaObj then
			if not statusId then
				articleHistoryObj:raiseError(
					'former featured articles should have a current status',
					'الگو:تاریخچه مقاله#Former featured articles'
				)
			elseif statusId == 'GA' then
				statusId = 'FFA/GA'
			elseif statusId == 'DGA' then
				statusId = 'FFA'
			else
				articleHistoryObj:raiseError(
					string.format(
						"'%s' is not a valid current status for former featured articles",
						tostring(statusCode)
					),
					'الگو:تاریخچه مقاله#Former featured articles'
				)
			end
		end
	end

	return statusId
end,

-------------------------------------------------------------------------------
-- Notices
-------------------------------------------------------------------------------

-- The notices table contains configuration tables for notices about the article
-- that are unrelated to its current status.
-- Each configuration table can have the following fields:
--
-- id: the main ID for the notice. This should be the same as the configuration
--    table key.
-- isActive: a function that should return a truthy value if the notice should
--    be displayed, and a falsy value if not. (Falsy values are false and nil,
--    and truthy values are everything else.) The function takes an article
--    history object as its first parameter.
-- makeData: a function that should return a table of data to be used by other
--    functions in this notice configuration table. It can be accessed using
--    noticeObj:getData().
-- icon: the filename of the notice icon, minus the "File:" prefix.
-- iconCaption: the icon caption.
-- iconSize: The icon size, including "px" suffix. The default is defined in
--    defaultIconSize.
-- iconSmallSize: The icon size if we are outputting a small template. The
--    default is defined in defaultSmallIconSize.
-- text: The notice text. This may be a string or a function. If it is a
--    function, it takes an article history object as the first parameter, and
--    the current notice object as the second parameter, and should return the
--    text string.
-- categories: The categories set by the notice. This may be an array of
--    category names, or a function. If it is a function, it takes an article
--    history object as the first parameter, and the current notice object as
--    the second parameter, and should return an array of category objects.
-- noticeBarIcon: the icon to use for the notice bar. This can be a string, or
--    a function, or true. If it is a function it takes an article history
--    object as the first parameter, and should output the icon filename. If it
--    is true, it uses the value of icon. If it is nil then no notice bar icon
--    will be displayed.
-- noticeBarIconCaption: the caption to use for the notice bar icon. This can be
--    a string or a function. If it is a function, it takes an article history
--    object as its first parameter, and should return the caption text. If this
--    is absent, the icon caption is used instead.
-- noticeBarIconSize: the size of the notice bar icon, including "px" suffix.
--    The default is set by defaultNoticeBarIconSize.

notices = {
	{
		id = 'FT',
		isActive = function (articleHistoryObj)
			local args = articleHistoryObj.args
			local prefixArgs = articleHistoryObj.prefixArgs
			-- ftmain is included here because it leads to better error
			-- messages than leaving it out, even though ftmain by itself is
			-- invalid.
			return args.ftname or args.ftmain or prefixArgs.ft
		end,
		makeData = function (articleHistoryObj)
			local args = articleHistoryObj.args
			local prefixArgs = articleHistoryObj.prefixArgs
			local data = {}
			local getTopicStatus = require('Module:FeaturedTopicSum').status
			local yesno = require('Module:Yesno')

			local function makeTopicData(name, isMain, paramNum)
				if name then
					return {
						name = name,
						isMain = yesno(isMain) or false,
						status = getTopicStatus(name),
						paramNum = paramNum
					}
				elseif isMain then
					local num = paramNum and tostring(paramNum) or ''
					articleHistoryObj:raiseError(
						string.format(
							"parameter 'ft%smain' is set, but no featured " ..
								"topic name is set in parameter 'ft%sname'",
							num, num
						),
						'الگو:تاریخچه مقاله#Featured topic names'
					)
				else
					return nil
				end
			end
			data[#data + 1] = makeTopicData(args.ftname, args.ftmain)
			if prefixArgs.ft then
				for i, t in ipairs(prefixArgs.ft) do
					if t[1] > 1 then -- we use args.ftname instead of args.ft1name
						data[#data + 1] = makeTopicData(t.name, t.main, t[1])
					end
				end
			end

			-- Check for rogue ft.. parameters
			if #data < 1 then
				articleHistoryObj:raiseError(
					"a parameter starting with 'ft' was detected, but no " ..
						"featured topic names were specified; " ..
						"please check the parameter names",
					'الگو:تاریخچه مقاله#Featured topic names'
				)
			end

			-- Find if one of the topics is featured.
			local isInFeaturedTopic = false
			for _, topic in ipairs(data) do
				if topic.status == 'FT' then
					isInFeaturedTopic = true
					break
				end
			end
			data.isInFeaturedTopic = isInFeaturedTopic

			return data
		end,
		icon = function (articleHistoryObj, noticeObj)
			local data = noticeObj:getData(articleHistoryObj)
			if not data then
				return nil
			end
			if data.isInFeaturedTopic then
				return 'Cscr-featuredtopic-fawiki.svg'
			else
				return 'Symbol star2-fa.svg'
			end
		end,
		iconCaption = function (articleHistoryObj, noticeObj)
			local data = noticeObj:getData(articleHistoryObj)
			if not data then
				return nil
			end
			if data.isInFeaturedTopic then
				return 'ستارهٔ موضوع برگزیده'
			else
				return 'ستارهٔ موضوع خوب'
			end
		end,
		iconSize = '48px',
		iconSmallSize = '30px',
		text = function (articleHistoryObj, noticeObj)
			local data = noticeObj:getData(articleHistoryObj)
			if not data then
				return nil
			end
			local article = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText

			local firstBlurb = "'''%s''' %s سری '''[[اسلامیکال:موضوعات برگزیده/%s|%s]]'''، %s است."
			local otherBlurb = "این نوشتار همچنین %s سری '''[[اسلامیکال:موضوعات برگزیده/%s|%s]]'''، %s است."
			local finalBlurb = "%s به عنوان یکی از بهترین نوشتارهای " ..
				"ساختهٔ [[اسلامیکال:اسلامیکال‌ها|اجتماع اسلامیکال]] شناخته شده است. " ..
				"اگر می‌توانید %s را به‌روز کنید یا آن را بهبود دهید، [[اسلامیکال:جسور باشید|لطفاً انجامش دهید]]."
			local main = 'نوشتار اصلی در'
			local notMain = 'بخشی از'
			local featuredLink = 'یک [[اسلامیکال:موضوعات برگزیده|موضوع برگزیده]]'
			local featuredNoLink = 'یک موضوع برگزیده'
			local goodLink = 'یک [[اسلامیکال:موضوعات خوب|موضوع خوب]]'
			local goodNoLink = 'یک موضوع خوب'
			local thisSingular = 'این مقاله'
			local thisPlural = 'این مقاله‌ها'
			local itSingular = 'آن'
			local itPlural = 'آن‌ها'

			local hasFeaturedLink = false
			local hasGoodLink = false
			local text = {}
			
			-- First topic
			do
				local topic = data[1]
				local link
				if topic.status == 'FT' then
					link = featuredLink
					hasFeaturedLink = true
				else
					link = goodLink
					hasGoodLink = true
				end
				text[#text + 1] = string.format(
					firstBlurb,
					article,
					topic.isMain and main or notMain,
					topic.name,
					topic.name,
					link
				)
			end

			-- Other topics
			for i = 2, #data do
				local topic = data[i]
				local link
				if topic.status == 'FT' then
					if hasFeaturedLink then
						link = featuredNoLink
					else
						link = featuredLink
						hasFeaturedLink = true
					end
				else
					if hasGoodLink then
						link = goodNoLink
					else
						link = goodLink
						hasGoodLink = true
					end
				end
				text[#text + 1] = string.format(
					otherBlurb,
					topic.isMain and main or notMain,
					topic.name,
					topic.name,
					link
				)
			end

			-- Final blurb
			do
				local isPlural = #data > 1
				text[#text + 1] = string.format(
					finalBlurb,
					isPlural and thisPlural or thisSingular,
					isPlural and itPlural or itSingular
				)
			end

			return table.concat(text, ' ')
		end,
		categories = function (articleHistoryObj, noticeObj)
			local data = noticeObj:getData(articleHistoryObj)
			if not data then
				return nil
			end
			local status = articleHistoryObj:getStatusId()
			local article = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
			local cats = {}

			local function addCat(cat, sort)
				cats[#cats + 1] = Category.new(cat, sort)
			end

			-- Page-wide status categories
			if status == 'FA' then
				addCat('مقاله‌های درجه برگزیده موضوعات برگزیده')
			elseif status == 'FL' then
				addCat('مقاله‌های درجه فهرست برگزیده موضوعات برگزیده')
			elseif status == 'FFA/GA' or status == 'GA' then
				addCat('مقاله‌های درجه خوب موضوعات برگزیده')
			else
				addCat('مقاله‌های درجه ارزیابی‌نشده موضوعات برگزیده')
			end

			-- Topic-specific status categories
			local function addTopicCats(catFormat)
				for i, topic in ipairs(data) do
					addCat(string.format(catFormat, topic.name))
				end
			end
			if status == 'FA' or status == 'FL' then
				addTopicCats('محتوای برگزیده در موضوع برگزیده %s')
			elseif status == 'FFA/GA' or 'GA' then
				addTopicCats('محتوای خوب در موضوع برگزیده %s')
			else
				addTopicCats('موضوع برگزیده %s')
			end

			-- Importance categories: not used in fawiki, so commented out
			--[===[ 
			local hasTop, hasHigh, hasMid, hasLow -- These check for dupes
			for i, topic in ipairs(data) do
				local cat, sort
				if topic.status == 'FT' then
					if topic.isMain and not hasTop then
						cat = 'Top-importance Featured topics articles'
						sort = topic.name .. ' ' .. article
						hasTop = true
					elseif not topic.isMain and not hasHigh then
						cat = 'High-importance Featured topics articles'
						hasHigh = true
					end
				else
					if topic.isMain and not hasMid then
						cat = 'Mid-importance Featured topics articles'
						sort = topic.name .. ' ' .. article
						hasMid = true
					elseif not topic.isMain and not hasLow then
						cat = 'Low-importance Featured topics articles'
						hasLow = true
					end
				end
				if cat then
					addCat(cat, sort)
				end
			end
			]===]

			return cats
		end
	},

	-- Main page date
	{
		id = 'MAINDATE',
		isActive = function (articleHistoryObj)
			local args = articleHistoryObj.args
			local status = articleHistoryObj:getStatusId()
			return args.maindate or status == 'FA' or status == 'FL'
		end,
		makeData = function (articleHistoryObj)
			local args = articleHistoryObj.args
			local status = articleHistoryObj:getStatusId()
			local data = {}

			local function validateMainDate(argName, dataName)
				local originalDate = args[argName]
				if originalDate then
					data[dataName] = getDate(originalDate)
					if not data[dataName] then
						articleHistoryObj:raiseError(
							string.format(
								"تاریخ نامعتبر '%s' در پارامتر '%s' شناسایی شد",
								originalDate,
								argName
							),
							'الگو:تاریخچه مقاله#Invalid date'
						)
					end
				end
			end

			validateMainDate('maindate', 'mainDate')
			if data.mainDate then
				validateMainDate('maindate2', 'mainDate2')
				if data.mainDate2 and data.mainDate.Ymd >= data.mainDate2.Ymd then
					articleHistoryObj:raiseError(
						"the date in the 'maindate' parameter must be earlier than the date in the 'maindate2' parameter",
						'الگو:تاریخچه مقاله#Main Page date order'
					)
				end
			end

			data.currentDate = getDate()
			
			-- Whether the page is a list or not for the purposes of the Main
			-- Page. The first Today's Featured List was on 13 June 2011, so
			-- lists that were featured before then count as articles.
			data.isList = (status == 'FL' or status == 'FFL')
				and (not data.mainDate or data.mainDate.Ymd >= 20110613)

			return data
		end,
		icon = 'Wikipedia-logo-v2.svg',
		iconCaption = 'Main Page trophy',
		text = function (articleHistoryObj, noticeObj)
			local data = noticeObj:getData(articleHistoryObj)
			if not data or not data.mainDate then
				return nil
			end

			-- Build the blurb for all the possible combinations of past,
			-- present and future appearances of maindate and maindate2.
			local pagetype = data.isList and 'فهرست' or 'مقاله'
			local mainDate = data.mainDate
			local mainDate2 = data.mainDate2
			local todaysFA = "نوشتار پیشنهادی هفته"

			local function makeFeaturedLink(date, display)
				return string.format(
					"[[اسلامیکال:نوشتار پیشنهادی هفته/%s/%s|%s]]",
					date.fao, date.faW,
					display or ('هفتهٔ ' .. date.fao .. 'سال ' .. date.faW)
				)
			end

			local function isPastWeek(date)
				return date.o < data.currentDate.o or (date.o == data.currentDate.o and date.W < data.currentDate.W)
			end

			local function isCurrentWeek(date)
				return date.o == data.currentDate.o and date.W == data.currentDate.W
			end

			local function isFutureWeek(date)
				return date.o > data.currentDate.o or (date.o == data.currentDate.o and date.W > data.currentDate.W)
			end

			if data.mainDate2 then
				if isPastWeek(mainDate) then
					if isPastWeek(mainDate2) then
						return string.format(
							"این مقاله در %s و %s به عنوان %s به صفحهٔ اصلی اسلامیکال رفت.",
							makeFeaturedLink(mainDate),
							makeFeaturedLink(mainDate2),
							todaysFA
						)
					elseif isCurrentWeek(mainDate2) then
						return string.format(
							"این مقاله هم‌اکنون به عنوان %s در صفحهٔ اصلی اسلامیکال قرار دارد. نمایش قبلی آن %s بود.",
							makeFeaturedLink(mainDate2, todaysFA),
							makeFeaturedLink(mainDate)
						)
					else
						return string.format(
							"این مقاله در %s به عنوان %s به صفحهٔ اصلی اسلامیکال رفت و نمایش بعدی آن در %s خواهد بود.",
							makeFeaturedLink(mainDate),
							todaysFA,
							makeFeaturedLink(mainDate2)
						)
					end
				elseif isCurrentWeek(mainDate) then
					if isFutureWeek(mainDate2) then
						return string.format(
							"این مقاله هم‌اکنون به عنوان %s در صفحهٔ اصلی اسلامیکال قرار دارد. نمایش بعدی آن در %s خواهد بود.",
							makeFeaturedLink(mainDate, todaysFA),
							makeFeaturedLink(mainDate2)
						)
					else
						return nil
					end
				else
					if isFutureWeek(mainDate2) then
						return string.format(
							"این مقاله به عنوان %s اسلامیکال در %s روی صفحهٔ اصلی خواهد رفت و نوبت بعدی آن %s است.",
							todaysFA,
							makeFeaturedLink(mainDate),
							makeFeaturedLink(mainDate2)
						)
					else
						return nil
					end
				end
			else
				if isPastWeek(mainDate) then
					return string.format(
						"این مقاله در هفتهٔ %s سال %s به عنوان %s به صفحهٔ اصلی اسلامیکال رفت.",
						mainDate.faW, mainDate.fao,
						makeFeaturedLink(mainDate, todaysFA)
					)
				elseif isCurrentWeek(mainDate) then
					return string.format(
						"این مقاله هم‌اکنون به عنوان %s در صفحهٔ اصلی اسلامیکال قرار دارد.",
						makeFeaturedLink(mainDate, todaysFA),
						mainDate.faW, mainDate.fao
					)
				else
					return string.format(
						"این مقاله به عنوان %s اسلامیکال در هفتهٔ %s سال %s روی صفحهٔ اصلی خواهد رفت.",
						makeFeaturedLink(mainDate, todaysFA),
						mainDate.faW, mainDate.fao
					)
				end
			end
		end,
		categories = function (articleHistoryObj, noticeObj)
			local data = noticeObj:getData(articleHistoryObj)
			if not data then
				return nil
			end
			local status = articleHistoryObj:getStatusId()
			local cats = {}

			local pagetype = data.isList and 'فهرست‌های' or 'مقاله‌های'
			if data.mainDate and data.mainDate.Ymd <= data.currentDate.Ymd then
				cats[#cats + 1] = Category.new(string.format(
					'%s برگزیده که در صفحهٔ اصلی نمایش یافته‌اند',
					pagetype
				))
				if data.mainDate2 and data.mainDate2.Ymd <= data.currentDate.Ymd then
					cats[#cats + 1] = Category.new(string.format(
						'%s برگزیده که در صفحهٔ اصلی دو بار نمایش یافته‌اند',
						pagetype
					))
				else
					cats[#cats + 1] = Category.new(string.format(
						'%s برگزیده که در صفحهٔ اصلی یک بار نمایش یافته‌اند',
						pagetype
					))
				end
			elseif status == 'FA' or status == 'FL' or data.mainDate then
				cats[#cats + 1] = Category.new(string.format(
					'%s برگزیده که در صفحهٔ اصلی نمایش نیافته‌اند',
					pagetype
				))
			end
			return cats
		end
	}
},

-------------------------------------------------------------------------------
-- Actions
-------------------------------------------------------------------------------

-- The actions table contains configuration tables for actions such as featured
-- article candidacies and peer review, etc.
-- Each configuration table can have the following fields:
--
-- id: the main ID for the action. This should be the same as the configuration
--    table key.
-- name: the name of the action. This can be a string or a function. If it is
--    a function, it takes an article history object as its first parameter and
--    the action object as its second parameter, and should return the name.
-- results: a table of possible results for the action. Keys in the table should
--    be a result ID, e.g. "promoted" or "kept", and values should be a subtable
--    with the following fields:
--    id: the result ID. This should be the same as the table key. It will
--        also define a possible input value for the action's result parameter.
--    text: the displayed result text. This may be a string or a function. If it
--        is a function, it takes an article history object as the first
--        parameter and the current action object as the second parameter, and
--        should return the result string.
--    aliases: an array of result ID aliases. Each of these will define a valid
--        value for the action's result parameter.
-- text: The action text. This may be a string or a function. If it is a
--    function, it takes an article history object as the first parameter and
--    the current action object as the second parameter, and should return the
--    text string.
-- categories: The categories set by the notice. This may be an array of
--    category names, or a function. If it is a function, it takes an article
--    history object as the first parameter and the current action object as the
--    second parameter, and should return an array of category objects.
-- noticeBarIcon: the icon to use for the notice bar. This can be a string, or
--    a function, or true. If it is a function it takes an article history
--    object as the first parameter, and should output the icon filename. If it
--    is true, it uses the value of icon. If it is nil then no notice bar icon
--    will be displayed.
-- noticeBarIconCaption: the caption to use for the notice bar icon. This can be
--    a string or a function. If it is a function, it takes an article history
--    object as its first parameter, and should return the caption text. If this
--    is absent, the icon caption is used instead.
-- noticeBarIconSize: the size of the notice bar icon, including "px" suffix.
--    The default is set by defaultNoticeBarIconSize.

actions = {
	FAC = {
		id = 'FAC',
		name = 'نامزدی برای مقالهٔ برگزیده',
		results = {
			promoted = {
				id = 'promoted',
				text = 'برگزیده شد',
				aliases = {'pass', 'passed'}
			},
			['not promoted'] = {
				id = 'not promoted',
				text = 'برگزیده نشد',
				aliases = {'fail', 'failed'}
			}
		}
	},
	FAR = {
		id = 'FAR',
		name = 'بازبینی مقالهٔ برگزیده',
		aliases = {'FARC'},
		results = {
			kept = {
				id = 'kept',
				text = 'برگزیده ماند',
				aliases = {'pass', 'passed', 'keep'}
			},
			demoted = {
				id = 'demoted',
				text = 'برگزیده نماند',
				aliases = {'fail', 'failed', 'remove', 'removed'}
			},
			merged = {
				id = 'merged',
				text = 'ادغام شد',
				aliases = {'merge'}
			}
		},
		categories = function (articleHistoryObj, actionObj)
			local ret = {}
			local result = actionObj.resultId
			if result == 'demoted' or result == 'merged' then
				local status = articleHistoryObj:getStatusId()
				local sortKey = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
				if status == 'FA' or status == 'FL' then
					sortKey = '#' .. sortKey
				end
				ret[#ret + 1] = Category.new(
					'مقاله‌های برگزیده پیشین ',
					sortKey
				)
			end
			return ret
		end
	},
	BP = {
		id = 'BP',
		name = 'Brilliant prose',
		results = {
			nominated = {
				id = 'nominated',
				text = 'نامزد شد',
				aliases = {'pass', 'promoted', 'nom'}
			}
		}
	},
	RBP = {
		id = 'RBP',
		name = 'Refreshing brilliant prose',
		results = {
			kept = {
				id = 'kept',
				text = 'باقی ماند',
				aliases = {'pass', 'passed', 'keep'}
			},
			['not kept'] = {
				id = 'not kept',
				text = 'باقی نماند',
				aliases = {'fail', 'failed', 'remove', 'removed', 'demoted'}
			}
		},
		categories = function (articleHistoryObj, actionObj)
			local ret = {}
			if actionObj.resultId == 'not kept' then
				ret[#ret + 1] = Category.new(
					'Islamical former brilliant prose',
					articleHistoryObj.currentTitle.text
				)
			end
			return ret
		end
	},
	FLC = {
		id = 'FLC',
		name = 'نامزد فهرست برگزیده',
		results = {
			promoted = {
				id = 'promoted',
				text = 'برگزیده شد',
				aliases = {'pass', 'passed'}
			},
			['not promoted'] = {
				id = 'not promoted',
				text = 'برگزیده نشد',
				aliases = {'fail', 'failed'}
			}
		}
	},
	FLR = {
		id = 'FLR',
		name = 'نامزد بازبینی فهرست برگزیده',
		results = {
			kept = {
				id = 'kept',
				text = 'برگزیده ماند',
				aliases = {'pass', 'passed', 'keep'}
			},
			demoted = {
				id = 'demoted',
				text = 'برگزیده نماند',
				aliases = {'fail', 'failed', 'remove', 'removed'}
			},
			merged = {
				id = 'merged',
				text = 'ادغام شد',
				aliases = {'merge'}
			}
		},
		categories = function (articleHistoryObj, actionObj)
			local ret = {}
			local result = actionObj.resultId
			if result == 'demoted' or result == 'merged' then
				local sortKey
				if articleHistoryObj:getStatusId() == 'FL' then
					sortKey = '#' .. articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
				else
					sortKey = articleHistoryObj.currentTitle.text
				end
				ret[#ret + 1] = Category.new(
					'فهرست‌های برگزیده پیشین اسلامیکال',
					sortKey
				)
			end
			return ret
		end
	},
	FTC = {
		id = 'FTC',
		name = 'نامزدی برای موضوع برگزیده',
		results = {
			promoted = {
				id = 'promoted',
				text = 'برگزیده شد',
				aliases = {'pass', 'passed'}
			},
			['not promoted'] = {
				id = 'not promoted',
				text = 'برگزیده نشد',
				aliases = {'fail', 'failed'}
			}
		}
	},
	FTR = {
		id = 'FTR',
		name = 'بازبینی موضوع برگزیده',
		results = {
			kept = {
				id = 'kept',
				text = 'برگزیده ماند',
				aliases = {'pass', 'passed', 'keep'}
			},
			demoted = {
				id = 'demoted',
				text = 'برگزیده نماند',
				aliases = {'fail', 'failed', 'remove', 'removed'}
			},
			merged = {
				id = 'merged',
				text = 'ادغام شد',
				aliases = {'merge'}
			}
		}
	},
	FPOC = {
		id = 'FPOC',
		name = 'نامزد درگاه برگزیده',
		results = {
			promoted = {
				id = 'promoted',
				text = 'برگزیده شد',
				aliases = {'pass', 'passed'}
			},
			['not promoted'] = {
				id = 'not promoted',
				text = 'برگزیده نشد',
				aliases = {'fail', 'failed'}
			}
		}
	},
	FPOR = {
		id = 'FPOR',
		name = 'بازبینی درگاه برگزیده',
		results = {
			kept = {
				id = 'kept',
				text = 'برگزیده ماند',
				aliases = {'pass', 'passed', 'keep'}
			},
			demoted = {
				id = 'demoted',
				text = 'برگزیده نماند',
				aliases = {'fail', 'failed', 'remove', 'removed'}
			},
			merged = {
				id = 'merged',
				text = 'ادغام شد',
				aliases = {'merge'}
			}
		}
	},
	GAN = {
		id = 'GAN',
		name = 'نامزدی برای مقالهٔ خوب',
		aliases = {'GAC'},
		results = {
			listed = {
				id = 'listed',
				text = 'خوب شد',
				aliases = {'pass', 'passed', 'promoted'}
			},
			['not listed'] = {
				id = 'not listed',
				text = 'خوب نشد',
				aliases = {'fail', 'failed', 'not promoted'}
			}
		},
		categories = function (articleHistoryObj, actionObj)
			local ret = {}
			if actionObj.resultId == 'not listed' then
				local status = articleHistoryObj:getStatusId()
				if status ~= 'FA'
					and status ~= 'GA'
					and status ~= 'FFA'
				then
					ret[#ret + 1] = Category.new(
						'مقاله‌های ناموفق در خوبیدگی',
						articleHistoryObj.currentTitle.text
					)
				end
			end
			return ret
		end
	},
	GAR = {
		id = 'GAR',
		name = 'بازبینی مقالهٔ خوب',
		results = {
			kept = {
				id = 'kept',
				text = 'خوب ماند',
				aliases = {'pass', 'passed', 'keep'}
			},
			delisted = {
				id = 'delisted',
				text = 'خوب نماند',
				aliases = {'fail', 'failed'}
			},
			listed = {
				id = 'listed',
				text = 'خوب شد'
			},
			['not listed'] = {
				id = 'not listed',
				text = 'خوب نشد'
			}
		},
		categories = function (articleHistoryObj, actionObj)
			local ret = {}
			if actionObj.resultId == 'delisted' then
				local status = articleHistoryObj:getStatusId()
				if status ~= 'FA'
					and status ~= 'GA'
				then
					ret[#ret + 1] = Category.new(
						'مقاله‌های خوب پیشین',
						articleHistoryObj.currentTitle.text
					)
				end
			end
		end
	},
	GTC = {
		id = 'GTC',
		name = 'نامزدی برای موضوع خوب',
		results = {
			promoted = {
				id = 'promoted',
				text = 'خوب شد',
				aliases = {'pass', 'passed'}
			},
			['not promoted'] = {
				id = 'not promoted',
				text = 'خوب نشد',
				aliases = {'fail', 'failed'}
			}
		}
	},
	GTR = {
		id = 'GTR',
		name = 'نامزد بازبینی موضوع خوب',
		results = {
			kept = {
				id = 'kept',
				text = 'خوب ماند',
				aliases = {'pass', 'passed', 'keep'}
			},
			demoted = {
				id = 'demoted',
				text = 'خوب نماند',
				aliases = {'fail', 'failed', 'remove', 'removed'}
			},
			merged = {
				id = 'merged',
				text = 'ادغام شد',
				aliases = {'merge'}
			}
		}
	},
	PR = {
		id = 'PR',
		name = 'داوری همتا',
		results = {
			reviewed = {
				id = 'reviewed',
				text = 'بازبینی شد',
				aliases = {'_BLANK'}
			},
			['not reviewed'] = {
				id = 'not reviewed',
				text = 'بازبینی نشد',
			}
		},
		categories = {'Old requests for peer review'}
	},
	WPR = {
		id = 'WPR',
		name = function (articleHistoryObj, actionObj)
			local names = {
				approved = 'WikiProject approved revision',
				copyedited = 'Guild of Copy Editors',
				collaboration = 'WikiProject collaboration',
				maindate = "نوشتار پیشنهادی هفته"
			}
			local result = actionObj.resultId
			return result and names[result] or 'WikiProject peer review'
		end,
		results = {
			approved = {
				id = 'approved',
				text = function(articleHistoryObj, actionObj)
					if actionObj.oldid then
						local url = mw.uri.fullUrl(
							articleHistoryObj.currentTitle.prefixedText,
							{diff = 'cur', oldid = actionObj.oldid}
						)
						return string.format(
							'[%s %s]',
							tostring(url),
							'Diff to current version'
						)
					else
						error(string.format(
							"No oldid detected for the approved version; " ..
								"please set the 'action%doldid' parameter " ..
								"or give the 'action%dresult' parameter a " ..
								"different value.",
							actionObj.paramNum,
							actionObj.paramNum
						))
					end
				end,
				aliases = {'approved version'}
			},
			copyedited = {
				id = 'copyedited',
				text = 'Copyedited',
				aliases = {'copyedit', 'proofread'}
			},
			maindate = {
				id = 'maindate',
				text = 'صفحهٔ اصلی'
			},
			collaborated = {
				id = 'collaborated',
				text = 'Collaborated',
				aliases = {'cotw', 'collaboration'}
			},
			reviewed = {
				id = 'reviewed',
				text = 'بازبینی شد',
				aliases = {'_BLANK'}
			}
		}
	},
	WAR = {
		id = 'WAR',
		name = 'WikiProject A-class review',
		results = {
			approved = {
				id = 'approved',
				text = 'پذیرفته شد',
				aliases = {'pass', 'passed'}
			},
			['not approved'] = {
				id = 'not approved',
				text = 'پذیرفته نشد',
				aliases = {'fail', 'failed', 'not reviewed'}
			},
			reviewed = {
				id = 'reviewed',
				text = 'بازبینی شد',
				aliases = {'_BLANK'}
			},
			kept = {
				id = 'kept',
				text = 'باقی ماند',
				aliases = {'keep'}
			},
			demoted = {
				id = 'demoted',
				text = 'باقی نماند',
				aliases = {'demote'}
			}
		}
	},
	AFD = {
		id = 'AFD',
		name = 'نظرخواهی برای حذف',
		results = {
			kept = {
				id = 'kept',
				text = 'باقی ماند',
				aliases = {'withdrawn', 'keep'}
			},
			deleted = {
				id = 'deleted',
				text = 'حذف شد',
				aliases = {'delete'}
			},
			merged = {
				id = 'merged',
				text = 'ادغام شد',
				aliases = {'merge'}
			},
			['no consensus'] = {
				id = 'no consensus',
				text = 'به اجماع نرسید'
			},
			['speedily kept'] = {
				id = 'speedily kept',
				text = 'سریع باقی ماند',
				aliases = {'speedy keep'}
			},
			['speedily deleted'] ={
				id = 'speedily deleted',
				text = 'سریع حذف شد',
				aliases = {'speedy delete'}
			},
			redirected = {
				id = 'redirected',
				text = 'تغییرمسیر شد',
				aliases = {'redirect'}
			},
			renamed = {
				id = 'renamed',
				text = 'تغییر نام یافت',
				aliases = {'rename', 'move', 'moved'}
			},
		}
	},
	MFD = {
		id = 'MFD',
		name = 'Miscellanea for deletion',
		results = {
			kept = {
				id = 'kept',
				text = 'Kept',
				aliases = {'withdrawn', 'keep'}
			},
			deleted = {
				id = 'deleted',
				text = 'Deleted',
				aliases = {'delete'}
			},
			merged = {
				id = 'merged',
				text = 'Merged',
				aliases = {'merge'}
			},
			['no consensus'] = {
				id = 'no consensus',
				text = 'No consensus'
			},
			['speedily kept'] = {
				id = 'speedily kept',
				text = 'Speedily kept',
				aliases = {'speedy keep'}
			},
			['speedily deleted'] = {
				id = 'speedily deleted',
				text = 'Speedily deleted',
				aliases = {'speedy delete'}
			},
			redirected = {
				id = 'redirected',
				text = 'Redirected',
				aliases = {'redirect'}
			},
			renamed = {
				id = 'renamed',
				text = 'Renamed',
				aliases = {'rename', 'move', 'moved'}
			},
		}
	},
	TFD = {
		id = 'TFD',
		name = 'Templates for discussion',
		results = {
			kept = {
				id = 'kept',
				text = 'Kept',
				aliases = {'withdrawn', 'keep'}
			},
			deleted = {
				id = 'deleted',
				text = 'Deleted',
				aliases = {'delete'}
			},
			merged = {
				id = 'merged',
				text = 'Merged',
				aliases = {'merge'}
			},
			['no consensus'] = {
				id = 'no consensus',
				text = 'No consensus'
			},
			['speedily kept'] = {
				id = 'speedily kept',
				text = 'Speedily kept',
				aliases = {'speedy keep'}
			},
			['speedily deleted'] = {
				id = 'speedily deleted',
				text = 'Speedily deleted',
				aliases = {'speedy delete'}
			},
			redirected = {
				text = 'Redirected',
				aliases = {'redirect'}
			},
			renamed = {
				id = 'renamed',
				text = 'Renamed',
				aliases = {'rename', 'move', 'moved'}
			},
		}
	},
	CSD = {
		id = 'CSD',
		name = 'Candidate for speedy deletion',
		results = {
			kept = {
				id = 'kept',
				text = 'Kept',
				aliases = {'withdrawn', 'keep'}
			},
			deleted = {
				id = 'deleted',
				text = 'Deleted',
				aliases = {'delete', 'speedily deleted', 'speedy delete'}
			},
			['speedily kept'] = {
				id = 'speedily kept',
				text = 'Speedily kept',
				aliases = {'speedy keep'}
			},
			redirected = {
				id = 'redirected',
				text = 'Redirected',
				aliases = {'redirect'}
			},
			prod = {
				id = 'prod',
				text = 'به [[اسلامیکال:حذف زمان‌دار|حذف زمان‌دار]] منتقل شد',
				aliases = {'prodded'}
			},
			afd = {
				id = 'afd',
				text = 'Sent to [[WP:AFD|articles for deletion]]',
				aliases = {'afded'}
			},
			renamed = {
				id = 'renamed',
				text = 'Renamed',
				aliases = {'rename', 'move', 'moved'}
			},
		}
	},
	PROD = {
		id = 'PROD',
		name = 'حذف زمان‌دار',
		results = {
			kept = {
				id = 'kept',
				text = 'باقی ماند',
				aliases = {'withdrawn', 'keep'}
			},
			deleted = {
				id = 'deleted',
				text = 'حذف شد',
				aliases = {'delete'}
			},
			['speedily kept'] = {
				id = 'speedily kept',
				text = 'به سرعت باقی ماند',
				aliases = {'speedy keep'}
			},
			['speedily deleted'] = {
				id = 'speedily deleted',
				text = 'به سرعت حذف شد',
				aliases = {'speedy delete'}
			},
			redirected = {
				id = 'redirected',
				text = 'تبدیل به تغییرمسیر شد',
				aliases = {'redirect'}
			},
			afd = {
				id = 'afd',
				text = 'Sent to [[WP:AFD|articles for deletion]]',
				aliases = {'afded'}
			},
			renamed = {
				id = 'renamed',
				text = 'تغییر نام یافت',
				aliases = {'rename', 'move', 'moved'}
			},
		}
	},
	DRV = {
		id = 'DRV',
		name = 'Deletion review',
		results = {
			endorsed = {
				id = 'endorsed',
				text = 'Endorsed',
				aliases = {'endorse'}
			},
			relisted = {
				id = 'relisted',
				text = 'Relisted',
				aliases = {'relist'}
			},
			overturned = {
				id = 'overturned',
				text = 'Overturned',
				aliases = {'overturn'}
			},
			['no consensus'] = {
				id = 'no consensus',
				text = 'No consensus'
			}
		}
	}
},

-------------------------------------------------------------------------------
-- Collapsible notices
-------------------------------------------------------------------------------

-- The collapsibleNotices table contains configuration tables for notices that
-- go in the collapsible part of the template, underneath the actions.
-- Each configuration table can have the following fields:
--
-- id: the main ID for the notice. This should be the same as the configuration
--    table key.
-- isActive: a function that should return a truthy value if the notice should
--    be displayed, and a falsy value if not. (Falsy values are false and nil,
--    and truthy values are everything else.) The function takes an article
--    history object as its first parameter.
-- makeData: a function that should return a table of data to be used by other
--    functions in this notice configuration table. It can be accessed using
--    noticeObj:getData().
-- icon: the filename of the notice icon, minus the "File:" prefix.
-- iconCaption: the icon caption.
-- iconSize: The icon size, including "px" suffix. The default is defined in
--    defaultIconSize.
-- iconSmallSize: The icon size if we are outputting a small template. The
--    default is defined in defaultSmallIconSize.
-- text: The notice text. This may be a string or a function. If it is a
--    function, it takes an article history object as the first parameter, and
--    the current collapsible notice object as the second parameter, and should
--    return the text string.
-- categories: The categories set by the notice. This may be an array of
--    category names, or a function. If it is a function, it takes an article
--    history object as the first parameter, and the current collapsible notice
--    object as the second parameter, and should return an array of category
--    objects.
-- noticeBarIcon: the icon to use for the notice bar. This can be a string, or
--    a function, or true. If it is a function it takes an article history
--    object as the first parameter, and should output the icon filename. If it
--    is true, it uses the value of icon. If it is nil then no notice bar icon
--    will be displayed.
-- noticeBarIconCaption: the caption to use for the notice bar icon. This can be
--    a string or a function. If it is a function, it takes an article history
--    object as its first parameter, and should return the caption text. If this
--    is absent, the icon caption is used instead.
-- noticeBarIconSize: the size of the notice bar icon, including "px" suffix.
--    The default is set by defaultNoticeBarIconSize.

collapsibleNotices = {
	-- DYK
	{
		id = 'DYK',
		icon = 'Symbol_question_fa.svg',
		iconCaption = 'آیا می‌دانستید که',
		iconSmallSize = '15px',
		noticeBarIcon = true,
		isActive = function (articleHistoryObj)
			return isActiveDatedObject(articleHistoryObj, 'dyk')
		end,
		makeData = function (articleHistoryObj)
			return makeDateData(articleHistoryObj, 'dyk', {'entry','link'})
		end,
		text = function (articleHistoryObj, collapsibleNoticeObj)
			local data = collapsibleNoticeObj:getData(articleHistoryObj)
			if not data then
				return nil
			end
			local week, year = data[1].date.faW, data[1].date.fao
			local raPage = 'اسلامیکال:آیا می‌دانستید که...؟/' .. year .. '/هفته ' .. week
			if not titleExists(raPage) then
				raPage = 'اسلامیکال:آیا می‌دانستید که...؟'
			end
			local blurb = string.format(
				"یک جمله از این مقاله در '''[[%s|هفتهٔ %s سال %s]]''' در " ..
					"ستون ''«[[اسلامیکال:آیا می‌دانستید که...؟|آیا می‌دانستید که...؟]]»'' [[صفحهٔ اصلی]] اسلامیکال به نمایش درآمده است.",
				raPage, week, year
			)
			return makeDateText(data, blurb)
		end,
		collapsibleText = function (articleHistoryObj, collapsibleNoticeObj)
			local data = collapsibleNoticeObj:getData(articleHistoryObj)
			if not data then
				return nil
			end
			local ctext = {}
			if #data == 1 and data[1].entry then
                if data[1].link then
                    ctext[#ctext + 1] = string.format(
                        "'''[[%s|متن ورودی]]''' به شرح زیر بود: ''آیا می‌دانستید که %s''",
                        data[1].link,data[1].entry
                    )
                else
                    ctext[#ctext + 1] = string.format(
                        "متن ورودی به شرح زیر بود: ''آیا می‌دانستید که %s''",
                        data[1].entry
                    )
               end
			else
				local entries = {}
				local lastEntryDate
                local DYKLink
				for i, t in ipairs(data) do
					entries[#entries + 1] = t.entry
					lastEntryDate = t.date.long
                    DYKLink = t.link
				end
				if #entries == 1 then
                    if DYKLink then
                        ctext[#ctext + 1] = string.format(
                            "'''[[%s|متن ورودی]]''' به شرح زیر بود: ''آیا می‌دانستید که %s''",
                            DYKLink,lastEntryDate, entries[1]
                        )
                    else
                        ctext[#ctext + 1] = string.format(
                            "'''متن ورودی به شرح زیر بود: ''آیا می‌دانستید که %s''",
                            lastEntryDate, entries[1]
                        )
                    end
				elseif #entries > 1 then
					ctext[#ctext + 1] = 'متن ورودی‌ها به شرح زیر بودند:\n'
					local list = mw.html.create('ul')
					for i, t in ipairs(data) do
						if t.entry then
                            if t.link then
                                list:tag('li'):wikitext(string.format(
                                    "%s: ''([[%s|پیوند]]): آیا می‌دانستید که %s''",
                                    t.date.long,t.link, t.entry
                                ))
                            else
                                list:tag('li'):wikitext(string.format(
                                    "%s: '' آیا می‌دانستید که %s''",
                                    t.date.long, t.entry
                                ))
                            end
						end
					end
					ctext[#ctext + 1] = tostring(list)
				end
			end
			if #ctext > 0 then
				return table.concat(ctext)
			else
				return nil
			end
		end,
		
		-- not used in fawiki, so commented out
		--[===[
		categories = function (articleHistoryObj, collapsibleNoticeObj)
			local cats = {}
			local status = articleHistoryObj:getStatusId()
			local cat
			if status == 'FA' then
				cat = 'مقاله‌های آیا می‌دانستید اسلامیکال'
			elseif status == 'FL' then
				cat = 'مقاله‌های آیا می‌دانستید اسلامیکال'
			elseif status == 'GA' or status == 'FFA/GA' then
				cat = 'مقاله‌های آیا می‌دانستید اسلامیکال'
			else
				cat = 'مقاله‌های آیا می‌دانستید اسلامیکال'
			end
			cats[1] = Category.new(cat)
			return cats
		end
		]===]--
	},

	-- ITN
	{
		id = 'ITN',
		isActive = function (articleHistoryObj)
			return isActiveDatedObject(articleHistoryObj, 'itn')
		end,
		makeData = function (articleHistoryObj)
			return makeDateData(articleHistoryObj, 'itn', {'link'})
		end,
		icon = 'Globe current.svg',
		iconCaption = 'In the news',
		noticeBarIcon = true,
		noticeBarIconSize = '20px',
		text = function (articleHistoryObj, collapsibleNoticeObj)
			local data = collapsibleNoticeObj:getData(articleHistoryObj)
			if not data then
				return nil
			end
			local dates = {}
			for i, t in ipairs(data) do
				local date = {}
				if t.link then
					date.link = t.link
				elseif t.date.Ymd >= 20090101 then
					date.link = string.format(
						'Islamical:ITN archives/%s/%s',
						t.date.faY,
						t.date.fam
					)
				elseif t.date.Ymd >= 20050101 then
					date.link = string.format(
						'Portal:Current events/%s %s %s',
						t.date.faY,
						t.date.fam,
						t.date.fad
					)
				end
				date.date = t.date
				dates[#dates + 1] = date
			end
			local intro
			if #data > 1 then
				intro = 'News items involving this article were'
			else
				intro = 'A news item involving this article was'
			end
			local blurb = intro ..
				" featured on Islamical's [[Main Page]] in the " ..
				"''\"[[Template:In the news|In the news]]\"'' column on $1."
			return makeDateText(dates, blurb)
		end,
		categories = function (articleHistoryObj, collapsibleNoticeObj)
			local cats = {}
			cats[1] = Category.new('مقاله‌های از میان خبرهای اسلامیکال')
			return cats
		end
	},

	-- On This Day
	{
		id = 'OTD',
		isActive = function (articleHistoryObj)
			return isActiveDatedObject(articleHistoryObj, 'otd')
		end,
		makeData = function (articleHistoryObj)
			return makeDateData(articleHistoryObj, 'otd', {'link', 'oldid'})
			-- TODO: remove 'link' after it is no longer needed for tracking
		end,
		icon = 'Nuvola apps date-fa.png',
		iconCaption = '...یادبودها',
		noticeBarIcon = true,
		noticeBarIconSize = '35px',
		text = function (articleHistoryObj, collapsibleNoticeObj)
			local data = collapsibleNoticeObj:getData(articleHistoryObj)
			if not data then
				return nil
			end
			local dates = {}
			for i, t in ipairs(data) do
				local date = {}
				date.date = t.date
				date.link = t.link
				if t.oldid then
					-- TODO: Move this inside the main module
					local oldid = tonumber(t.oldid)
					if oldid and 
						math.floor(oldid) == oldid and
						oldid > 0 and
						oldid < math.huge
					then
						-- If the oldid is valid, it takes precedence over
						-- explicit links.
						date.link = 'Special:PermaLink/' .. t.oldid
					else
						collapsibleNoticeObj:addWarning(
							string.format(
								"invalid oldid '%s' detected in parameter '%s'; " ..
									"if an oldid is specified it must be a positive integer",
								t.oldid,
								t.argPrefix .. 'oldid'
							),
							'الگو:تاریخچه مقاله#Invalid oldid'
						)
					end
				end
				dates[#dates + 1] = date
			end
			local intro
			if #data > 1 then
				intro = 'یادبودهایی از این مقاله '
			else
				intro = 'یادبودی از این مقاله '
			end
			local blurb = intro ..
				"در ستون یادبودها در تاریخ $1 در [[صفحهٔ اصلی]] اسلامیکال به نمایش درآمده است. " 
			return makeDateText(dates, blurb)
		end,
		categories = function (articleHistoryObj, collapsibleNoticeObj)
			local cats = {}
			cats[1] = Category.new('مقاله‌های یادبودهای برگزیده')
			local data = collapsibleNoticeObj:getData(articleHistoryObj)
			if data then
				for i, t in ipairs(data) do
					if t.link then
						cats[#cats + 1] = Category.new(
							'الگو:تاریخچه مقاله دارای پیوند به otd dates'
						)
						break
					end
				end
			end
			return cats
		end
	},

	-- Article Collaboration and Improvement Drive
	{
		id = 'ACID',
		isActive = function (articleHistoryObj)
			return articleHistoryObj.args.aciddate
		end,
		icon = 'Article Collaboration and Improvement Drive.svg',
		iconCaption = 'Article Collaboration and Improvement Drive',
		noticeBarIcon = true,
		noticeBarIconSize = '20px',
		text = function (articleHistoryObj)
			local args = articleHistoryObj.args
			local blurb = 'This article was on the ' ..
				'[[WP:ACID|Article Collaboration and Improvement Drive]] ' ..
				'for the week of %s.'
			local date = validateDate('aciddate', args.aciddate)
			return string.format(blurb, date.long)
		end
	},

	-- League of Copy Editors
	{
		id = 'LOCE',
		isActive = function (articleHistoryObj)
			return articleHistoryObj.args.loceNotAnActiveOption
		end,
		icon = 'LoCiconRevised.png',
		iconCaption = 'League of Copyeditors',
		iconSize = '25px',
		noticeBarIcon = true,
		text = 'This article, or a portion of it, was copyedited by the ' ..
			'[[WP:LoCE|League of Copyeditors]].'
	}
},

-------------------------------------------------------------------------------
-- Notice bar icons
-------------------------------------------------------------------------------

-- This table holds configuration tables for notice bar icons that don't appear
-- as part of a row. Other notice bar icons are handled in the statuses,
-- notices, actions, and collapsibleNotices tables.
-- It accepts the following fields:
-- isActive: a function that should return a truthy value if the notice should
--    be displayed, and a falsy value if not. (Falsy values are false and nil,
--    and truthy values are everything else.) The function takes an article
--    history object as its first parameter.
-- icon: the filename of the notice bar icon, minus the "File:" prefix.

noticeBarIcons = {
	-- Peer review, or NA status
	{
		isActive = function (articleHistoryObj)
			local status = articleHistoryObj:getStatusId()
			-- @XXX: This is what the template does, but we should take into
			-- account peer review actions as well.
			return not status or status == 'PR' or status == 'NA'
		end,
		icon = 'Nuvola apps kedit.svg'
	},

	-- Islamical 1.0
	{
		isActive = function (articleHistoryObj)
			return articleHistoryObj.args['v1.0NotAnActiveOption']
		end,
		icon = 'WP1 0 Icon.svg'
	}
},

-------------------------------------------------------------------------------
-- Extra categories
-------------------------------------------------------------------------------

-- This table contains categories that don't appear as part of a row. It is an
-- array of functions; each function takes an article history object as input
-- and must return an array of category objects as output.

extraCategories = {
	-- Four award
	function (articleHistoryObj)
		local yesno = require('Module:Yesno')
		local ret = {}
		local isFour = yesno(articleHistoryObj.args.four)
		if isFour then
			ret[#ret + 1] = Category.new('مقاله‌های دارای جایزه چهار')
		elseif isFour == false then
			ret[#ret + 1] = Category.new('مقاله‌های ناموفق در جایزه چهار')
		elseif articleHistoryObj:getStatusId() == 'FA' then
			local isDYK = false
			for i, obj in ipairs(articleHistoryObj:getCollapsibleNoticeObjects()) do
				if obj.id == 'DYK' then
					isDYK = true
					break
				end
			end
			if isDYK then
				for i, obj in ipairs(articleHistoryObj:getActionObjects()) do
					if obj.id == 'GAN' and obj.resultId == 'listed' then
						ret[#ret + 1] = Category.new('مقاله‌های احتمالی برای دریافت جایزه چهار')
						break
					end
				end
			end
		end
		return ret
	end,

	-- Deletion to Quality award
	function (articleHistoryObj)
		local ret = {}
		local status = articleHistoryObj:getStatusId()
		if status == 'FA' or status == 'FL' or status == 'GA' then
			local iAfd = 0
			local hasAfd = false
			local actionObjects = articleHistoryObj:getActionObjects()
			for i, obj in ipairs(actionObjects) do
				if obj.id == 'AFD' then
					iAfd = i
					hasAfd = true
					break
				end
			end
			if hasAfd then
				local function hasNomination(id, result)
					for i = iAfd + 1, #actionObjects do
						local obj = actionObjects[i]
						if obj.id == id and obj.resultId == result then
							return true
						end
					end
					return false
				end
				if status == 'GA' and hasNomination('GAN', 'listed') or
					status == 'FL' and hasNomination('FLC', 'promoted') or
					status == 'FA' and hasNomination('FAC', 'promoted')
				then
					ret[#ret + 1] = Category.new('نامزدهای جایزه حذف تا برگزیدگی')
				end
			end
		end
		return ret
	end,

	-- Track small banners
	function (articleHistoryObj)
		local ret = {}
		if articleHistoryObj.isSmall then
			table.insert(ret, Category.new('الگوهای تاریخچه مقاله در اندازه کوچک'))
		end
		return ret
	end,
},

-------------------------------------------------------------------------------
-- Parameters
-------------------------------------------------------------------------------

-- The parameter values used to generate the page actions. These are used as
-- Lua patterns, so any of the magic characters *+-.^$%[] should be escaped
-- with a preceding % symbol.
actionParamPrefix = 'action',
actionParamSuffixes = {
	[''] = 'code',
	date = 'date',
	link = 'link',
	result = 'resultCode',
	oldid = 'oldid'
},

-- The parameter used to set the current status.
currentStatusParam = 'currentstatus',

-------------------------------------------------------------------------------
-- Other settings
-------------------------------------------------------------------------------

-- If this number or fewer of collapsible rows are present (including actions
-- and collapsible notices) they will not be collapsed. If this is set to the
-- string "all", all rows will always be visible. Otherwise, the input must be
-- a number. The default is three rows.
uncollapsedRows = 3,

-- The default size for icons. The default is 30px.
defaultIconSize = '30px',

-- The default size for icons for small templates. The default is 15px.
defaultSmallIconSize = '15px',

-- The default size for status icons. The default is 50px.
defaultStatusIconSize = '50px',

-- The default size for status icons for small templates. The default is 30px.
defaultSmallStatusIconSize = '30px',

-- The default size for notice bar icons. The default is 15px.
defaultNoticeBarIconSize = '15px',

-- The default size for collapsible status icons. The default is 50px.
defaultCollapsibleNoticeIconSize = '20px',

-- The default size for collapsible status icons for small templates. The
-- default is 30px.
defaultSmallCollapsibleNoticeIconSize = '20px',

-------------------------------------------------------------------------------
-- Messages
-------------------------------------------------------------------------------

msg = {

-- The heading for the collapsible table of actions if we are in the main
-- namespace or the talk namespace.
['milestones-header'] = 'رخدادهای برجستهٔ مقاله',

-- The heading for the collapsible table of actions if we are in a different
-- namespace.
-- $1 - the subject namespace name.
['milestones-header-other-ns'] = '$1 رخداد برجسته',

-- The milestones date header.
['milestones-date-header'] = 'تاریخ',

-- The milestones process header.
['milestones-process-header'] = 'فرایند',

-- The milestones result header.
['milestones-result-header'] = 'نتیجه',

-- The format to display the action dates in. The syntax is the same as the
-- #time parser function.
['action-date-format'] = 'j F Y',

-- The category to use if any errors are detected.
['error-category'] = 'الگوهای تاریخچه مقاله که دارای خطا هستند',

-- Define boilerplate text for error messages and warnings, both with and
-- without help links.
-- $1 - the error message
-- $2 - a link to a help page and section for the error
['error-message-help'] = 'خطا: $1 ([[$2|راهنما]]).',
['error-message-nohelp'] = 'خطا: $1.',
['warning-help'] = 'هشدار: $1 ([[$2|راهنما]]).',
['warning-nohelp'] = 'هشدار: $1.',

-- Error for row objects that should output notice bar icons but for which no
-- icon values could be found.
['row-error-missing-icon'] = "notice bar icon config set to 'true' but no " ..
	'image could be found',

-- A help link for row-error-missing-icon
['row-error-missing-icon-help'] = 'الگو:تاریخچه مقاله#Missing icon',

-- Error for action objects that aren't passed a code.
-- $1 - the parameter name for the code
['action-error-no-code'] = "no action code found in the '$1' parameter; " ..
	"please add a code or remove other parameters starting with '$1'",

-- A help link for action-error-no-code
['action-error-no-code-help'] = 'الگو:تاریخچه مقاله#Action codes',

-- Error for action objects that are passed an invalid code.
-- $1 - the code that the user input
-- $2 - the parameter name for the code
['action-error-invalid-code'] = "invalid action code '$1' passed to the '$2' parameter",

-- A help link for action-error-invalid-code
['action-error-invalid-code-help'] = 'الگو:تاریخچه مقاله#Action codes',

-- Error for action objects with blank result parameters, where result
-- parameters are required for the action's ID.
-- $1 - the action ID
-- $2 - the result parameter name
['action-error-blank-result'] = "the '$1' action requires a result code; " ..
	"please add a result code to parameter '$2'",

-- A help link for action-error-blank-result
['action-error-blank-result-help'] = 'الگو:تاریخچه مقاله#Action results',

-- Error for action objects with invalid result parameters.
-- $1 - the result code that the user input
-- $2 - the action ID
-- $3 - the result parameter name
['action-error-invalid-result'] = "invalid result '$1' for action '$2' " ..
	"detected in parameter '$3'",

-- A help link for action-error-invalid-result
['action-error-invalid-result-help'] = 'الگو:تاریخچه مقاله#Action results',

-- Warning for action objects with invalid dates.
-- $1 - the date input by the user
-- $2 - the date parameter name
['action-warning-invalid-date'] = "invalid date '$1' detected in parameter '$2'",

-- A help link for action-warning-invalid-date
['action-warning-invalid-date-help'] = 'الگو:تاریخچه مقاله#Invalid date',

-- Error for action objects with no dates.
-- $1 - the parameter number
-- $2 - the date parameter name
-- $3 - the action parameter name
['action-warning-no-date'] = "تاریخی برای action $1 وارد نشده‌است؛ " ..
	"لطفاً یک تاریخ را در پارامتر «$2'» وارد کنید یا پارامترهای دیگر که " ..
	"با «$3» آغاز می‌شوند را حذف کنید",

-- A help link for action-warning-no-date
['action-warning-no-date-help'] = 'الگو:تاریخچه مقاله#No date',

-- The text to display in place of the action date if it is missing.
['action-date-missing'] = '?',

-- Error for action objects with invalid oldids.
-- $1 - the oldid input by the user
-- $2 - the oldid parameter name
['action-warning-invalid-oldid'] = "invalid oldid '$1' detected in parameter '$2'; " ..
	"if an oldid is specified it must be a positive integer",

-- A help link for action-warning-invalid-oldid
['action-warning-invalid-oldid-help'] = 'الگو:تاریخچه مقاله#Invalid oldid',

-- Error for invalid current status codes.
-- $1 - the code input by the user
['articlehistory-warning-invalid-status'] = "'$1' is not a valid status code",

-- A help link for articlehistory-warning-invalid-status
['articlehistory-warning-invalid-status-help'] = 'الگو:تاریخچه مقاله#Invalid status',

-- Warning for invocations that specify a current status without specifying any
-- actions.
['articlehistory-warning-status-no-actions'] = "a current status was supplied " ..
	'without any actions',

-- A help link for articlehistory-warning-status-no-actions
['articlehistory-warning-status-no-actions-help'] = 'الگو:تاریخچه مقاله#No actions',

-- The text to display the current status at the bottom of the collapsible
-- table.
-- $1 - the current status name
['status-blurb'] = "وضعیت کنونی: '''$1'''",

-- The text to display at the bottom of the collapsible table if the current
-- status is unknown.
['status-unknown'] = '؟',

}

-------------------------------------------------------------------------------
--                              CONFIG TABLE END
-------------------------------------------------------------------------------

}