Bước tới nội dung

Mô đun:documentation2

Từ điển mở Wiktionary

Serves {{Tài liệu 2}} and {{Tài liệu mô đun chuyển tự}}. {{Tài liệu 2}} is added to modules automatically (through MediaWiki:Scribunto-doc-page-show if the doc page exists, otherwise through MediaWiki:Scribunto-doc-page-does-not-exist); added to user JavaScript pages automatically (through MediaWiki:Clearyourcache); and manually added to template pages. It automatically adds categories, or categories and documentation, to some modules based on their titles.

More specifically, for modules:

  1. When there is no doc page for the module, Module:documentation2 checks for various sorts of special modules (based on the module title) and autogenerates the documentation and categories of those modules. If this check fails, the module is added to Thể loại:Bản mẫu và mô đun chưa có tài liệu, and Module:module categorization is called to autogenerate the categories for lang-specific modules of the form LANGCODE-TYPE, optionally with a subpage (e.g. LANGCODE-TYPE/data, LANGCODE-TYPE/testcases, LANGCODE-TYPE/data/testcases, or any other subpage). If this check also fails, the module is added to Thể loại:Mô đun chưa phân loại.
  2. When there is a doc page for the module, the contents of that page take precedence over any autogenerated content. However, if that page does not have an <includeonly>...</includeonly> section and does not have an invocation of {{module cat}}, the same checks are done as when no doc page exists (including checks for specially-titled modules and falling back to calling Module:module categorization), but only for the purposes of autogenerating categories. If no such categories could be determined, the module is added to Thể loại:Mô đun chưa phân loại.

More specifically, for templates:

  • ... (DOCUMENT ME)

Ideas:

  • Make more usable on other Wiktionaries by creating data module with translations of text, and moving module regex to separate module.

Automatic module documentation generators

Regex Thể loại Mô đun xử lý
^Module:languages/data/(3/%l/extra)$ (không được chỉ định) (xử lý nội bộ)
^Module:languages/data/(3/%l)$ (không được chỉ định) (xử lý nội bộ)
^Module:languages/data/(2/extra)$ (không được chỉ định) (xử lý nội bộ)
^Module:languages/data/(2)$ (không được chỉ định) (xử lý nội bộ)
^Module:languages/data/(exceptional/extra)$ (không được chỉ định) (xử lý nội bộ)
^Module:languages/data/(exceptional)$ (không được chỉ định) (xử lý nội bộ)
^Mô đun:languages/.+$ Mô đun ngôn ngữ và chữ viết (không có trình tạo tài liệu)
^Mô đun:scripts/.+$ Mô đun ngôn ngữ và chữ viết (không có trình tạo tài liệu)
^Mô đun:data tables/data..?.?.?$ Mô đun dữ liệu bảng tham chiếu phân mảnh (không có trình tạo tài liệu)
^Module:zh/data/dial%-pron/.+$ Mô đun dữ liệu phát âm phương ngữ tiếng Trung Quốc Module:documentation2/functions/zh dial or syn
^Module:zh/data/dial%-syn/.+$ Mô đun dữ liệu từ đồng nghĩa phương ngữ tiếng Trung Quốc Module:documentation2/functions/zh dial or syn
^Mô đun:zh/data/glyph%-data/.+$ Mô đun dữ liệu biểu mẫu ký tự lịch sử tiếng Trung Quốc (xử lý nội bộ)
^Module:zh/data/ltc%-pron/(.+)$ Mô đun dữ liệu phát âm tiếng Trung Quốc trung đại|%1 Module:documentation2/functions/zh data
^Module:zh/data/och%-pron%-BS/(.+)$ Mô đun dữ liệu phát âm tiếng Trung Quốc cổ (Baxter-Sagart)|%1 Module:documentation2/functions/zh data
^Module:zh/data/och%-pron%-ZS/(.+)$ Mô đun dữ liệu phát âm tiếng Trung Quốc cổ (Trịnh Chương)|%1 Module:documentation2/functions/zh data
^Mô đun:zh/data/(.+)$ Mô đun dữ liệu tiếng Trung Quốc|%1 (không có trình tạo tài liệu)
^Module:mul/guoxue%-data/cjk%-?(.*)$ (không được chỉ định) Module:documentation2/functions/guoxue-data
^Module:Unicode data/(.+)$ Mô đun dữ liệu Unicode|%1 (xử lý nội bộ)
^Mô đun:number list/data/(.+)$ (không được chỉ định) (xử lý nội bộ)
^Mô đun:accel/(.+)$ (không được chỉ định) (xử lý nội bộ)
^Mô đun:inc%-ash/dial/data/(.+)$ Mô đun Ashokan Prakrit|%1 (xử lý nội bộ)
^.+%-translit$ (không được chỉ định) Module:documentation2/functions/translit
^Mô đun:form of/lang%-data/(.+)$ (không được chỉ định) (xử lý nội bộ)
^Module:labels/data/lang/(.+)$ (không được chỉ định) (xử lý nội bộ)
^Mô đun:category tree/lang/(.+)$ (không được chỉ định) (xử lý nội bộ)
^Module:category tree/topic/(.+)$ (không được chỉ định) (xử lý nội bộ)
^Module:category tree/(.+)$ (không được chỉ định) (xử lý nội bộ)
^Mô đun:ja/data/(.+)$ Mô đun dữ liệu tiếng Nhật|%1 (không có trình tạo tài liệu)
^Mô đun:fi%-dialects/data/feature/Kettunen1940 ([0-9]+)$ Mô đun atlas dữ liệu phương ngữ tiếng Phần Lan|%1 (xử lý nội bộ)
^Mô đun:fi%-dialects/data/feature/(.+) Mô đun dữ liệu phương ngữ tiếng Phần Lan|%1 (không có trình tạo tài liệu)
^Mô đun:fi%-dialects/data/word/(.+) Mô đun dữ liệu phương ngữ tiếng Phần Lan|%1 (không có trình tạo tài liệu)
^Mô đun:Swadesh/data/([%l-]+)$ (không được chỉ định) (xử lý nội bộ)
^Mô đun:Swadesh/data/([%l-]+)/([^/]*)$ (không được chỉ định) (xử lý nội bộ)
^Mô đun:typing%-aids (không được chỉ định) (xử lý nội bộ)
^Mô đun:R:([%l-]+):(.+)$ (không được chỉ định) (xử lý nội bộ)
^Module:Quotations/([%l-]+)/?(.*) (không được chỉ định) Module:documentation2/functions/Quotation
^Module:affix/lang%-data/([%l-]+) (không được chỉ định) Module:documentation2/functions/affix lang-data
^Module:dialect synonyms/([%l-]+)$ (không được chỉ định) (xử lý nội bộ)
^Mô đun:dialect synonyms/([%l-]+)/(.+)$ (không được chỉ định) (xử lý nội bộ)
^Mô đun:bibliography/data/([%l-]+)$ (không được chỉ định) (xử lý nội bộ)
local export = {}

