模組解[]
require('strict');
local p = {};

--[[-------------------------< L A N G - X X _ S E T T I N G S >-----------------------------------------------

{{#invoke:Lang/documentor tool|lang_xx_settings|template={{ROOTPAGENAME}}}}

reads the content of the template and extracts the parameters from {{#invoke:Lang|...}} for display on the template's
documentation page

]]

function p.lang_xx_settings (frame)
	local page = mw.title.makeTitle ('Template', frame.args['template'] or frame.args[1]);	-- get a page object for this page in 'Template:' namespace
	if not page then
		return '';																-- TODO: error message?
	end
	
	local content = page:getContent();											-- get unparsed content
	if not page then
		return '';																-- TODO: error message?
	end

	local out = {};
	
	local params;
	local style;

	if content:match ('{{%s*#invoke:%s*[Ll]ang%s*|[^|]+|[^}]+}}') or content:match ('{{%s*#invoke:%s*[Ll]ang/sandbox%s*|[^|]+|[^}]+}}') then			-- if this template uses [[Module:Lang]]
		params = content:match ('{{%s*#invoke:%s*[Ll]ang%s*|[^|]+(|[^}]+)}}') or content:match ('{{%s*#invoke:%s*[Ll]ang/sandbox%s*|[^|]+(|[^}]+)}}')	-- extract the #invoke:'s parameters
		if not params then 
			return '';															-- there should be at least one or the template/module won't work TODO: error message?
		end
		table.insert (out, '{| class="wikitable" style="text-align:right; float:right"\n|+設定')	-- start a wikitable
		for k, v in params:gmatch ('%s*|%s*([^%s=]+)%s*=%s*([^%s|]+)') do		-- get the parameter names (k) and values (v)
			if 'label' == k then												-- special case for labels because spaces and pipes
				v = params:match ('label%s*=%s*(%[%[[^%]]+%]%])') or params:match ('label%s*=%s*([^|\n]+)') or '缺少label';
			end
			table.insert (out, table.concat ({k, '\n|', v}));					-- make rudimentary wikitable entries
		end

		style = content:match ('lang_xx_([^|]+)');
		return table.concat ({table.concat (out,'\n|-\n! scope="row" | '), '\n|-\n|colspan="2"|風格:', style, '\n|-\n|}'});	-- add inter-row markup and close the wikitable and done
	else
		return '';																-- does not use [[Module:Lang]] so abandon quietly
	end
end


--[[-------------------------< U S E S _ M O D U L E >---------------------------------------------------------

{{#invoke:Lang/documentor tool|uses_module|template={{ROOTPAGENAME}}}}

reads the content of the template to determine if this {{lang-xx}} template uses Module:Lang.  Returns the index
of the substring '{{#invoke|lang|' in the template page content if true; empty string if false

Used in template documentation {{#if:}} parser functions.

]]

function p.uses_module (frame)
	local page = mw.title.makeTitle ('Template', frame.args['template'] or frame.args[1]);	-- get a page object for this page in 'Template:' namespace
	if not page then
		return '';																-- TODO: error message?
	end
	
	local content = page:getContent();											-- get unparsed content
	if not page then
		return '';																-- TODO: error message?
	end
	
	return content:find ('{{%s*#invoke:[Ll]ang%s*|') or '';						-- return index or empty string
end

--[[ -------------------------- < S H A R E D _ C O D E > --------------------------

- Tables:
-- language_categories
-- error_messages
-- strings

- Functions:
-- make_error(message, layout, parent_category, nocat)
-- get_language_link(language_name, language_code)
-- get_see_also_section(page_title, language_name, language_code)
-- get_hidden_category_template(frame)
-- get_top_section(frame)
-- get_bottom_section(frame, language_name, see_also_section, parent_category)

]]

local language_categories = {
	["LANGUAGES_SOURCES"] = "有%s來源嘅文章 (%s)",
	["LANGUAGES_COLLECTIVE_SOURCES"] = "Articles with %s-collective sources (%s)",
	["CS1"] = "CS1 %s-language sources (%s)",
	["LANGUAGE_TEXT"] = "Articles containing %s-language text",
	-- old version ["LANGUAGES_COLLECTIVE_TEXT"] = "Articles with text from the %s collective",
	["LANGUAGES_COLLECTIVE_TEXT"] = "Articles with text in %s",
	["ENGLISH"] = "Articles containing explicitly cited %s-language text",
}

local error_assistance = " Please see [[Template talk:Lang]] for assistance."

local error_messages = {
	["ASSISTANCE"] = "Please see [[Template talk:Lang]] for assistance.",
	["INCORRECT_CATEGORY_TITLE"] = "[[:%s]] is not the category being populated by the {{tlx|%s}} template. The correct category is located at: [[:%s]].",
	["NO_CATEGORY_TITLE_FOUND"] = "No language category found for '''%s.'''" .. error_assistance,
	["NOT_VALID_CATEGORY_FORMAT"] = "'''%s''' is not a a valid category title." .. error_assistance,
	["NOT_VALID_LANGUAGE_CODE"] = "[[%s]] is not a valid ISO 639 or IETF language name." .. error_assistance,
}

local strings = {
	["ERROR_CATEGORY"] = "[[Category:Lang and lang-xx template errors]]",
	["ERROR_SPAN"] = '<span style="font-size: 100%%; font-style: normal;" class="error">Error: %s </span>',
	["PURGE_DIV"] = '<div style="font-size: x-small;">%s</div>',
	["SEE_ALSO"] = "\n==See also==",
	["SEE_ALSO_ITEM"] = "* [[:%s]]",
}


--[[ -------------------------- < M A K E _ E R R O R > --------------------------

Create an error message.
Does not place page in error category if args.nocat is used.
Does not categorize in parent cateogory if used in category namespace (usually for /testcases).

]]

local function make_error(message, layout, parent_category, nocat)
	table.insert(layout, string.format(strings["ERROR_SPAN"], message))

	if not nocat then
		table.insert(layout, strings["ERROR_CATEGORY"])
	end

	if mw.title.getCurrentTitle().nsText == "Category" then
		table.insert(layout, parent_category)
	end

	return table.concat(layout)
end


--[[ -------------------------- < G E T _ L A N G U A G E _ L I N K > --------------------------

Generates a language link for the correct style.

Collective languages use the name_from_tag value,
while other languages use a display name of "x-language".

]]

local function get_language_link(language_name, language_code)
	local lang_module = require('Module:Lang')
	-- Is a language collective?
	if language_name:find('languages') then
		return lang_module.name_from_tag({language_code, link = "yes"})
	else
		return lang_module.name_from_tag({language_code, link = "yes", label = lang_module.name_from_tag({language_code})})
	end
end


--[[ -------------------------- < G E T _ S E E _ A L S O _ S E C T I O N > --------------------------

Generates a consistent style See also section for
{{Category articles containing non-English-language text}} and {{Non-English-language source category}}.

If {{CS1 language sources}} is converted, it should also use it.

]]

local function get_see_also_section(page_title, language_name, language_code)
	local see_also_section = {}

	for _, category_name in pairs(language_categories) do
		local category = mw.title.new(string.format(category_name, language_name, language_code), 14)
 		if category and page_title ~= category.text and category.exists then
			table.insert(see_also_section, string.format(strings["SEE_ALSO_ITEM"], category.prefixedText))
		end
	end

	table.sort(see_also_section)
	table.insert(see_also_section, 1, strings["SEE_ALSO"])

	if table.getn(see_also_section) == 1 then
		return ""
	else
		return table.concat(see_also_section, "\n")
	end
end


--[[ -------------------------- < G E T _ H I D D E N _ C A T E G O R Y _ T E M P L A T E > --------------------------

Generates the Template:Hidden category template.

This function is separate from the get_top_section() function
as this should be used in both error categories and valid categories.

]]

local function get_hidden_category_template(frame)
	return frame:expandTemplate{title = 'Hidden category'}
end


--[[ -------------------------- < G E T _ T O P _ S E C T I O N > --------------------------

Generates a consistent top maintenance template section which consists of:
-- Template:Possibly empty category
-- Template:Purge

]]

local function get_top_section(frame)
	local top_section = {}
	if mw.site.stats.pagesInCategory(mw.title.getCurrentTitle().text, "all") == 0 then
		table.insert(top_section, frame:expandTemplate{title = 'Possibly empty category'})
	else
		table.insert(top_section, frame:expandTemplate{title = 'Possibly empty category', args = {hidden=true}})
	end

	local purge_module = require('Module:Purge')
	table.insert(top_section, string.format(strings["PURGE_DIV"], purge_module._main({"清呢版嘅緩衝記憶體"})))

	return table.concat(top_section, "\n\n")
end


--[[ -------------------------- < G E T _ B O T T O M _ S E C T I O N > --------------------------

Generates a consistent non-text section which consists of:
-- Template:CatAutoTOC
-- A see also section
-- {{DEFAULTSORT}}
-- Categorization in parent category

]]

local function get_bottom_section(frame, language_name, see_also_section, parent_category)
	local bottom_section = {}
	table.insert(bottom_section, frame:expandTemplate{title = 'CatAutoTOC'})
	table.insert(bottom_section, see_also_section)

	if mw.title.getCurrentTitle().nsText == "Category" then
		table.insert(bottom_section, frame:preprocess{text = "{{DEFAULTSORT:" .. language_name .. "}}"})
		table.insert(bottom_section, parent_category)
	end

	return table.concat(bottom_section, "\n\n\n")
end


--[[ -------------------------- < N O N _ C A N T O N E S E _ L A N G U A G E _ S O U R C E S _ C A T E G O R Y > --------------------------

{{#invoke:Lang/documentor tool|non_cantonese_language_sources_category}}

This function implements {{非粵文來源類}}.

]]

local non_cantonese_language_sources_strings = {
	["LINE1"] = "呢個類係愛嚟追蹤用%s辨認%s來源嘅文章。",
	["PARENT_CATEGORY"] = "[[Category:有非粵文來源嘅文章]]",
	["TEMPLATE"] = "In lang",
}

function p.non_cantonese_language_sources_category(frame)
	local page = mw.title.getCurrentTitle()
	local args = require('Module:Arguments').getArgs(frame)
	-- args.test is used for /testcases
	if args.test then
		page = mw.title.new(args.test)
	end

	local page_title = page.text
	local language_code = page_title:match('%(([%a%-]+)%)')
	local language_name = require('Module:Lang')._name_from_tag({language_code})

	local layout = {}
	table.insert(layout, get_hidden_category_template(frame))
	local parent_category = non_cantonese_language_sources_strings["PARENT_CATEGORY"]

	local correct_language_category_title = require('Module:In lang')._in_lang({language_code, ["list-cats"]="yes"})
	if correct_language_category_title == "" then
		-- Error: No category title found for language code.
		return make_error(string.format(error_messages["NO_CATEGORY_TITLE_FOUND"], language_code), layout, parent_category, args.nocat)
	end

	local current_category_title = page.prefixedText
	if correct_language_category_title ~= current_category_title then
		-- Error: The current title used is not in the supported format.
		return make_error(
			string.format(error_messages["INCORRECT_CATEGORY_TITLE"], current_category_title, non_cantonese_language_sources_strings["TEMPLATE"], correct_language_category_title),
			layout, parent_category, args.nocat)
	end

	local language_link = get_language_link(language_name, language_code)
	local text = string.format(non_cantonese_language_sources_strings["LINE1"], frame:expandTemplate{title = 'Tlx', args = {non_cantonese_language_sources_strings["TEMPLATE"], language_code}}, language_link)

	table.insert(layout, get_top_section(frame))	
	table.insert(layout, text)
	local see_also_section = get_see_also_section(page_title, language_name, language_code)

	local bottom = get_bottom_section(frame, language_name, see_also_section, parent_category)
	return table.concat(layout, "\n\n") .. bottom
end


return p;