<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://linguifex.com/w/index.php?action=history&amp;feed=atom&amp;title=Module%3Aform_of_doc</id>
	<title>Module:form of doc - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://linguifex.com/w/index.php?action=history&amp;feed=atom&amp;title=Module%3Aform_of_doc"/>
	<link rel="alternate" type="text/html" href="https://linguifex.com/w/index.php?title=Module:form_of_doc&amp;action=history"/>
	<updated>2026-04-03T18:33:10Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>https://linguifex.com/w/index.php?title=Module:form_of_doc&amp;diff=225236&amp;oldid=prev</id>
		<title>Sware: Created page with &quot;--[=[ 	This module contains functions to implement {{form of/*doc}} templates. 	The module contains the actual implementation, meant to be called from other 	Lua code. See [[M...&quot;</title>
		<link rel="alternate" type="text/html" href="https://linguifex.com/w/index.php?title=Module:form_of_doc&amp;diff=225236&amp;oldid=prev"/>
		<updated>2021-03-24T16:16:16Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;--[=[ 	This module contains functions to implement {{form of/*doc}} templates. 	The module contains the actual implementation, meant to be called from other 	Lua code. See [[M...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;--[=[&lt;br /&gt;
	This module contains functions to implement {{form of/*doc}} templates.&lt;br /&gt;
	The module contains the actual implementation, meant to be called from other&lt;br /&gt;
	Lua code. See [[Module:form of doc/templates]] for the function meant to be&lt;br /&gt;
	called directly from templates.&lt;br /&gt;
&lt;br /&gt;
	Author: Benwing2&lt;br /&gt;
]=]&lt;br /&gt;
&lt;br /&gt;
local export = {}&lt;br /&gt;
&lt;br /&gt;
local m_template_link = require(&amp;quot;Module:template link&amp;quot;)&lt;br /&gt;
local m_languages = require(&amp;quot;Module:languages&amp;quot;)&lt;br /&gt;
local m_table = require(&amp;quot;Module:table&amp;quot;)&lt;br /&gt;
local strutils = require(&amp;quot;Module:string utilities&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
local usub = mw.ustring.sub&lt;br /&gt;
local uupper = mw.ustring.upper&lt;br /&gt;
local rfind = mw.ustring.find&lt;br /&gt;
local rsubn = mw.ustring.gsub&lt;br /&gt;
&lt;br /&gt;
-- version of rsubn() that discards all but the first return value&lt;br /&gt;
local function rsub(term, foo, bar)&lt;br /&gt;
	local retval = rsubn(term, foo, bar)&lt;br /&gt;
	return retval&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function lang_name(langcode, param)&lt;br /&gt;
	local lang = m_languages.getByCode(langcode) or m_languages.err(langcode, param)&lt;br /&gt;
	return lang:getCanonicalName()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function ucfirst(text)&lt;br /&gt;
	return uupper(usub(text, 1, 1)) .. usub(text, 2)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function template_name(preserve_lang_code)&lt;br /&gt;
	-- Fetch the template name, minus the &amp;#039;/documentation&amp;#039; suffix that may follow&lt;br /&gt;
	-- and without any language-specific prefixes (e.g. &amp;#039;el-&amp;#039; or &amp;#039;bsl-ine-pro-&amp;#039;)&lt;br /&gt;
	-- (unless `preserve_lang_code` is given).&lt;br /&gt;
	local PAGENAME =  mw.title.getCurrentTitle().text&lt;br /&gt;
	local tempname = rsub(PAGENAME, &amp;quot;/documentation$&amp;quot;, &amp;quot;&amp;quot;)&lt;br /&gt;
	if not preserve_lang_code then&lt;br /&gt;
		while true do&lt;br /&gt;
			-- Repeatedly strip off language code prefixes, in case there are multiple.&lt;br /&gt;
			local newname = rsub(tempname, &amp;quot;^[a-z][a-z][a-z]?%-&amp;quot;, &amp;quot;&amp;quot;)&lt;br /&gt;
			if newname == tempname then&lt;br /&gt;
				break&lt;br /&gt;
			end&lt;br /&gt;
			tempname = newname&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return tempname&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function export.introdoc(args)&lt;br /&gt;
	local langname = args.lang and lang_name(args.lang, &amp;quot;lang&amp;quot;)&lt;br /&gt;
	local exlangnames = {}&lt;br /&gt;
	for _, exlang in ipairs(args.exlang) do&lt;br /&gt;
		table.insert(exlangnames, lang_name(exlang, &amp;quot;exlang&amp;quot;))&lt;br /&gt;
	end&lt;br /&gt;
	parts = {}&lt;br /&gt;
	table.insert(parts, &amp;quot;This template creates a definition line for &amp;quot;)&lt;br /&gt;
	table.insert(parts, args.pldesc or rsub(template_name(), &amp;quot; of$&amp;quot;, &amp;quot;&amp;quot;) .. &amp;quot;s&amp;quot;)&lt;br /&gt;
	table.insert(parts, &amp;quot; &amp;quot;)&lt;br /&gt;
	table.insert(parts, args.primaryentrytext or &amp;quot;of primary entries&amp;quot;)&lt;br /&gt;
	if args.lang then&lt;br /&gt;
		table.insert(parts, &amp;quot; in &amp;quot; .. langname)&lt;br /&gt;
	elseif #args.exlang &amp;gt; 0 then&lt;br /&gt;
		table.insert(parts, &amp;quot;, e.g. in &amp;quot; .. m_table.serialCommaJoin(exlangnames, {conj = &amp;quot;or&amp;quot;}))&lt;br /&gt;
	end&lt;br /&gt;
	table.insert(parts, &amp;quot;.&amp;quot;)&lt;br /&gt;
	if #args.cat &amp;gt; 0 then&lt;br /&gt;
		table.insert(parts, &amp;quot; It also categorizes the page into &amp;quot;)&lt;br /&gt;
		local catparts = {}&lt;br /&gt;
		for _, cat in ipairs(args.cat) do&lt;br /&gt;
			if args.lang then&lt;br /&gt;
				table.insert(catparts, &amp;quot;[[:Category:&amp;quot; .. langname .. &amp;quot; &amp;quot; .. cat .. &amp;quot;]]&amp;quot;)&lt;br /&gt;
			else&lt;br /&gt;
				table.insert(catparts, &amp;quot;the proper language-specific subcategory of [[:Category:&amp;quot; .. ucfirst(cat) .. &amp;quot; by language]] (e.g. [[:Category:&amp;quot; .. (exlangnames[1] or &amp;quot;English&amp;quot;) .. &amp;quot; &amp;quot; .. cat .. &amp;quot;]])&amp;quot;)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		table.insert(parts, m_table.serialCommaJoin(catparts))&lt;br /&gt;
		table.insert(parts, &amp;quot;.&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	if args.addlintrotext then&lt;br /&gt;
		table.insert(parts, &amp;quot; &amp;quot;)&lt;br /&gt;
		table.insert(parts, args.addlintrotext)&lt;br /&gt;
	end&lt;br /&gt;
	table.insert(parts, &amp;quot;\n&amp;quot;)&lt;br /&gt;
	if args.withcap and args.withdot then&lt;br /&gt;
		table.insert(parts, [===[&lt;br /&gt;
&lt;br /&gt;
By default, this template displays its output as a full sentence, with an initial capital letter and a trailing period (full stop). This can be overridden using &amp;lt;code&amp;gt;|nocap=1&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;|nodot=1&amp;lt;/code&amp;gt; (see below).&lt;br /&gt;
]===])&lt;br /&gt;
	elseif args.withcap then&lt;br /&gt;
		table.insert(parts, [===[&lt;br /&gt;
&lt;br /&gt;
By default, this template displays its output with an initial capital letter. This can be overridden using &amp;lt;code&amp;gt;|nocap=1&amp;lt;/code&amp;gt; (see below).&lt;br /&gt;
]===])&lt;br /&gt;
	end&lt;br /&gt;
	table.insert(parts, [===[&lt;br /&gt;
&lt;br /&gt;
This template is &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; meant to be used in etymology sections.]===])&lt;br /&gt;
	if args.etymtemp then&lt;br /&gt;
		table.insert(parts, &amp;quot; For those sections, use &amp;lt;code&amp;gt;{{[[Template:&amp;quot; .. args.etymtemp .. &amp;quot;|&amp;quot; .. args.etymtemp .. &amp;quot;]]}}&amp;lt;/code&amp;gt; instead.&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	table.insert(parts, [===[&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note that users can customize how the output of this template displays by modifying their monobook.css files. See [[:Category:Form-of templates|“Form of” templates]] for details.&lt;br /&gt;
]===])&lt;br /&gt;
	return table.concat(parts)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function param(params, list, required)&lt;br /&gt;
	local paramparts = {}&lt;br /&gt;
	if type(params) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
		params = {params}&lt;br /&gt;
	end&lt;br /&gt;
	for _, p in ipairs(params) do&lt;br /&gt;
		local listparts = {}&lt;br /&gt;
		table.insert(listparts, &amp;quot;&amp;lt;code&amp;gt;|&amp;quot; .. p .. &amp;quot;=&amp;lt;/code&amp;gt;&amp;quot;)&lt;br /&gt;
		if list then&lt;br /&gt;
			table.insert(listparts, &amp;quot;, &amp;lt;code&amp;gt;|&amp;quot; .. p .. &amp;quot;2=&amp;lt;/code&amp;gt;&amp;quot;)&lt;br /&gt;
			table.insert(listparts, &amp;quot;, &amp;lt;code&amp;gt;|&amp;quot; .. p .. &amp;quot;3=&amp;lt;/code&amp;gt;&amp;quot;)&lt;br /&gt;
			table.insert(listparts, &amp;quot;, etc.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
		table.insert(paramparts, table.concat(listparts))&lt;br /&gt;
	end&lt;br /&gt;
	local reqtext = required and &amp;quot;&amp;#039;&amp;#039;&amp;#039;(required)&amp;#039;&amp;#039;&amp;#039;&amp;quot; or &amp;quot;&amp;#039;&amp;#039;(optional)&amp;#039;&amp;#039;&amp;quot;&lt;br /&gt;
	return table.concat(paramparts, &amp;quot; or &amp;quot;) .. &amp;quot; &amp;quot; .. reqtext&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function export.paramdoc(args)&lt;br /&gt;
	local parts = {}&lt;br /&gt;
	&lt;br /&gt;
	local function param_and_doc(params, list, required, doc)&lt;br /&gt;
		table.insert(parts, &amp;quot;; &amp;quot;)&lt;br /&gt;
		table.insert(parts, param(params, list, required))&lt;br /&gt;
		table.insert(parts, &amp;quot;\n&amp;quot;)&lt;br /&gt;
		table.insert(parts, &amp;quot;: &amp;quot;)&lt;br /&gt;
		table.insert(parts, doc)&lt;br /&gt;
		table.insert(parts, &amp;quot;\n&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local tempname = template_name()&lt;br /&gt;
	local art = args.art or rfind(tempname, &amp;quot;^[aeiouAEIOU]&amp;quot;) and &amp;quot;an&amp;quot; or &amp;quot;a&amp;quot;&lt;br /&gt;
	local sgdescof = args.sgdescof or art .. &amp;quot; &amp;quot; .. tempname&lt;br /&gt;
	table.insert(parts, &amp;quot;&amp;#039;&amp;#039;Positional (unnamed) parameters:&amp;#039;&amp;#039;\n&amp;quot;)&lt;br /&gt;
	if args.lang then&lt;br /&gt;
		param_and_doc(&amp;quot;1&amp;quot;, false, true, &amp;quot;The term to link to (which this page is &amp;quot; .. sgdescof .. &amp;quot;). This should include any needed diacritics as appropriate to &amp;quot; .. lang_name(args.lang, &amp;quot;lang&amp;quot;) .. &amp;quot;. These diacritics will automatically be stripped out in the appropriate fashion in order to create the link to the page.&amp;quot;)&lt;br /&gt;
		param_and_doc(&amp;quot;2&amp;quot;, false, false, &amp;quot;The text to be shown in the link to the term. If empty or omitted, the term specified by the first parameter will be used. This parameter is normally not necessary, and should not be used solely to indicate diacritics; instead, put the diacritics in the first parameter.&amp;quot;)&lt;br /&gt;
	else&lt;br /&gt;
		param_and_doc(&amp;quot;1&amp;quot;, false, true, &amp;quot;The [[WT:LANGCODE|language code]] of the term linked to (which this page is &amp;quot; .. sgdescof .. &amp;quot;). See [[Wiktionary:List of languages]]. &amp;lt;small&amp;gt;The parameter &amp;lt;code&amp;gt;|lang=&amp;lt;/code&amp;gt; is a deprecated synonym; please do not use. If this is used, all numbered parameters move down by one.&amp;lt;/small&amp;gt;&amp;quot;)&lt;br /&gt;
		param_and_doc(&amp;quot;2&amp;quot;, false, true, &amp;quot;The term to link to (which this page is &amp;quot; .. sgdescof .. &amp;quot;). This should include diacritics as appropriate to the language (e.g. accents in Russian to mark the stress, vowel diacritics in Arabic, macrons in Latin to indicate vowel length, etc.). These diacritics will automatically be stripped out in a language-specific fashion in order to create the link to the page.&amp;quot;)&lt;br /&gt;
		param_and_doc(&amp;quot;3&amp;quot;, false, false, &amp;quot;The text to be shown in the link to the term. If empty or omitted, the term specified by the second parameter will be used. This parameter is normally not necessary, and should not be used solely to indicate diacritics; instead, put the diacritics in the second parameter.&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	table.insert(parts, &amp;quot;&amp;#039;&amp;#039;Named parameters:&amp;#039;&amp;#039;\n&amp;quot;)&lt;br /&gt;
	param_and_doc({&amp;quot;t&amp;quot;, args.lang and &amp;quot;3&amp;quot; or &amp;quot;4&amp;quot;}, false, false, &amp;quot;A gloss or short translation of the term linked to. &amp;lt;small&amp;gt;The parameter &amp;lt;code&amp;gt;|gloss=&amp;lt;/code&amp;gt; is a deprecated synonym; please do not use.&amp;lt;/small&amp;gt;&amp;quot;)&lt;br /&gt;
	param_and_doc(&amp;quot;tr&amp;quot;, false, false, &amp;quot;Transliteration for non-Latin-script terms, if different from the automatically-generated one.&amp;quot;)&lt;br /&gt;
	param_and_doc(&amp;quot;ts&amp;quot;, false, false, &amp;quot;Transcription for non-Latin-script terms whose transliteration is markedly different from the actual pronunciation. Should not be used for IPA pronunciations.&amp;quot;)&lt;br /&gt;
	param_and_doc(&amp;quot;sc&amp;quot;, false, false, &amp;quot;Script code to use, if script detection does not work. See [[Wiktionary:Scripts]].&amp;quot;)&lt;br /&gt;
	if args.withfrom then&lt;br /&gt;
		param_and_doc(&amp;quot;from&amp;quot;, true, false, &amp;quot;A label (see &amp;quot; .. m_template_link.format_link({&amp;quot;label&amp;quot;}) .. &amp;quot;) that gives additional information on the dialect that the term belongs to, the place that it originates from, or something similar.&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	if args.withdot then&lt;br /&gt;
		param_and_doc(&amp;quot;dot&amp;quot;, false, false, &amp;quot;A character to replace the final dot that is normally shown automatically.&amp;quot;)&lt;br /&gt;
		param_and_doc(&amp;quot;nodot&amp;quot;, false, false, &amp;quot;If &amp;lt;code&amp;gt;|nodot=1&amp;lt;/code&amp;gt;, then no automatic dot will be shown.&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	if args.withcap then&lt;br /&gt;
		param_and_doc(&amp;quot;nocap&amp;quot;, false, false, &amp;quot;If &amp;lt;code&amp;gt;|nocap=1&amp;lt;/code&amp;gt;, then the first letter will be in lowercase.&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	param_and_doc(&amp;quot;id&amp;quot;, false, false, &amp;quot;A sense id for the term, which links to anchors on the page set by the &amp;quot; .. m_template_link.format_link({&amp;quot;senseid&amp;quot;}) .. &amp;quot; template.&amp;quot;)&lt;br /&gt;
	return table.concat(parts)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function export.usagedoc(args)&lt;br /&gt;
	local exlangs = {}&lt;br /&gt;
	for _, exlang in ipairs(args.exlang) do&lt;br /&gt;
		table.insert(exlangs, exlang)&lt;br /&gt;
	end&lt;br /&gt;
	table.insert(exlangs, &amp;#039;en&amp;#039;)&lt;br /&gt;
	table.insert(exlangs, &amp;#039;de&amp;#039;)&lt;br /&gt;
	table.insert(exlangs, &amp;#039;ja&amp;#039;)&lt;br /&gt;
	exlangs = m_table.removeDuplicates(exlangs)&lt;br /&gt;
	local sub = {}&lt;br /&gt;
	local langparts = {}&lt;br /&gt;
	for i, langcode in ipairs(exlangs) do&lt;br /&gt;
		table.insert(langparts, &amp;#039;&amp;lt;code&amp;gt;&amp;#039; .. langcode .. &amp;#039;&amp;lt;/code&amp;gt; for &amp;#039; .. lang_name(langcode, &amp;quot;exlang&amp;quot;))&lt;br /&gt;
	end&lt;br /&gt;
	sub.exlangs = m_table.serialCommaJoin(langparts, {conj = &amp;quot;or&amp;quot;})&lt;br /&gt;
	sub.tempname = template_name(&amp;quot;preserve lang code&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	if args.lang then&lt;br /&gt;
		return strutils.format([===[&lt;br /&gt;
==Usage==&lt;br /&gt;
Use in the definition line, most commonly as follows:&lt;br /&gt;
 # {\op}{\op}{tempname}|&amp;lt;var&amp;gt;&amp;lt;primary entry goes here&amp;gt;&amp;lt;/var&amp;gt;{\cl}{\cl}&lt;br /&gt;
&lt;br /&gt;
===Parameters===&lt;br /&gt;
]===], sub) .. export.paramdoc(args)&lt;br /&gt;
	else&lt;br /&gt;
		return strutils.format([===[&lt;br /&gt;
==Usage==&lt;br /&gt;
Use in the definition line, most commonly as follows:&lt;br /&gt;
 # {\op}{\op}{tempname}|&amp;lt;var&amp;gt;&amp;lt;langcode&amp;gt;&amp;lt;/var&amp;gt;|&amp;lt;var&amp;gt;&amp;lt;primary entry goes here&amp;gt;&amp;lt;/var&amp;gt;{\cl}{\cl}&lt;br /&gt;
where &amp;lt;code&amp;gt;&amp;lt;var&amp;gt;&amp;lt;langcode&amp;gt;&amp;lt;/var&amp;gt;&amp;lt;/code&amp;gt; is the [[Wiktionary:Languages|language code]], e.g. {exlangs}.&lt;br /&gt;
&lt;br /&gt;
===Parameters===&lt;br /&gt;
]===], sub) .. export.paramdoc(args)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function export.fulldoc(args)&lt;br /&gt;
	local docsubpage = mw.getCurrentFrame():expandTemplate{title=&amp;quot;documentation subpage&amp;quot;, args={}}&lt;br /&gt;
	local shortcuts = #args.shortcut &amp;gt; 0 and require(&amp;quot;Module:shortcut box&amp;quot;).show(args.shortcut) or &amp;quot;&amp;quot;&lt;br /&gt;
	local introdoc = export.introdoc(args)&lt;br /&gt;
	local usagedoc = export.usagedoc(args)&lt;br /&gt;
	return docsubpage .. &amp;quot;\n&amp;quot; .. shortcuts .. introdoc .. &amp;quot;\n&amp;quot; .. usagedoc&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function export.infldoc(args)&lt;br /&gt;
	args = require(&amp;quot;Module:table&amp;quot;).shallowcopy(args)&lt;br /&gt;
	args.sgdesc = args.sgdesc or (args.art or &amp;quot;the&amp;quot;) .. &amp;quot; &amp;quot; ..&lt;br /&gt;
		rsub(template_name(), &amp;quot; of$&amp;quot;, &amp;quot;&amp;quot;) .. (args.form and &amp;quot; &amp;quot; .. args.form or &amp;quot;&amp;quot;)&lt;br /&gt;
	args.pldesc = args.sgdesc&lt;br /&gt;
	args.sgdescof = args.sgdescof or args.sgdesc .. &amp;quot; of&amp;quot;&lt;br /&gt;
	args.primaryentrytext = args.primaryentrytext or &amp;quot;of a primary entry&amp;quot;&lt;br /&gt;
	return export.fulldoc(args)	&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local tag_type_to_description = {&lt;br /&gt;
	-- If not listed, we just capitalize the first letter&lt;br /&gt;
	[&amp;quot;tense-aspect&amp;quot;] = &amp;quot;Tense/aspect&amp;quot;,&lt;br /&gt;
	[&amp;quot;voice-valence&amp;quot;] = &amp;quot;Voice/valence&amp;quot;,&lt;br /&gt;
	[&amp;quot;comparison&amp;quot;] = &amp;quot;Degrees of comparison&amp;quot;,&lt;br /&gt;
	[&amp;quot;class&amp;quot;] = &amp;quot;Inflectional class&amp;quot;,&lt;br /&gt;
	[&amp;quot;sound change&amp;quot;] = &amp;quot;Sound changes&amp;quot;,&lt;br /&gt;
	[&amp;quot;grammar&amp;quot;] = &amp;quot;Misc grammar&amp;quot;,&lt;br /&gt;
	[&amp;quot;other&amp;quot;] = &amp;quot;Other tags&amp;quot;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local tag_type_order = {&lt;br /&gt;
	&amp;quot;person&amp;quot;,&lt;br /&gt;
	&amp;quot;number&amp;quot;,&lt;br /&gt;
	&amp;quot;gender&amp;quot;,&lt;br /&gt;
	&amp;quot;animacy&amp;quot;,&lt;br /&gt;
	&amp;quot;tense-aspect&amp;quot;,&lt;br /&gt;
	&amp;quot;mood&amp;quot;,&lt;br /&gt;
	&amp;quot;voice-valence&amp;quot;,&lt;br /&gt;
	&amp;quot;non-finite&amp;quot;,&lt;br /&gt;
	&amp;quot;case&amp;quot;,&lt;br /&gt;
	&amp;quot;state&amp;quot;,&lt;br /&gt;
	&amp;quot;comparison&amp;quot;,&lt;br /&gt;
	&amp;quot;register&amp;quot;,&lt;br /&gt;
	&amp;quot;deixis&amp;quot;,&lt;br /&gt;
	&amp;quot;clusivity&amp;quot;,&lt;br /&gt;
	&amp;quot;class&amp;quot;,&lt;br /&gt;
	&amp;quot;attitude&amp;quot;,&lt;br /&gt;
	&amp;quot;sound change&amp;quot;,&lt;br /&gt;
	&amp;quot;grammar&amp;quot;,&lt;br /&gt;
	&amp;quot;other&amp;quot;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local function sort_by_first(namedata1, namedata2)&lt;br /&gt;
	return namedata1[1] &amp;lt; namedata2[1]&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function export.tagtable()&lt;br /&gt;
	m_data = mw.loadData(&amp;quot;Module:form of/data&amp;quot;)&lt;br /&gt;
	m_data2 = mw.loadData(&amp;quot;Module:form of/data2&amp;quot;)&lt;br /&gt;
	m_form_of = require(&amp;quot;Module:form of&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local function organize_data(data_module)&lt;br /&gt;
		local tab = {}&lt;br /&gt;
		for name, data in pairs(data_module.tags) do&lt;br /&gt;
			if not data.tag_type then&lt;br /&gt;
				-- Throw an error because hopefully it will get noticed and fixed.&lt;br /&gt;
				-- If we just skip it, it may never get fixed.&lt;br /&gt;
				error(&amp;quot;Tag &amp;#039;&amp;quot; .. name .. &amp;quot;&amp;#039; has no tag_type&amp;quot;)&lt;br /&gt;
			end&lt;br /&gt;
			if not tab[data.tag_type] then&lt;br /&gt;
				tab[data.tag_type] = {}&lt;br /&gt;
			end&lt;br /&gt;
			table.insert(tab[data.tag_type], {name, data})&lt;br /&gt;
		end&lt;br /&gt;
		local tag_type_order_set = require(&amp;quot;Module:table&amp;quot;).listToSet(tag_type_order)&lt;br /&gt;
		for tag_type, tags_of_type in pairs(tab) do&lt;br /&gt;
			if not tag_type_order_set[tag_type] then&lt;br /&gt;
				-- See justification above for throwing an error.&lt;br /&gt;
				error(&amp;quot;Tag type &amp;#039;&amp;quot; .. tag_type .. &amp;quot;&amp;#039; not listed in tag_type_order&amp;quot;)&lt;br /&gt;
			end&lt;br /&gt;
			table.sort(tags_of_type, sort_by_first)&lt;br /&gt;
		end&lt;br /&gt;
		local multitag_shortcuts = {}&lt;br /&gt;
		local list_shortcuts = {}&lt;br /&gt;
		local function get_display_form(tags)&lt;br /&gt;
			local normtags = m_form_of.normalize_tags(tags)&lt;br /&gt;
			local display_forms = {}&lt;br /&gt;
			for _, normtag in ipairs(normtags) do&lt;br /&gt;
				table.insert(display_forms, m_form_of.get_tag_display_form(normtag))&lt;br /&gt;
			end&lt;br /&gt;
			return table.concat(display_forms, &amp;quot; &amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		for shortcut, full in pairs(data_module.shortcuts) do&lt;br /&gt;
			if type(full) == &amp;quot;table&amp;quot; then&lt;br /&gt;
				table.insert(list_shortcuts, {shortcut, get_display_form(full)})&lt;br /&gt;
			elseif full:find(&amp;quot;//&amp;quot;) then&lt;br /&gt;
				table.insert(multitag_shortcuts, {shortcut, get_display_form({full})})&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		table.sort(list_shortcuts, sort_by_first)&lt;br /&gt;
		table.sort(multitag_shortcuts, sort_by_first)&lt;br /&gt;
&lt;br /&gt;
		return tab, multitag_shortcuts, list_shortcuts&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local data_tab, data_multitag_shortcuts, data_list_shortcuts = organize_data(m_data)&lt;br /&gt;
	local data2_tab, data2_multitag_shortcuts, data2_list_shortcuts = organize_data(m_data2)&lt;br /&gt;
&lt;br /&gt;
	local parts = {}&lt;br /&gt;
&lt;br /&gt;
	local function insert_group(group)&lt;br /&gt;
		for _, namedata in ipairs(group) do&lt;br /&gt;
			local sparts = {}&lt;br /&gt;
			local name = namedata[1]&lt;br /&gt;
			local data = namedata[2]&lt;br /&gt;
			table.insert(sparts, &amp;quot;| &amp;lt;code&amp;gt;&amp;quot; .. name .. &amp;quot;&amp;lt;/code&amp;gt; || &amp;quot;)&lt;br /&gt;
			if data.shortcuts then&lt;br /&gt;
				local ssparts = {}&lt;br /&gt;
				for _, shortcut in ipairs(data.shortcuts) do&lt;br /&gt;
					table.insert(ssparts, &amp;quot;&amp;lt;code&amp;gt;&amp;quot; .. shortcut .. &amp;quot;&amp;lt;/code&amp;gt;&amp;quot;)&lt;br /&gt;
				end&lt;br /&gt;
				table.insert(sparts, table.concat(ssparts, &amp;quot;, &amp;quot;) .. &amp;quot; &amp;quot;)&lt;br /&gt;
			end&lt;br /&gt;
			table.insert(sparts, &amp;quot;|| &amp;quot; .. m_form_of.get_tag_display_form(name))&lt;br /&gt;
			table.insert(parts, &amp;quot;|-&amp;quot;)&lt;br /&gt;
			table.insert(parts, table.concat(sparts))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function insert_shortcut_group(shortcuts)&lt;br /&gt;
		for _, namedisp in ipairs(shortcuts) do&lt;br /&gt;
			local name = namedisp[1]&lt;br /&gt;
			local disp = namedisp[2]&lt;br /&gt;
			table.insert(parts, &amp;quot;|-&amp;quot;)&lt;br /&gt;
			table.insert(parts, &amp;quot;| || &amp;lt;code&amp;gt;&amp;quot; .. name .. &amp;quot;&amp;lt;/code&amp;gt; || &amp;quot; .. disp)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	table.insert(parts, &amp;#039;{|class=&amp;quot;wikitable&amp;quot;&amp;#039;)&lt;br /&gt;
	table.insert(parts, &amp;quot;! Canonical tag !! Shortcut(s) !! Display form&amp;quot;)&lt;br /&gt;
	for _, tag_type in ipairs(tag_type_order) do&lt;br /&gt;
		local group_tab = data_tab[tag_type]&lt;br /&gt;
		if group_tab then&lt;br /&gt;
			table.insert(parts, &amp;quot;|-&amp;quot;)&lt;br /&gt;
			table.insert(parts, &amp;#039;! colspan=&amp;quot;3&amp;quot; style=&amp;quot;text-align: center; background: #dddddd;&amp;quot; | &amp;#039; ..&lt;br /&gt;
				(tag_type_to_description[tag_type] or strutils.ucfirst(tag_type)) .. &amp;quot; (more common)&amp;quot;)&lt;br /&gt;
			insert_group(group_tab)&lt;br /&gt;
		end&lt;br /&gt;
		group_tab = data2_tab[tag_type]&lt;br /&gt;
		if group_tab then&lt;br /&gt;
			table.insert(parts, &amp;quot;|-&amp;quot;)&lt;br /&gt;
			table.insert(parts, &amp;#039;! colspan=&amp;quot;3&amp;quot; style=&amp;quot;text-align: center; background: #dddddd;&amp;quot; | &amp;#039; ..&lt;br /&gt;
				(tag_type_to_description[tag_type] or strutils.ucfirst(tag_type)) .. &amp;quot; (less common)&amp;quot;)&lt;br /&gt;
			insert_group(group_tab)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if #data_multitag_shortcuts &amp;gt; 0 then&lt;br /&gt;
		table.insert(parts, &amp;quot;|-&amp;quot;)&lt;br /&gt;
		table.insert(parts, &amp;#039;! colspan=&amp;quot;3&amp;quot; style=&amp;quot;text-align: center; background: #dddddd;&amp;quot; | Multitag shortcuts (more common)&amp;#039;)&lt;br /&gt;
		insert_shortcut_group(data_multitag_shortcuts)&lt;br /&gt;
	end&lt;br /&gt;
	if #data2_multitag_shortcuts &amp;gt; 0 then&lt;br /&gt;
		table.insert(parts, &amp;quot;|-&amp;quot;)&lt;br /&gt;
		table.insert(parts, &amp;#039;! colspan=&amp;quot;3&amp;quot; style=&amp;quot;text-align: center; background: #dddddd;&amp;quot; | Multitag shortcuts (less common)&amp;#039;)&lt;br /&gt;
		insert_shortcut_group(data2_multitag_shortcuts)&lt;br /&gt;
	end&lt;br /&gt;
	if #data_list_shortcuts &amp;gt; 0 then&lt;br /&gt;
		table.insert(parts, &amp;quot;|-&amp;quot;)&lt;br /&gt;
		table.insert(parts, &amp;#039;! colspan=&amp;quot;3&amp;quot; style=&amp;quot;text-align: center; background: #dddddd;&amp;quot; | List shortcuts (more common)&amp;#039;)&lt;br /&gt;
		insert_shortcut_group(data_list_shortcuts)&lt;br /&gt;
	end&lt;br /&gt;
	if #data2_list_shortcuts &amp;gt; 0 then&lt;br /&gt;
		table.insert(parts, &amp;quot;|-&amp;quot;)&lt;br /&gt;
		table.insert(parts, &amp;#039;! colspan=&amp;quot;3&amp;quot; style=&amp;quot;text-align: center; background: #dddddd;&amp;quot; | List shortcuts (less common)&amp;#039;)&lt;br /&gt;
		insert_shortcut_group(data2_list_shortcuts)&lt;br /&gt;
	end&lt;br /&gt;
	table.insert(parts, &amp;quot;|}&amp;quot;)&lt;br /&gt;
	return table.concat(parts, &amp;quot;\n&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function export.postable()&lt;br /&gt;
	m_pos = mw.loadData(&amp;quot;Module:form of/pos&amp;quot;)&lt;br /&gt;
	local shortcut_tab = {}&lt;br /&gt;
	for shortcut, full in pairs(m_pos) do&lt;br /&gt;
		if not shortcut_tab[full] then&lt;br /&gt;
			shortcut_tab[full] = {}&lt;br /&gt;
		end&lt;br /&gt;
		table.insert(shortcut_tab[full], shortcut)&lt;br /&gt;
	end&lt;br /&gt;
	local shorcut_list = {}&lt;br /&gt;
	for full, shortcuts in pairs(shortcut_tab) do&lt;br /&gt;
		table.sort(shortcuts)&lt;br /&gt;
		table.insert(shorcut_list, {full, shortcuts})&lt;br /&gt;
	end&lt;br /&gt;
	table.sort(shorcut_list, function(fs1, fs2) return fs1[1] &amp;lt; fs2[1] end)&lt;br /&gt;
&lt;br /&gt;
	local parts = {}&lt;br /&gt;
	table.insert(parts, &amp;#039;{|class=&amp;quot;wikitable&amp;quot;&amp;#039;)&lt;br /&gt;
	table.insert(parts, &amp;quot;! Canonical part of speech !! Shortcut(s)&amp;quot;)&lt;br /&gt;
	for _, full_shortcuts in ipairs(shorcut_list) do&lt;br /&gt;
		local full = full_shortcuts[1]&lt;br /&gt;
		local shortcuts = full_shortcuts[2]&lt;br /&gt;
		table.insert(parts, &amp;quot;|-&amp;quot;)&lt;br /&gt;
		local sparts = {}&lt;br /&gt;
		for _, shortcut in ipairs(shortcuts) do&lt;br /&gt;
			table.insert(sparts, &amp;quot;&amp;lt;code&amp;gt;&amp;quot; .. shortcut .. &amp;quot;&amp;lt;/code&amp;gt;&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
		table.insert(parts, &amp;quot;| &amp;lt;code&amp;gt;&amp;quot; .. full .. &amp;quot;&amp;lt;/code&amp;gt; || &amp;quot; .. table.concat(sparts, &amp;quot;, &amp;quot;))&lt;br /&gt;
	end&lt;br /&gt;
	table.insert(parts, &amp;quot;|}&amp;quot;)&lt;br /&gt;
	return table.concat(parts, &amp;quot;\n&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function export.cattable()&lt;br /&gt;
	local m_cats = mw.loadData(&amp;quot;Module:form of/cats&amp;quot;)&lt;br /&gt;
	local cats_by_lang = {}&lt;br /&gt;
	local function find_categories(catstruct)&lt;br /&gt;
		local cats = {}&lt;br /&gt;
		&lt;br /&gt;
		local function process_spec(spec)&lt;br /&gt;
			if type(spec) == &amp;quot;string&amp;quot; then&lt;br /&gt;
				table.insert(cats, spec)&lt;br /&gt;
				return&lt;br /&gt;
			elseif not spec or spec == true then&lt;br /&gt;
				return&lt;br /&gt;
			elseif type(spec) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
				error(&amp;quot;Wrong type of condition &amp;quot; .. spec .. &amp;quot;: &amp;quot; .. type(spec))&lt;br /&gt;
			end&lt;br /&gt;
			local predicate = spec[1]&lt;br /&gt;
			if predicate == &amp;quot;multi&amp;quot; or predicate == &amp;quot;cond&amp;quot; then&lt;br /&gt;
				-- WARNING! #spec doesn&amp;#039;t work for objects loaded from loadData()&lt;br /&gt;
				for i, sp in ipairs(spec) do&lt;br /&gt;
					if i &amp;gt; 1 then&lt;br /&gt;
						process_spec(sp)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			elseif predicate == &amp;quot;pexists&amp;quot; then&lt;br /&gt;
				process_spec(spec[2])&lt;br /&gt;
				process_spec(spec[3])&lt;br /&gt;
			elseif predicate == &amp;quot;has&amp;quot; or predicate == &amp;quot;hasall&amp;quot; or predicate == &amp;quot;hasany&amp;quot; or&lt;br /&gt;
				predicate == &amp;quot;tags=&amp;quot; or predicate == &amp;quot;p=&amp;quot; or predicate == &amp;quot;pany&amp;quot; or&lt;br /&gt;
				predicate == &amp;quot;not&amp;quot; then&lt;br /&gt;
				process_spec(spec[3])&lt;br /&gt;
				process_spec(spec[4])&lt;br /&gt;
			elseif predicate == &amp;quot;and&amp;quot; or predicate == &amp;quot;or&amp;quot; then&lt;br /&gt;
				process_spec(spec[3])&lt;br /&gt;
				process_spec(spec[4])&lt;br /&gt;
			elseif predicate == &amp;quot;call&amp;quot; then&lt;br /&gt;
				return&lt;br /&gt;
			else&lt;br /&gt;
				error(&amp;quot;Unrecognized predicate: &amp;quot; .. predicate)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		for _, spec in ipairs(catstruct) do&lt;br /&gt;
			process_spec(spec)&lt;br /&gt;
		end&lt;br /&gt;
		return cats&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	for lang, catspecs in pairs(m_cats) do&lt;br /&gt;
		local cats = find_categories(catspecs)&lt;br /&gt;
		table.insert(cats_by_lang, {lang, cats})&lt;br /&gt;
	end&lt;br /&gt;
	table.sort(cats_by_lang, sort_by_first)&lt;br /&gt;
	&lt;br /&gt;
	local lang_independent_cat_index = nil&lt;br /&gt;
	for i, langcats in ipairs(cats_by_lang) do&lt;br /&gt;
		local lang = langcats[1]&lt;br /&gt;
		if lang == &amp;quot;und&amp;quot; then&lt;br /&gt;
			lang_independent_cat_index = i&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if lang_independent_cat_index then&lt;br /&gt;
		local lang_independent_cats = table.remove(cats_by_lang, lang_independent_cat_index)&lt;br /&gt;
		table.insert(cats_by_lang, 1, lang_independent_cats)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local parts = {}	&lt;br /&gt;
	table.insert(parts, &amp;#039;{|class=&amp;quot;wikitable&amp;quot;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
	for i, langcats in ipairs(cats_by_lang) do&lt;br /&gt;
		local langcode = langcats[1]&lt;br /&gt;
		local cats = langcats[2]&lt;br /&gt;
		if #cats &amp;gt; 0 then&lt;br /&gt;
			if i &amp;gt; 1 then&lt;br /&gt;
				table.insert(parts, &amp;quot;|-&amp;quot;)&lt;br /&gt;
			end&lt;br /&gt;
			if langcode == &amp;quot;und&amp;quot; then&lt;br /&gt;
				table.insert(parts, &amp;#039;! style=&amp;quot;text-align: center; background: #dddddd;&amp;quot; | Language-independent&amp;#039;)&lt;br /&gt;
			else&lt;br /&gt;
				local lang = m_languages.getByCode(langcode) or error(&amp;quot;Unrecognized language code: &amp;quot; .. langcode)&lt;br /&gt;
				table.insert(parts, &amp;#039;! style=&amp;quot;text-align: center; background: #dddddd;&amp;quot; | &amp;#039; .. lang:getCanonicalName())&lt;br /&gt;
			end&lt;br /&gt;
			for _, cat in ipairs(cats) do&lt;br /&gt;
				table.insert(parts, &amp;quot;|-&amp;quot;)&lt;br /&gt;
				table.insert(parts, &amp;quot;| &amp;lt;code&amp;gt;&amp;quot; .. cat .. &amp;quot;&amp;lt;/code&amp;gt;&amp;quot;)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	table.insert(parts, &amp;quot;|}&amp;quot;)&lt;br /&gt;
	return table.concat(parts, &amp;quot;\n&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return export&lt;br /&gt;
&lt;br /&gt;
-- For Vim, so we get 4-space tabs&lt;br /&gt;
-- vim: set ts=4 sw=4 noet:&lt;/div&gt;</summary>
		<author><name>Sware</name></author>
	</entry>
</feed>