local array_module = "Module:array"
local debug_track_module = "Module:debug/track"
local frame_module = "Module:frame"
local fun_is_callable_module = "Module:fun/isCallable"
local languages_module = "Module:languages"
local links_module = "Module:links"
local load_module = "Module:load"
local module_categorization_module = "Module:module categorization"
local number_list_show_module = "Module:number list/show"
local pages_module = "Module:pages"
local parameters_module = "Module:parameters"
local scripts_module = "Module:scripts"
local string_endswith_module = "Module:string/endswith"
local string_gline_module = "Module:string/gline"
local string_insert_module = "Module:string/insert"
local string_startswith_module = "Module:string/startswith"
local string_utilities_module = "Module:string utilities"
local template_parser_module = "Module:template parser"
local title_exists_module = "Module:title/exists"
local title_new_title_module = "Module:title/newTitle"

local concat = table.concat
local error = error
local full_url = mw.uri.fullUrl
local get_current_title = mw.title.getCurrentTitle
local insert = table.insert
local ipairs = ipairs
local list_to_text = mw.text.listToText
local new_message = mw.message.new
local pcall = pcall
local require = require
local tonumber = tonumber
local tostring = tostring
local type = type
local unpack = unpack or table.unpack -- Lua 5.2 compatibility

local function Array(...)
	Array = require(array_module)
	return Array(...)
end

local function categorize_module(...)
	categorize_module = require(module_categorization_module).categorize
	return categorize_module(...)
end

local function debug_track(...)
	debug_track = require(debug_track_module)
	return debug_track(...)
end

local function endswith(...)
	endswith = require(string_endswith_module)
	return endswith(...)
end

local function expand_template(...)
	expand_template = require(frame_module).expandTemplate
	return expand_template(...)
end

local function find_templates(...)
	find_templates = require(template_parser_module).find_templates
	return find_templates(...)
end

local function full_link(...)
	full_link = require(links_module).full_link
	return full_link(...)
end

local function get_lang(...)
	get_lang = require(languages_module).getByCode
	return get_lang(...)
end

local function get_pagetype(...)
	get_pagetype = require(pages_module).get_pagetype
	return get_pagetype(...)
end

local function get_script(...)
	get_script = require(scripts_module).getByCode
	return get_script(...)
end

local function gline(...)
	gline = require(string_gline_module)
	return gline(...)
end

local function is_callable(...)
	is_callable = require(fun_is_callable_module)
	return is_callable(...)
end

local function is_documentation(...)
	is_documentation = require(pages_module).is_documentation
	return is_documentation(...)
end

local function is_sandbox(...)
	is_sandbox = require(pages_module).is_sandbox
	return is_sandbox(...)
end

local function new_title(...)
	new_title = require(title_new_title_module)
	return new_title(...)
end

local function number_list_show_table(...)
	number_list_show_table = require(number_list_show_module).table
	return number_list_show_table(...)
end

local function preprocess(...)
	preprocess = require(frame_module).preprocess
	return preprocess(...)
end

local function process_params(...)
	process_params = require(parameters_module).process
	return process_params(...)
end

local function safe_load_data(...)
	safe_load_data = require(load_module).safe_load_data
	return safe_load_data(...)
end

local function split(...)
	split = require(string_utilities_module).split
	return split(...)
end

local function startswith(...)
	startswith = require(string_startswith_module)
	return startswith(...)
end

local function string_insert(...)
	string_insert = require(string_insert_module)
	return string_insert(...)
end

local function title_exists(...)
	title_exists = require(title_exists_module)
	return title_exists(...)
end

local function ugsub(...)
	ugsub = require(string_utilities_module).gsub
	return ugsub(...)
end

local function umatch(...)
	umatch = require(string_utilities_module).match
	return umatch(...)
end

local skins = {
	["common"     ] = "";
	["vector"     ] = "Vector";
	["monobook"   ] = "Monobook";
	["cologneblue"] = "Cologne Blue";
	["modern"     ] = "Modern";
}

local function track(page)
	debug_track("documentation/" .. page)
	return true
end

local function compare_pages(page1, page2, text)
	return "[" .. tostring(
		full_url("Special:ComparePages", {page1 = page1, page2 = page2}))
		.. " " .. text .. "]"
end

-- Avoid transcluding [[Module:languages/cache]] everywhere.
local lang_cache = setmetatable({}, { __index = function (self, k)
	return require("Module:languages/cache")[k]
end })

local function zh_link(word)
	return full_link{
		lang = lang_cache.zh,
		term = word
	}
end

local function make_languages_data_documentation(title, cats, division)
	local doc_template, module_cat
	if endswith(division, "/extra") then
		division = division:sub(1, -7)
		doc_template = "language extradata documentation"
		module_cat = "Mô đun dữ liệu ngôn ngữ bổ sung"
	else
		doc_template = "language data documentation"
		module_cat = "Mô đun dữ liệu ngôn ngữ"
	end
	local sort_key
	if division == "exceptional" then
		sort_key = "x"
	else
		sort_key = division:gsub("/", "")
	end
	cats:insert(module_cat .. "|" .. sort_key)
	return {
		title = doc_template
	}
end

local function make_Unicode_data_documentation(title, cats)
	local subpage, first_three_of_code_point
		= title.fullText:match("^Module:Unicode data/([^/]+)/(%x%x%x)$")
	if subpage == "names" or subpage == "images" or subpage == "emoji images" then
		local low, high =
			tonumber(first_three_of_code_point .. "000", 16),
			tonumber(first_three_of_code_point .. "FFF", 16)
		local text, text_type
		if subpage == "names" then
			text_type = "dữ liệu hình ảnh"
		elseif subpage == "images" then
			text_type = "dữ liệu hình ảnh"
		elseif subpage == "emoji images" then
			text_type = "hình ảnh theo phong cách emoji"
		end
		text = string.format(
			"Mô đun dữ liệu này chứa " .. text_type .. " của " ..
			"các điểm mã [[Phụ lục:Unicode|Unicode]] trong phạm vi từ U+%04X đến U+%04X.",
			low, high)
		if subpage == "images" and safe_load_data("Module:Unicode data/emoji images/" .. first_three_of_code_point) then
			text = text .. " Danh sách này bao gồm các biến thể văn bản của emoji. Để biết danh sách các biến thể biểu tượng cảm xúc của những emoji đó, xem [[Module:Unicode data/emoji images/" .. first_three_of_code_point .. "]]."
		elseif subpage == "emoji images" then
			text = text .. " Đối với hình ảnh theo phong cách văn bản, xem [[Module:Unicode data/images/" .. first_three_of_code_point .. "]]."
		end
		return text
	end
end

local function insert_lang_data_module_cats(cats, langcode, overall_data_module_cat)
	local lang = lang_cache[langcode]
	if lang then
		local langname
		if lang._fullCode then
			langname = lang_cache[lang._fullCode]:getCanonicalName()
		else
			langname = lang:getCanonicalName()
		end
		cats:insert(overall_data_module_cat .. "|" .. langname)
		cats:insert("Mô đun " .. langname)
		cats:insert("Mô đun dữ liệu " ..langname)
		return lang, langname
	end
end

--[=[
This provides categories and documentation for various data modules, so that [[Category:Uncategorized modules]] isn't
unnecessarily cluttered. It is a list of tables, each of which have the following possible fields:

`regex` (required): A Lua pattern to match the module's title. If it matches, the data in this entry will be used.
	Any captures in the pattern can by referenced in the `cat` field using %1 for the first capture, %2 for the
	second, etc. (often used for creating the sortkey for the category). In addition, the captures are passed to the
	`process` function as the third and subsequent parameters.

`process` (optional): This may be a function or a string. If it is a function, it is called as follows:
	   `process(TITLE, CATS, CAPTURE1, CAPTURE2, ...)`
	where:
	   * TITLE is a title object describing the module's title; see
	     [https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Title_objects].
	   * CATS is an array object (see [[Module:array]]) of categories that the module will be added to.
	   * CAPTURE1, CAPTURE2, ... contain any captures in the `regex` field.
	The return value of `process` should either be a string (which will be used as the module's documentation), or a
	table specifying the name of a template to expand to get the documentation, along with the arguments to that
	template. In the latter format, the template name (bare, without the "Template:" prefix) should be in the `title`
	field, and any arguments should be in `args; in this case, the template name will be listed above the generated
	documentation as the source of the documentation, along with an edit button to edit the template's contents.
	If, however, the return value of the `process` function is a string, any template invocations will be expanded
	using frame:preprocess(), and [[Module:documentation]] will be listed as the source of the documentation.

	If `process` itself is a string rather than a function, it should name a submodule under
	[[Module:documentation/functions/]] which returns a function, of the same type as described above. This submodule
	will be specified as the source of the documentation (unless it returns a table naming a template to expand to get
	the documentation, as described above).

	If `process` is omitted entirely, the module will have no documentation.

`cat` (optional): A string naming the category into which the module should be placed, or a list of such strings.
	Captures specified in `regex` may be referenced in this string using %1 for the first capture, %2 for the second,
	etc. It is also possible to add categories in the `process` function by inserting them into the passed-in CATS
	array (the second parameter).
]=]

local module_regex = {
	{
		regex = "^Module:languages/data/(3/%l/extra)$",
		process = make_languages_data_documentation,
	},
	{
		regex = "^Module:languages/data/(3/%l)$",
		process = make_languages_data_documentation,
	},
	{
		regex = "^Module:languages/data/(2/extra)$",
		process = make_languages_data_documentation,
	},
	{
		regex = "^Module:languages/data/(2)$",
		process = make_languages_data_documentation,
	},
	{
		regex = "^Module:languages/data/(exceptional/extra)$",
		process = make_languages_data_documentation,
	},
	{
		regex = "^Module:languages/data/(exceptional)$",
		process = make_languages_data_documentation,
	},
	{
		regex = "^Mô đun:languages/.+$",
		cat = "Mô đun ngôn ngữ và chữ viết",
	},
	{
		regex = "^Mô đun:scripts/.+$",
		cat = "Mô đun ngôn ngữ và chữ viết",
	},
	{
		regex = "^Mô đun:data tables/data..?.?.?$",
		cat = "Mô đun dữ liệu bảng tham chiếu phân mảnh",
	},
	{
		regex = "^Module:zh/data/dial%-pron/.+$",
		cat = "Mô đun dữ liệu phát âm phương ngữ tiếng Trung Quốc",
		process = "zh dial or syn",
	},
	{
		regex = "^Module:zh/data/dial%-syn/.+$",
		cat = "Mô đun dữ liệu từ đồng nghĩa phương ngữ tiếng Trung Quốc",
		process = "zh dial or syn",
	},
	{
		regex = "^Mô đun:zh/data/glyph%-data/.+$",
		cat = "Mô đun dữ liệu biểu mẫu ký tự lịch sử tiếng Trung Quốc",
		process = function(title, cats)
			local character = title.fullText:match("^Module:zh/data/glyph%-data/(.+)")
			if character then
				return ("Mô đun này chứa dữ liệu về các hình thức lịch sử của chữ Hán %s.")
					:format(zh_link(character))
			end
		end,
	},
	{
		regex = "^Module:zh/data/ltc%-pron/(.+)$",
		cat = "Mô đun dữ liệu phát âm tiếng Trung Quốc trung đại|%1",
		process = "zh data",
	},
	{
		regex = "^Module:zh/data/och%-pron%-BS/(.+)$",
		cat = "Mô đun dữ liệu phát âm tiếng Trung Quốc cổ (Baxter-Sagart)|%1",
		process = "zh data",
	},
	{
		regex = "^Module:zh/data/och%-pron%-ZS/(.+)$",
		cat = "Mô đun dữ liệu phát âm tiếng Trung Quốc cổ (Trịnh Chương)|%1",
		process = "zh data",
	},
	{
		-- capture rest of zh/data submodules
		regex = "^Mô đun:zh/data/(.+)$",
		cat = "Mô đun dữ liệu tiếng Trung Quốc|%1",
	},
	{
		regex = "^Module:mul/guoxue%-data/cjk%-?(.*)$",
		process = "guoxue-data",
	},
	{
		regex = "^Module:Unicode data/(.+)$",
		cat = "Mô đun dữ liệu Unicode|%1",
		process = make_Unicode_data_documentation,
	},
	{
		regex = "^Mô đun:number list/data/(.+)$",
		process = function(title, cats, lang_code)
			local lang = insert_lang_data_module_cats(cats, lang_code, "Mô đun dữ liệu số")
			if lang then
				return ("Mô đun này chứa dữ liệu về nhiều loại số khác nhau trong %s.\n%s")
					:format(lang:makeCategoryLink(), number_list_show_table() or "")
			end
		end,
	},
	{
		regex = "^Mô đun:accel/(.+)$",
		process = function(title, cats)
			local lang_code = title.subpageText
			local lang = lang_cache[lang_code]
			if lang then
				cats:insert("Mô đun " .. lang:getCanonicalName() .. "|accel")
				cats:insert(("Mô đun con Accel|%s"):format(lang:getCanonicalName()))
				return ("Mô đun này chứa các quy tắc tạo mục từ mới cho %s; xem [[WT:ACCEL]] để có cái nhìn tổng quan và [[Module:accel]] để biết thông tin về việc tạo các quy tắc mới.")
					:format(lang:makeCategoryLink())
			end
		end,
	},
	{
		regex = "^Mô đun:inc%-ash/dial/data/(.+)$",
		cat = "Mô đun Ashokan Prakrit|%1",
		process = function(title, cats)
			local word = title.fullText:match("^Module:inc%-ash/dial/data/(.+)$")
			if word then
				local lang = lang_cache["inc-ash"]
				return ("Mô đun này chứa dữ liệu về cách phát âm của %s trong các phương ngữ của %s.")
					:format(full_link({ term = word, lang = lang }, "term"),
						lang:makeCategoryLink())
			end
		end,
	},
	{
		regex = "^.+%-translit$",
		process = "translit",
	},
	{
		regex = "^Mô đun:form of/lang%-data/(.+)$",
		process = function(title, cats, lang_code)
			local lang, langname = insert_lang_data_module_cats(cats, lang_code, "Mô đun dạng từ theo ngôn ngữ cụ thể")
			if lang then
				-- FIXME, display more info.
				return "Mô đun này chứa dữ liệu dạng ngôn ngữ cụ thể (thẻ, phím tắt, tham số lemma cơ sở, v.v.) cho " ..
					langname .. "."
			end
		end
	},
	{
		regex = "^Module:labels/data/lang/(.+)$",
		process = function(title, cats, lang_code)
			local lang = insert_lang_data_module_cats(cats, lang_code, "Mô-đun dữ liệu nhãn theo ngôn ngữ cụ thể")
			if lang then
				return {
					title = "label language-specific data documentation",
					args = { [1] = lang_code },
				}
			end
		end
	},
	{
		regex = "^Mô đun:category tree/lang/(.+)$",
		process = function(title, cats, lang_code)
			local lang, langname = insert_lang_data_module_cats(cats, lang_code, "Mô đun dữ liệu cây thể loại/lang")
			if lang then
				return "Mô đun này xử lý việc tạo ra các mô tả và phân loại cho các trang thể loại " .. langname .. " theo "
					.. "định dạng \"LABEL " .. langname .. "\" trong đó LABEL có thể là bất kỳ văn bản nào. Ví dụ là "
					.. "[[:Thể loại:Chia động từ 2.1 tiếng Bulgaria]] và [[:Thể loại:Danh từ trung tính gốc vòm mềm tiếng Nga]]. "
					.. "Mô đun này là một phần của hệ thống cây thể loại, là một khuôn khổ chung để tạo ra "
					.. "mô tả và phân loại các trang thể loại.\n\n"
					.. "Để biết thêm thông tin, hãy xem [[Module:category tree/lang/tài liệu]].\n\n"
					.. "'''LƯU Ý:''' Nếu bạn thêm một mô đun ngôn ngữ cụ thể mới, bạn phải thêm mã ngôn ngữ vào "
					.. "danh sách ở đầu [[Module:category tree/lang]] để mô đun được nhận dạng."
			end
		end
	},
	{
		regex = "^Module:category tree/topic/(.+)$",
		process = function(title, cats, submodule)
			cats:insert("Mô đun dữ liệu cây thể loại/topic| ")
			return {
				title = "topic cat data submodule documentation"
			}
		end
	},
	{
		regex = "^Module:category tree/(.+)$",
		process = function(title, cats, submodule)
			cats:insert("Mô đun dữ liệu cây thể loại| ")
			return {
				title = "category tree data submodule documentation"
			}
		end
	},
	{
		regex = "^Mô đun:ja/data/(.+)$",
		cat = "Mô đun dữ liệu tiếng Nhật|%1",
	},
	{
		regex = "^Mô đun:fi%-dialects/data/feature/Kettunen1940 ([0-9]+)$",
		cat = "Mô đun atlas dữ liệu phương ngữ tiếng Phần Lan|%1",
		process = function(title, cats, shard)
			return "Mô-đun này chứa phân đoạn " .. shard .. " của phiên bản trực tuyến tác phẩm năm 1940 của Lauri Kettunen " ..
				"''Suomen murteet III A. Murrekartasto'' (\"Finnish dialects III A: Dialect atlas\"). " ..
				"Nó đã được nhập và chuyển đổi từ urn:nbn:fi:csc-kata20151130145346403821, được xuất bản bởi " ..
				"''Kotimaisten kielten keskus'' theo giấy phép CC BY 4.0."
		end
	},
	{
		regex = "^Mô đun:fi%-dialects/data/feature/(.+)",
		cat = "Mô đun dữ liệu phương ngữ tiếng Phần Lan|%1",
	},
	{
		regex = "^Mô đun:fi%-dialects/data/word/(.+)",
		cat = "Mô đun dữ liệu phương ngữ tiếng Phần Lan|%1",
	},
	{
		regex = "^Mô đun:Swadesh/data/([%l-]+)$",
		process = function(title, cats, lang_code)
			local lang, langname = insert_lang_data_module_cats(cats, lang_code, "Mô đun Swadesh")
			if lang then
				return "Mô đun này chứa [[danh sách Swadesh]] có các từ vựng cơ bản trong " .. langname .. "."
			end
		end
	},
	{
		regex = "^Mô đun:Swadesh/data/([%l-]+)/([^/]*)$",
		process = function(title, cats, lang_code, variety)
			local lang, langname = insert_lang_data_module_cats(cats, lang_code, "Mô đun Swadesh")
			if lang then
				local prefix = "Mô đun này chứa [[danh sách Swadesh]] có các từ vựng cơ bản trong "
				local etym_lang = get_lang(variety, nil, "allow etym")
				if etym_lang then
					return ("%s %s các kiểu khác nhau của %s."):format(prefix, etym_lang:getCanonicalName(), langname)
				end
				local script = get_script(variety)
				if script then
					return ("chữ viết %s %s %s."):format(prefix, langname, script:getCanonicalName())
				end
				return ("%s %s các kiểu khác nhau của %s."):format(prefix, variety, langname)
			end
		end
	},
	{
		regex = "^Mô đun:typing%-aids",
		process = function(title, cats)
			local data_suffix = title.fullText:match("^Module:typing%-aids/data/(.+)$")
			local sortkey
			if data_suffix then
				if data_suffix:find "^[%l-]+$" then
					local lang = get_lang(data_suffix)
					if lang then
						sortkey = lang:getCanonicalName()
						cats:insert("Mô đun dữ liệu " .. sortkey)
					end
				elseif data_suffix:find "^%u%l%l%l$" then
					local script = get_script(data_suffix)
					if script then
						sortkey = script:getCanonicalName()
						cats:insert(script:getCategoryName())
					end
				end
				cats:insert("Mô-đun dữ liệu chèn ký tự|" .. (sortkey or data_suffix))
			end
		end,
	},
	{
		regex = "^Mô đun:R:([%l-]+):(.+)$",
		process = function(title, cats, lang_code, refname)
			local lang = lang_cache[lang_code]
			if lang then
				cats:insert("Mô đun " .. lang:getCanonicalName() .. "|" .. refname)
				cats:insert(("Mô đun tham khảo|%s"):format(lang:getCanonicalName()))
				return "Mô đun này triển khai bản mẫu tham khảo {{temp|R:" ..	lang_code .. ":" .. refname .. "}}."
			end
		end,
	},
	{
		regex = "^Module:Quotations/([%l-]+)/?(.*)",
		process = "Quotation",
	},
	{
		regex = "^Module:affix/lang%-data/([%l-]+)",
		process = "affix lang-data",
	},
	{
		regex = "^Module:dialect synonyms/([%l-]+)$",
		process = function(title, cats, lang_code)
			local lang = lang_cache[lang_code]
			if lang then
				local langname = lang:getCanonicalName()
				cats:insert("Mô đun dữ liệu từ phương ngữ đồng nghĩa|" .. langname)
				cats:insert("Mô đun dữ liệu từ phương ngữ đồng nghĩa " .. langname .. "| ")
				return "Mô đun này chứa dữ liệu về các dạng cụ thể của " .. langname .. ", được sử dụng bởi " ..
					"{{tl|dialect synonyms}}. Các từ đồng nghĩa thực tế được chứa trong các mô đun con.\n\n" ..
					expand_template({ title = 'dial syn', args = { lang_code, ["demo mode"] = "y" } })
			end
		end,
	},
	{
		regex = "^Mô đun:dialect synonyms/([%l-]+)/(.+)$",
		process = function(title, cats, lang_code, term)
			local lang = lang_cache[lang_code]
			if lang then
				local langname = lang:getCanonicalName()
				cats:insert("Mô đun dữ liệu từ phương ngữ đồng nghĩa|" .. langname)
				cats:insert("Mô đun dữ liệu từ phương ngữ đồng nghĩa " .. langname .. "|" .. term)
				return ("Mô đun này chứa các từ phương ngữ đồng nghĩa %s cho {{mention|%s|%s}}.\n\n%s"):format(langname, lang_code, term, expand_template({ title = 'dial syn', args = { lang_code, term } }))
			end
		end,
	},
	{
		regex = "^Mô đun:bibliography/data/([%l-]+)$",
		process = function(title, cats, lang_code)
			if lang_code == "preload" then
				return 'Được sử dụng làm mô hình cơ sở cho các ngôn ngữ khác khi nhấn vào nút "tạo mô đun con ngôn ngữ mới".'
			end
			local page = require(title.fullText).bib_page
			if not page then
				page = lang_cache[lang_code]:getCanonicalName()
				if page then
					cats:insert("Mô đun " ..page)
				end
			end
			cats:insert("Mô đun tham khảo")
			return "Mô-đun này chứa dữ liệu thư mục cho "..page..". Đối với thư mục được định dạng, xem '''[[Appendix:Bibliography/"..page.."]]'''."
		end,
	},
}

function export.show(frame)
	local boolean_default_false = {type = "boolean", default = false}
	local args = process_params(frame.args, {
		["hr"] = true,
		["for"] = true,
		["from"] = true,
		["allowondoc"] = boolean_default_false, -- Don't throw an error if used on a documentation subpage.
		["notsubpage"] = boolean_default_false,
		["nodoc"] = boolean_default_false,
		["nolinks"] = boolean_default_false, -- suppress all "Useful links"
		["nosandbox"] = boolean_default_false, -- supress sandbox
	})
	
	local output = Array('\n<div class="documentation" style="display:block; clear:both">\n')
	local cats = Array()
	
	local nodoc = args.nodoc
	
	local title = args["for"] and new_title(args["for"]) or get_current_title()
	local doc_title = args.from ~= "-" and new_title(args.from or title.fullText .. '/tài liệu') or nil
	local contentModel = title.contentModel
	local pagetype, is_script_or_stylesheet = get_pagetype(title)
	local preload, fallback_docs, doc_content, old_doc_title, user_name, skin_name, needs_doc
	local doc_content_source = "Module:documentation2"
	local auto_generated_cat_source
	local cats_auto_generated = false
	
	if not args.allowondoc and is_documentation(title) then
		-- TODO: merge with {{documentation subpage}}, and choose behaviour based on the page type.
		error("Bản mẫu này không nên được sử dụng trên trang tài liệu. Vui lòng sử dụng [[Bản mẫu:documentation subpage]].")
	elseif is_sandbox(title) then
		local sandbox_ns = title.nsText
		preload = ("Template:Tài liệu 2/preload%s%sSandbox"):format(
			sandbox_ns == "Mô_đun" and sandbox_ns or "Bản_mẫu",
			title.rootText:match("^[Tt]hành viên:(.+)") and "Thành viên" or ""
		)
	elseif pagetype:match("%f[%w]gadget%f[%W]") then
		preload = "Template:Tài liệu 2/preloadGadget"
	elseif pagetype:match("%f[%w]script%f[%W]") then -- .js
		if title.nsText == "MediaWiki" then
			preload = "Template:Tài liệu 2/preloadMediaWikiJavaScript"
		else
			preload  = "Template:Tài liệu/preload" -- XXX
			if title.nsText == "Thành_viên" then
				user_name = title.rootText
			end
		end
		is_script_or_stylesheet = true
	elseif pagetype:match("%f[%w]stylesheet%f[%W]") then -- .css
		preload  = "Template:Tài liệu/preload" -- XXX
		if title.nsText == "Thành_viên" then
			user_name = title.rootText
		end
		is_script_or_stylesheet = true
	elseif contentModel == "Scribunto" then -- Exclude pages in Module: which aren't Scribunto.
		preload  = "Template:Tài liệu 2/preloadModule"
	elseif pagetype:match("%f[%w]bản_mẫu%f[%W]") or pagetype:match("%f[%w]project%f[%W]") then
		preload  = "Template:Tài liệu/preload"
	end

	if doc_title and doc_title.isRedirect then
		old_doc_title = doc_title
		doc_title = doc_title.redirectTarget
	end

	output:insert("<dl class=\"plainlinks\" style=\"font-size: smaller;\">")

	local function get_module_doc_and_cats(categories_only)
		cats_auto_generated = true
		local automatic_cats = nil
		if user_name then
			fallback_docs = "documentation/fallback/user module"
			automatic_cats = {"Mô đun chỗ thử thành viên"}
		else
			for _, data in ipairs(module_regex) do
				local captures = {umatch(title.fullText, data.regex)}
				if #captures > 0 then
					local cat, process_function
					if is_callable(data.process) then
						process_function = data.process
					elseif type(data.process) == "string" then
						doc_content_source = "Module:documentation2/functions/" .. data.process
						process_function = require(doc_content_source)
					end

					if process_function then
						doc_content = process_function(title, cats, unpack(captures))
					end
					if type(doc_content) == "table" then
						doc_content_source = doc_content.title and "Bản_mẫu:" .. doc_content.title or doc_content_source
						doc_content = expand_template(doc_content)
					elseif doc_content ~= nil then
						doc_content = preprocess(doc_content)
					end
					cat = data.cat
					
					if cat then
						if type(cat) == "string" then
							cat = {cat}
						end
						for _, c in ipairs(cat) do
							insert(cats, (ugsub(title.fullText, data.regex, c)))
						end
					end
					break
				end
			end
		end

		if title.subpageText == "templates" then
			cats:insert("Mô đun giao diện bản mẫu")
		end

		if automatic_cats then
			for _, c in ipairs(automatic_cats) do
				cats:insert(c)
			end
		end
		
		if #cats == 0 then
			local auto_cats = categorize_module(frame, "return raw", "noerror")
			if #auto_cats > 0 then
				auto_generated_cat_source = "Module:module categorization"
			end
			for _, category in ipairs(auto_cats) do
				cats:insert(category)
			end
		end

		-- meaning module is not in user’s sandbox or one of many datamodule boring series
		needs_doc = not categories_only and not (automatic_cats or doc_content or fallback_docs)
	end

	-- Override automatic documentation, if present.
	if doc_title and doc_title.exists then
		local cats_auto_generated_text = ""
		if contentModel == "Scribunto" then
			local doc_page_content = doc_title.content
			-- Track then do nothing if there are uses of includeonly. The
			-- pattern is slightly too permissive, but any false-positives are
			-- obvious typos that should be corrected.
			if doc_page_content:lower():match("</?includeonly%f[%s/>][^>]*>") then
				track("module-includeonly")
			else
				-- Check for uses of {{module cat}}. find_templates treats the
				-- input as transcluded by default (i.e. it parses the wikitext
				-- which will be transcluded through to the module page).
				local module_cat
				for template in find_templates(doc_page_content) do
					if template:get_name() == "module cat" then
						module_cat = true
						break
					end
				end
				if not module_cat then
					get_module_doc_and_cats("categories only")
					auto_generated_cat_source = auto_generated_cat_source or doc_content_source
					cats_auto_generated_text = " Thể loại được tự động tạo bởi [[" .. auto_generated_cat_source .. "]]. <sup>[[" ..
						new_title(auto_generated_cat_source):fullUrl{action = "edit"} ..  " sửa]]</sup>"
				end
			end
		end

		output:insert(
			"<dd><i style=\"font-size: larger;\">[[:en:Help:Documenting templates and modules|Tài liệu]] " ..
			"bên dưới nằm tại [[" ..
			doc_title.fullText .. "]]. " .. "<sup>[[" .. doc_title:fullUrl{action = "edit"} .. " sửa]]</sup>" ..
			cats_auto_generated_text .. "</i></dd>")
	else
		if contentModel == "Scribunto" then
			get_module_doc_and_cats(false)
		elseif title.nsText == "Bản_mẫu" then
			--cats:insert("Uncategorized templates")
			needs_doc = not (fallback_docs or nodoc)
		elseif user_name and is_script_or_stylesheet then
			skin_name = skins[title.text:sub(#title.rootText + 1):match("^/(%l+)%.[jc]ss?$")]
			if skin_name then
				fallback_docs = "documentation/fallback/user " .. contentModel
			end
		end
		
		if doc_content then
			output:insert(
				"<dd><i style=\"font-size: larger;\">[[:en:Help:Documenting templates and modules|Tài liệu]] " ..
				"bên dưới được " ..
				"tạo bởi [[" .. doc_content_source .. "]]. <sup>[[" ..
				new_title(doc_content_source):fullUrl{action = "edit"} ..
				" sửa]]</sup> </i></dd>")
		elseif not nodoc then
			if title.text:find("/sandbox%d*%f[/%z]") then
				local sandbox_of = title.fullText:gsub("/sandbox%d*%f[/%z]", "")
			    output:insert(
					"<dd><i style=\"font-size: larger;\">Chỗ thử của" ..
					" [[" .. sandbox_of .. "|" .. sandbox_of .. "]]. <sup>[" .. compare_pages(title.fullText, sandbox_of, "khác") .. "]</sup></i></dd>\n")
			elseif title.text:find("/testcases%d*%f[/%z]") then
				local testcase_of = title.fullText:gsub("/testcases%d*%f[/%z]", "")
				output:insert(
					"<dd><i style=\"font-size: larger;\">Trường hợp kiểm thử của" ..
					" [[" .. testcase_of .. "|" .. testcase_of .. "]]. <sup>[" .. compare_pages(title.fullText, testcase_of, "khác") .. "]</sup></i></dd>\n")
			elseif doc_title then
				output:insert(
					"<dd><i style=\"font-size: larger;\">Trang " .. pagetype ..
					" này thiếu [[:en:Help:Documenting templates and modules|trang con tài liệu]]. " ..
					(fallback_docs and "Bạn có thể " or "Xin hãy ") ..
					"[" .. doc_title:fullUrl{action = "edit", preload = preload}
					.. " tạo trang tài liệu này].</i></dd>\n")
			else
				output:insert(
					"<dd><i style=\"font-size: larger; color: var(--wikt-palette-red-9,#FF0000);\">Không thể tự động tạo " ..
					"trang tài liệu cho " .. pagetype .." này.</i></dd>\n")
			end
		end
	end
	
	if startswith(title.fullText, "MediaWiki:Gadget-") then
		local is_gadget = false
		for line in gline(new_title("MediaWiki:Gadgets-definition").content) do
			local gadget, items = line:match("^%*%s*(%a[%w_-]*)%[.-%]|(.+)$")
			if not gadget then
				gadget, items = line:match("^%*%s*(%a[%w_-]*)|(.+)$")
			end
			if gadget then
				items = Array(split(items, "|"))
				for i, item in ipairs(items) do
					if title.fullText == ("MediaWiki:Gadget-" .. item) then
						is_gadget = true

						output:insert("<dd> ''Tập lệnh này là một phần của tiện ích <code>")
						output:insert(gadget)
						output:insert("</code> ([")
						output:insert(tostring(full_url("MediaWiki:Gadgets-definition", {action = "edit"})))
						output:insert(" sửa định nghĩa])'' <dl>")
						
						output:insert("<dd> ''Mô tả ([")
						output:insert(tostring(full_url("MediaWiki:Gadget-" .. gadget, {action = "edit"})))
						output:insert(" sửa])'': ")
						
						output:insert(preprocess(new_message('Gadget-' .. gadget):plain()))
						output:insert(" </dd>")

						items:remove(i)
						if #items > 0 then
							for j, item in ipairs(items) do
								items[j] = '[[MediaWiki:Gadget-' .. item .. '|' .. item .. ']]'
							end
							output:insert("<dd> ''Phần khác'': ")
							output:insert(list_to_text(items))
							output:insert("</dd>")
						end

						output:insert("</dl></dd>")

						break
					end
				end
			end
		end
		
		if not is_gadget then
			output:insert("<dd> ''Tập lệnh này không phải là một phần của bất kỳ [")
			output:insert(tostring(full_url("Special:Gadgets", {uselang = "en"})))
			output:insert(' tiện ích] nào ([')
			output:insert(tostring(full_url("MediaWiki:Gadgets-definition", {action = "edit"})))
			output:insert(' sửa định nghĩa]).</dd>')
		-- else
			-- cats:insert("Wiktionary gadgets")
		end
	end
	
	if old_doc_title then
		output:insert("<dd> ''Đổi hướng từ'' [")
		output:insert(old_doc_title:fullUrl{redirect = "no"})
		output:insert(" ")
		output:insert(old_doc_title.fullText)
		output:insert("] ([")
		output:insert(old_doc_title:fullUrl{action = "edit"})
		output:insert(" sửa]).</dd>\n")
	end
	
	if not args.nolinks then	
		local links = Array()

		if title.isSubpage and not args.notsubpage then
			links:insert("[[:" .. title.nsText .. ":" .. title.rootText .. "|trang gốc]]")
			links:insert("[[Special:PrefixIndex/" .. title.nsText .. ":" .. title.rootText .. "/|trang con của trang gốc]]")
		else
			links:insert("[[Special:PrefixIndex/" .. title.fullText .. "/|danh sách trang con]]")
		end
		
		links:insert(
			"[" .. tostring(full_url("Special:WhatLinksHere/" .. title.fullText, {hidetrans = true, hideredirs = true})) .. " liên kết]")
	
		if contentModel ~= "Scribunto" then
			links:insert(
				"[" .. tostring(full_url("Special:WhatLinksHere/" .. title.fullText, {hidelinks = true, hidetrans = true})) .. " đổi hướng]")
		end
	
		if is_script_or_stylesheet then
			if user_name then
				links:insert("[[Special:MyPage" .. title.text:sub(#title.rootText + 1) .. "|của bạn]]")
			end
		else
			links:insert(
				"[" .. tostring(full_url("Special:WhatLinksHere/" .. title.fullText, {hidelinks = true, hideredirs = true})) .. " nhúng]")
		end
		
		if contentModel == "Scribunto" then
			local is_testcases = title.isSubpage and title.subpageText == "testcases"
			local without_subpage = title.nsText .. ":" .. title.baseText
			if is_testcases then
				links:insert("[[:" .. without_subpage .. "|trường hợp mô đun đã kiểm thử]]")
			else
				links:insert("[[" .. without_subpage .. "/testcases|trường hợp kiểm thử]]")
			end
			
			if user_name then
				links:insert("[[User:" .. user_name .. "|trang thành viên]]")
				links:insert("[[User talk:" .. user_name .. "|trang thảo luận thành viên]]")
				links:insert("[[Special:PrefixIndex/User:" .. user_name .. "/|không gian thành viên]]")
			-- If sandbox module, add a link to the module that this is a sandbox of.
			-- Exclude user sandbox modules like [[User:Dine2016/sandbox]].
			elseif title.text:find("/sandbox%d*%f[/%z]") then
				cats:insert("Chỗ thử mô đun")
				
				-- Sandbox modules don’t really need documentation.
				needs_doc = false
				
				-- Don't track user sandbox modules.
				local text_title = new_title(title.text)
				if not (text_title and text_title.namespace == 2) then
					track("sandbox to be moved")
					
					local sandbox_of, diff = title.baseText
					if title_exists(sandbox_of) then

					else
						track("no sandbox of")
					end
					

				end
			-- If not a sandbox module, add link to sandbox module.
			-- Sometimes there are multiple sandboxes for a single module:
			-- [[Module:sa-pronunc/sandbox]],  [[Module:sa-pronunc/sandbox2]].
			-- Occasionally sandbox modules have their own subpages that are also
			-- sandboxes: [[Module:grc-decl/sandbox/decl]].
			else
				local sandbox_title
				if title.rootText == "grc-decl" then
					sandbox_title = string_insert(title.fullText, 16, "/sandbox")
				elseif is_testcases then
					sandbox_title = title.fullText:gsub("/testcases", "/sandbox")
				else
					sandbox_title = title.fullText .. "/sandbox"
				end
				local sandbox_link = "[[:" .. sandbox_title .. "|chỗ thử]]"
				
				local diff
				if title_exists(sandbox_title) then
					diff = " (" .. compare_pages(title.fullText, sandbox_title, "khác") .. ")"
				end
				
				links:insert(sandbox_link .. (diff or ""))
			end
		end
		
		if title.nsText == "Bản_mẫu" then
			-- Error search: all(any namespace), hastemplate (show pages using the template), insource (show source code), incategory (any/specific error) -- [[mw:Help:CirrusSearch]], [[w:Help:Searching/Regex]]
			-- apparently same with/without: &profile=advanced&fulltext=1
			local errorq = 'searchengineselect=mediawiki&search=all: hastemplate:\"'..title.rootText..'\" insource:\"'..title.rootText..'\" incategory:'
			local eincategory = "Pages_with_module_errors|ParserFunction_errors|DisplayTitle_errors|Pages_with_ISBN_errors|Pages_with_ISSN_errors|Pages_with_reference_errors|Pages_with_syntax_highlighting_errors|Pages_with_TemplateStyles_errors"
			
			links:insert(
				'[' .. tostring(full_url('Special:Search', errorq..eincategory )) .. ' lỗi]'
				.. ' (' ..
				'[' .. tostring(full_url('Special:Search', errorq..'ParserFunction_errors' )) .. ' phân tích cú pháp]'
				.. '/' ..
				'[' .. tostring(full_url('Special:Search', errorq..'Pages_with_module_errors' )) .. ' mô đun]'
				.. ')'
			)
			
			if title.isSubpage and title.text:find("/sandbox%d*%f[/%z]") then -- This is a sandbox template.
				-- At the moment there are no user sandbox templates with subpage
				-- “/sandbox”.
				cats:insert("Chỗ thử bản mẫu")
				
				-- Sandbox templates don’t really need documentation.
				needs_doc = false
				
				-- Will behave badly if “/sandbox” occurs twice in title!
				local sandbox_of = title.fullText:gsub("/sandbox%d*%f[/%z]", "")
				

				if title_exists(sandbox_of) then

				else
					track("no sandbox of")
				end
				

			-- This is a template that can have a sandbox.
			elseif not args.nosandbox then -- unless we tell it not to
				local sandbox_title = title.fullText .. "/sandbox"
			
				local diff
				if title_exists(sandbox_title) then
					diff = " (" .. compare_pages(title.fullText, sandbox_title, "khác") .. ")"
				end
			
				links:insert("[[:" .. sandbox_title .. "|chỗ thử]]" .. (diff or ""))
			end
		end
		
		if #links > 0 then
			output:insert("<dd> ''Liên kết hữu ích'': " .. links:concat(" • ") .. "</dd>")
		end
	end
	
	output:insert("</dl>\n")
	
	-- Show error from [[Module:category tree/topic cat/data]] on its submodules'
	-- documentation to, for instance, warn about duplicate labels.
	if startswith(title.fullText, "Module:category tree/topic/") then
		local ok, err = pcall(require, "Module:category tree/topic/data")
		if not ok then
			output:insert('<span class="error">' .. err .. '</span>\n\n')
		end
	end
	
	if doc_title and doc_title.exists then
		-- Override automatic documentation, if present.
		doc_content = expand_template{ title = doc_title.fullText }
	elseif not doc_content and fallback_docs then
		doc_content = expand_template{
			title = fallback_docs,
			args = {
				['user'] = user_name,
				['page'] = title.fullText,
				['skin name'] = skin_name,
			},
		}
	end

	if doc_content then
		output:insert(doc_content)
	end

	output:insert('\n<span style="clear: both;" />')
	
	if cats_auto_generated and not cats[1] and (not doc_content or not doc_content:find("%[%[Category:")) then
		if contentModel == "Scribunto" then
			if not title.text:find("/testcases%d*%f[/%z]") then
			cats:insert("Mô đun chưa phân loại")
			end
		-- elseif title.nsText == "Bản mẫu" then
			-- cats:insert("Uncategorized templates")
		end
	end
	
	if needs_doc then
		if not title.text:find("/testcases%d*%f[/%z]") then
		cats:insert("Bản mẫu và mô đun chưa có tài liệu")
		end
	end
	
	for _, cat in ipairs(cats) do
		output:insert("[[Category:" .. cat .. "]]")
	end
	
	output:insert("</div>\n")

	return output:concat()
end

function export.module_auto_doc_table()
	local parts = {}
	local function ins(text)
		insert(parts, text)
	end
	ins('{|class="wikitable"')
	ins("! Regex !! Thể loại !! Mô đun xử lý")
	for _, spec in ipairs(module_regex) do
		local cat_text
		local cats = spec.cat
		if cats then
			local cat_parts = {}
			if type(cats) == "string" then
				cats = {cats}
			end
			for _, cat in ipairs(cats) do
				insert(cat_parts, ("<code>%s</code>"):format((cat:gsub("|", "&#124;"))))
			end
			cat_text = concat(cat_parts, ", ")
		else
			cat_text = "''(không được chỉ định)''"
		end
		ins("|-")
		ins(("| <code>%s</code> || %s || %s"):format(spec.regex, cat_text,
			is_callable(spec.process) and "''(xử lý nội bộ)''" or
			type(spec.process) == "string" and ("[[Module:documentation2/functions/%s]]"):format(spec.process) or
			"''(không có trình tạo tài liệu)''"))
	end
	ins("|}")
	return concat(parts, "\n")
end

-- Used by {{translit module documentation}}.
function export.translitModuleLangList(frame)
	local pagename, subpage
	
	if frame.args[1] then
		pagename = frame.args[1]
	else
		local title = get_current_title()
		subpage = title.subpageText
		pagename = title.text
		
		if subpage ~= pagename then
			pagename = title.rootText
		end
	end
	
	local translitModule = pagename
	
	local languageObjects = require("Module:languages/byTranslitModule")(translitModule)
	local codeInPagename = pagename:match("^([%l-]+)%-.*translit$")
	
	local categories = Array()
	local codeInPagenameInList = false
	if codeInPagename then
		if languageObjects[1] and subpage ~= "tài liệu" then
			local agreement = languageObjects[2] and "" or ""
			categories:insert("[[Thể loại:Mô đun chuyển tự được sử dụng bởi " ..
				#languageObjects .. " ngôn ngữ" .. agreement .. "]]")
		end
		
		languageObjects = Array(languageObjects)
			:filter(
				function (lang)
					local result = lang:getCode() ~= codeInPagename
					codeInPagenameInList = codeInPagenameInList or result
					return result
				end)
	end
	
	if subpage ~= "tài liệu" then
		for script_code in pagename:gmatch("%f[^-%z]%u%l%l%l%f[-]") do
			local script = get_script(script_code)
			if script then
				categories:insert("[[Category:" .. script:getCategoryName() .. "]]")
			end
		end
	end
	
	if subpage ~= "tài liệu" and not title_exists("Mô_đun:" .. pagename .. "/testcases") then
		categories:insert("[[Thể loại:Mô đun chuyển tự không có trang con trường hợp kiểm thử]]")
	end
	
	if not languageObjects[1] then
		return categories:concat()
	end
	
	local langs = Array(languageObjects)
		:sort(
			function(lang1, lang2)
				return lang1:getCode() < lang2:getCode()
			end)
		-- This will not error because languageObjects is not empty.
		:map(languageObjects[1].makeCategoryLink)
		:serialCommaJoin()
	
	return "Nó " .. ( codeInPagenameInList and "cũng" or "" ) ..
		" được sử dụng để phiên âm " .. langs .. "." .. categories:concat()
end

-- Used by {{entry name module documentation}}.
function export.entryNameModuleLangList(frame)
	local pagename, subpage
	
	if frame.args[1] then
		pagename = frame.args[1]
	else
		local title = get_current_title()
		subpage = title.subpageText
		pagename = title.text
		
		if subpage ~= pagename then
			pagename = title.rootText
		end
	end
	
	local entryNameModule = pagename
	
	local languageObjects = require("Mô_đun:languages/byEntryNameModule")(entryNameModule)
	local codeInPagename = pagename:match("^([%l-]+)%-.*entryname$")
	
	local categories = Array()
	local codeInPagenameInList = false
	if codeInPagename then
		if languageObjects[1] and subpage ~= "tài liệu" then
			local agreement = languageObjects[2] and "s" or ""
			categories:insert("[[Category:Mô đun tạo mục từ được sử dụng bởi " ..
				#languageObjects .. " ngôn ngữ" .. agreement .. "]]")
		end
		
		languageObjects = Array(languageObjects)
			:filter(
				function (lang)
					local result = lang:getCode() ~= codeInPagename
					codeInPagenameInList = codeInPagenameInList or result
					return result
				end)
	end
	
	if subpage ~= "tài liệu" then
		for script_code in pagename:gmatch("%f[^-%z]%u%l%l%l%f[-]") do
			local script = get_script(script_code)
			if script then
				categories:insert("[[Category:" .. script:getCategoryName() .. "]]")
			end
		end
	end
	
	if subpage ~= "tài liệu" and not title_exists("Mô_đun:" .. pagename .. "/testcases") then
		categories:insert("[[Category:Mô đun tạo tên mục từ không có trang con trường hợp kiểm thử]]")
	end
	
	if not languageObjects[1] then
		return categories:concat()
	end
	
	local langs = Array(languageObjects)
		:sort(
			function(lang1, lang2)
				return lang1:getCode() < lang2:getCode()
			end)
		-- This will not error because languageObjects is not empty.
		:map(languageObjects[1].makeCategoryLink)
		:serialCommaJoin()
	
	return "Nó " .. ( codeInPagenameInList and "cũng" or "" ) ..
		" được sử dụng để tạo tên mục từ cho " .. langs .. "." .. categories:concat()
end

-- Used by {{sortkey module documentation}}.
function export.sortkeyModuleLangList(frame)
	local pagename, subpage
	
	if frame.args[1] then
		pagename = frame.args[1]
	else
		local title = get_current_title()
		subpage = title.subpageText
		pagename = title.text
		
		if subpage ~= pagename then
			pagename = title.rootText
		end
	end
	
	local sortkeyModule = pagename
	
	local languageObjects = require("Mô_đun:languages/bySortkeyModule")(sortkeyModule)
	local codeInPagename = pagename:match("^([%l-]+)%-.*sortkey$")
	
	local categories = Array()
	local codeInPagenameInList = false
	if codeInPagename then
		if languageObjects[1] and subpage ~= "tài liệu" then
			local agreement = languageObjects[2] and "s" or ""
			categories:insert("[[Category:Mô đun tạo Sortkey được sử dụng bởi " ..
				#languageObjects .. " ngôn ngữ" .. agreement .. "]]")
		end
		
		languageObjects = Array(languageObjects)
			:filter(
				function (lang)
					local result = lang:getCode() ~= codeInPagename
					codeInPagenameInList = codeInPagenameInList or result
					return result
				end)
	end
	
	if subpage ~= "tài liệu" then
		for script_code in pagename:gmatch("%f[^-%z]%u%l%l%l%f[-]") do
			local script = get_script(script_code)
			if script then
				categories:insert("[[Category:" .. script:getCategoryName() .. "]]")
			end
		end
	end
	
	if subpage ~= "tài liệu" and not title_exists("Mô_đun:" .. pagename .. "/testcases") then
		categories:insert("[[Category:Mô đun tạo Sortkey không có trang con trường hợp kiểm thử]]")
	end
	
	if not languageObjects[1] then
		return categories:concat()
	end
	
	local langs = Array(languageObjects)
		:sort(
			function(lang1, lang2)
				return lang1:getCode() < lang2:getCode()
			end)
		-- This will not error because languageObjects is not empty.
		:map(languageObjects[1].makeCategoryLink)
		:serialCommaJoin()
	
	return "Nó " .. ( codeInPagenameInList and "cũng" or "" ) ..
		" được sử dụng để sắp xếp " .. langs .. "." .. categories:concat()
end

return export