<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://test.st34an.tech/index.php?action=history&amp;feed=atom&amp;title=Module%3AAffix%2Ftemplates</id>
	<title>Module:Affix/templates - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://test.st34an.tech/index.php?action=history&amp;feed=atom&amp;title=Module%3AAffix%2Ftemplates"/>
	<link rel="alternate" type="text/html" href="https://test.st34an.tech/index.php?title=Module:Affix/templates&amp;action=history"/>
	<updated>2026-04-10T17:51:08Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.45.3</generator>
	<entry>
		<id>https://test.st34an.tech/index.php?title=Module:Affix/templates&amp;diff=585&amp;oldid=prev</id>
		<title>Jsrs701: 1 revision imported</title>
		<link rel="alternate" type="text/html" href="https://test.st34an.tech/index.php?title=Module:Affix/templates&amp;diff=585&amp;oldid=prev"/>
		<updated>2026-04-10T07:29:55Z</updated>

		<summary type="html">&lt;p&gt;1 revision imported&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 07:29, 10 April 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;4&quot; class=&quot;diff-notice&quot; lang=&quot;en&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(No difference)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;!-- diff cache key mediawikidb:diff:1.41:old-584:rev-585 --&gt;
&lt;/table&gt;</summary>
		<author><name>Jsrs701</name></author>
	</entry>
	<entry>
		<id>https://test.st34an.tech/index.php?title=Module:Affix/templates&amp;diff=584&amp;oldid=prev</id>
		<title>bob&gt;Juelos at 09:47, 26 September 2023</title>
		<link rel="alternate" type="text/html" href="https://test.st34an.tech/index.php?title=Module:Affix/templates&amp;diff=584&amp;oldid=prev"/>
		<updated>2023-09-26T09:47:32Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local export = {}&lt;br /&gt;
&lt;br /&gt;
local m_affix = require(&amp;quot;Module:affix&amp;quot;)&lt;br /&gt;
local m_languages = require(&amp;quot;Module:languages&amp;quot;)&lt;br /&gt;
local pseudo_loan_module = &amp;quot;Module:affix/pseudo-loan&amp;quot;&lt;br /&gt;
local put -- initialized once, when needed, to require(&amp;quot;Module:parse utilities&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
local rsplit = mw.text.split&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Per-param modifiers, which can be specified either as separate parameters (e.g. t2=, pos3=) or as inline modifiers&lt;br /&gt;
-- &amp;lt;t:...&amp;gt;, &amp;lt;pos:...&amp;gt;, etc. The key is the name fo the parameter (e.g. &amp;quot;t&amp;quot;, &amp;quot;pos&amp;quot;) and the value is a table with&lt;br /&gt;
-- elements as follows:&lt;br /&gt;
-- * `extra_specs`: An optional table of extra key-value pairs to add to the spec used for parsing the parameter&lt;br /&gt;
--                  when specified as a separate parameter (e.g. {type = &amp;quot;boolean&amp;quot;} for a Boolean parameter, or&lt;br /&gt;
--                  {alias_of = &amp;quot;t&amp;quot;} for the &amp;quot;gloss&amp;quot; parameter, which is aliased to &amp;quot;t&amp;quot;), on top of the default, which&lt;br /&gt;
--                  is {list = true, allow_holes = true, require_index = true}.&lt;br /&gt;
-- * `convert`: An optional function to convert the raw argument into the form passed to [[Module:affix]].&lt;br /&gt;
--              This function takes four parameters: (1) `arg` (the raw argument); (2) `inline` (true if we&amp;#039;re&lt;br /&gt;
--              processing an inline modifier, false otherwise); (3) `term_index` (the actual index of the first term);&lt;br /&gt;
--              (4) `i` (the logical index of the term being processed, starting from 1).&lt;br /&gt;
-- * `item_dest`: The name of the key used when storing the parameter&amp;#039;s value into the processed `parts` list.&lt;br /&gt;
--                Normally the same as the parameter&amp;#039;s name. Different in the case of &amp;quot;t&amp;quot;, where we store the gloss in&lt;br /&gt;
--                &amp;quot;gloss&amp;quot;, and &amp;quot;g&amp;quot;, where we store the genders in &amp;quot;genders&amp;quot;.&lt;br /&gt;
-- * `param_key`: The name of the key used in the `params` spec passed to [[Module:parameters]]. Normally the same as&lt;br /&gt;
--                the parameter&amp;#039;s name. Different in the case of &amp;quot;lit&amp;quot;, &amp;quot;sc&amp;quot;, etc. where e.g. we distinguish per-term&lt;br /&gt;
--                parameters &amp;quot;lit1&amp;quot;, &amp;quot;lit2&amp;quot;, etc. from the overall parameter &amp;quot;lit&amp;quot;.&lt;br /&gt;
local param_mods = {&lt;br /&gt;
	t = {&lt;br /&gt;
		-- We need to store the t1=/t2= param and the &amp;lt;t:...&amp;gt; inline modifier into the &amp;quot;gloss&amp;quot; key of the parsed part,&lt;br /&gt;
		-- because that is what [[Module:affix]] expects.&lt;br /&gt;
		item_dest = &amp;quot;gloss&amp;quot;,&lt;br /&gt;
	},&lt;br /&gt;
	gloss = {&lt;br /&gt;
		-- The `extra_specs` handles the fact that &amp;quot;gloss&amp;quot; is an alias of &amp;quot;t&amp;quot;.&lt;br /&gt;
		extra_specs = {alias_of = &amp;quot;t&amp;quot;},&lt;br /&gt;
	},&lt;br /&gt;
	tr = {},&lt;br /&gt;
	ts = {},&lt;br /&gt;
	g = {&lt;br /&gt;
		-- We need to store the g1=/g2= param and the &amp;lt;g:...&amp;gt; inline modifier into the &amp;quot;genders&amp;quot; key of the parsed part,&lt;br /&gt;
		-- because that is what [[Module:affix]] expects.&lt;br /&gt;
		item_dest = &amp;quot;genders&amp;quot;,&lt;br /&gt;
		convert = function(arg, inline, term_index, i)&lt;br /&gt;
			return rsplit(arg, &amp;quot;,&amp;quot;)&lt;br /&gt;
		end,&lt;br /&gt;
	},&lt;br /&gt;
	id = {},&lt;br /&gt;
	alt = {},&lt;br /&gt;
	q = {},&lt;br /&gt;
	qq = {},&lt;br /&gt;
	lit = {&lt;br /&gt;
		-- lit1=, lit2=, ... are different from lit=; the former describe the literal meaning of an individual argument&lt;br /&gt;
		-- while the latter applies to the expression as a whole and appears after them at the end. To handle this in&lt;br /&gt;
		-- separate parameters, we need to set the key in the `params` object passed to [[Module:parameters]] to&lt;br /&gt;
		-- something else (in this case &amp;quot;partlit&amp;quot;) and set `list = &amp;quot;lit&amp;quot;` in the value of the `params` object. This&lt;br /&gt;
		-- causes [[Module:parameters]] to fetch parameters named lit1=, lit2= etc. but store them into &amp;quot;partlit&amp;quot;, while&lt;br /&gt;
		-- lit= is stored into &amp;quot;lit&amp;quot;.&lt;br /&gt;
		param_key = &amp;quot;partlit&amp;quot;,&lt;br /&gt;
		extra_specs = {list = &amp;quot;lit&amp;quot;},&lt;br /&gt;
	},&lt;br /&gt;
	pos = {&lt;br /&gt;
		-- pos1=, pos2=, ... are different from pos=; the former indicate the part of speech of an individual argument&lt;br /&gt;
		-- and appear in parens after the term (similar to the pos= argument to {{l}}), while the latter applies to the&lt;br /&gt;
		-- expression as a whole and controls the names of various categories. We handle the distinction identically to&lt;br /&gt;
		-- lit1= etc. vs. lit=; see above.&lt;br /&gt;
		param_key = &amp;quot;partpos&amp;quot;,&lt;br /&gt;
		extra_specs = {list = &amp;quot;pos&amp;quot;},&lt;br /&gt;
	},&lt;br /&gt;
	lang = {&lt;br /&gt;
		-- lang1=, lang2=, ... are different from 1=; the former set the language of individual arguments that are&lt;br /&gt;
		-- different from the overall language specified in 1=. Note that the preferred way of specifying a different&lt;br /&gt;
		-- language for a given individual argument is using a language-code prefix, e.g. &amp;#039;la:minūtia&amp;#039; or&lt;br /&gt;
		-- &amp;#039;grc:[[σκῶρ|σκατός]]&amp;#039;, instead of using langN=. Since for compatibility purposes we may support lang= as&lt;br /&gt;
		-- a synonym of 1=, we can&amp;#039;t store langN= in &amp;quot;lang&amp;quot;. Instead we do the same as for lit1= etc. vs. lit= above.&lt;br /&gt;
		-- In addition, we need a conversion function to convert from language codes to language objects, which needs&lt;br /&gt;
		-- to conditionalize the `param` parameter of `getByCode` of [[Module:languages]] on whether the param is&lt;br /&gt;
		-- inline. (This only affects the error message.)&lt;br /&gt;
		param_key = &amp;quot;partlang&amp;quot;,&lt;br /&gt;
		extra_specs = {list = &amp;quot;lang&amp;quot;},&lt;br /&gt;
		convert = function(arg, inline, term_index, i)&lt;br /&gt;
			-- term_index + i - 1 because we want to reference the actual term param name, which offsets from&lt;br /&gt;
			-- `term_index` (the index of the first term); subtract 1 since i is one-based.&lt;br /&gt;
			return m_languages.getByCode(arg, inline and &amp;quot;&amp;quot; .. (term_index + i - 1) .. &amp;quot;:lang&amp;quot; or &amp;quot;lang&amp;quot; .. i, &amp;quot;allow etym&amp;quot;)&lt;br /&gt;
		end,&lt;br /&gt;
	},&lt;br /&gt;
	sc = {&lt;br /&gt;
		-- sc1=, sc2=, ... are different from sc=; the former apply to individual arguments when lang1=, lang2=, ...&lt;br /&gt;
		-- is specified, while the latter applies to all arguments where langN=... isn&amp;#039;t specified. We handle the&lt;br /&gt;
		-- distinction identically to lit1= etc. vs. lit=; see above. In addition, we need a conversion function to&lt;br /&gt;
		-- convert from script codes to script objects, which needs to conditionalize the `param` parameter of&lt;br /&gt;
		-- `getByCode` of [[Module:scripts]] on whether the param is inline. (This only affects the error message.)&lt;br /&gt;
		param_key = &amp;quot;partsc&amp;quot;,&lt;br /&gt;
		extra_specs = {list = &amp;quot;sc&amp;quot;},&lt;br /&gt;
		convert = function(arg, inline, term_index, i)&lt;br /&gt;
			-- term_index + i - 1 same as above for &amp;quot;lang&amp;quot;.&lt;br /&gt;
			return require(&amp;quot;Module:scripts&amp;quot;).getByCode(arg, inline and &amp;quot;&amp;quot; .. (term_index + i - 1) .. &amp;quot;:sc&amp;quot; or &amp;quot;sc&amp;quot; .. i)&lt;br /&gt;
		end,&lt;br /&gt;
	},&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function get_valid_prefixes()&lt;br /&gt;
	local valid_prefixes = {}&lt;br /&gt;
	for param_mod, _ in pairs(param_mods) do&lt;br /&gt;
		table.insert(valid_prefixes, param_mod)&lt;br /&gt;
	end&lt;br /&gt;
	table.sort(valid_prefixes)&lt;br /&gt;
	return valid_prefixes&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function fetch_script(sc, param)&lt;br /&gt;
	return sc and require(&amp;quot;Module:scripts&amp;quot;).getByCode(sc, param) or nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Parse raw arguments in `args`. If `extra_params` is specified, it should be a one-argument function that is called&lt;br /&gt;
-- on the `params` structure before parsing; its purpose is to specify additional allowed parameters or possibly disable&lt;br /&gt;
-- parameters. If `has_source` is given, there is a source-language parameter following 1= (which becomes the&lt;br /&gt;
-- &amp;quot;destination&amp;quot; language parameter) and preceding the terms. This is currently used for {{pseudo-loan}}. The&lt;br /&gt;
-- source-language parameter is allowed to be an etymology-only language while the language in 1= is currently not so&lt;br /&gt;
-- allowed (FIXME: should we change this?). Returns five values ARGS, TERM_INDEX, LANG_OBJ, SCRIPT_OBJ, SOURCE_LANG_OBJ&lt;br /&gt;
-- where ARGS is a table of the parsed arguments; TERM_INDEX is the argument containing all the terms; LANG_OBJ is the&lt;br /&gt;
-- language object corresponding to the language code specified in 1=; SCRIPT_OBJ is the script object corresponding to&lt;br /&gt;
-- sc= (if given, otherwise nil); and SOURCE_LANG_OBJ is the language object corresponding to the source-language code&lt;br /&gt;
-- specified in 2= if `has_source` is specified (otherwise nil).&lt;br /&gt;
local function parse_args(args, extra_params, has_source, ilangcode)&lt;br /&gt;
	if args.lang then&lt;br /&gt;
		error(&amp;quot;The |lang= parameter is not used by this template. Place the language code in parameter 1 instead.&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local term_index = (ilangcode and 1 or 2) + (has_source and 1 or 0)&lt;br /&gt;
	local params = {&lt;br /&gt;
		[term_index] = {list = true, allow_holes = true},&lt;br /&gt;
&lt;br /&gt;
		[&amp;quot;lit&amp;quot;] = {},&lt;br /&gt;
		[&amp;quot;sc&amp;quot;] = {},&lt;br /&gt;
		[&amp;quot;pos&amp;quot;] = {},&lt;br /&gt;
		[&amp;quot;sort&amp;quot;] = {},&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if not ilangcode then&lt;br /&gt;
		params[1] = {required = true, default = &amp;quot;und&amp;quot;}&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local source_index&lt;br /&gt;
	if has_source then&lt;br /&gt;
		source_index = term_index - 1&lt;br /&gt;
		params[source_index] = {required = true, default = &amp;quot;und&amp;quot;}&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local default_param_spec = {list = true, allow_holes = true, require_index = true}&lt;br /&gt;
	for param_mod, param_mod_spec in pairs(param_mods) do&lt;br /&gt;
		local param_key = param_mod_spec.param_key or param_mod&lt;br /&gt;
		if not param_mod_spec.extra_specs then&lt;br /&gt;
			params[param_key] = default_param_spec&lt;br /&gt;
		else&lt;br /&gt;
			local param_spec = mw.clone(default_param_spec)&lt;br /&gt;
			for k, v in pairs(param_mod_spec.extra_specs) do&lt;br /&gt;
				param_spec[k] = v&lt;br /&gt;
			end&lt;br /&gt;
			params[param_key] = param_spec&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if extra_params then&lt;br /&gt;
		extra_params(params)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	args = require(&amp;quot;Module:parameters&amp;quot;).process(args, params)&lt;br /&gt;
	local lang&lt;br /&gt;
	if ilangcode then&lt;br /&gt;
		lang = m_languages.getByCode(ilangcode, true)&lt;br /&gt;
	else&lt;br /&gt;
		lang = m_languages.getByCode(args[1], 1)&lt;br /&gt;
	end&lt;br /&gt;
	local source&lt;br /&gt;
	if has_source then&lt;br /&gt;
		source = m_languages.getByCode(args[source_index], source_index, &amp;quot;allow etym&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	return args, term_index, lang, fetch_script(args[&amp;quot;sc&amp;quot;], &amp;quot;sc&amp;quot;), source&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Return an object containing all the properties of the `i`th term. `template` is the name of the calling template&lt;br /&gt;
-- (used only in the debug-tracking mechanism). `args` is the arguments as returned by parse_args(). `term_index` is&lt;br /&gt;
-- the argument containing all the terms. This handles all the complexities of fetching all the properties associated&lt;br /&gt;
-- with a term either out of separate parameters (e.g. pos3=, g2=) or from inline modifiers (e.g.&lt;br /&gt;
-- &amp;#039;term&amp;lt;pos:noun&amp;gt;&amp;lt;g:m-p&amp;gt;&amp;#039;). It also handles parsing off a separate language code attached to the beginning of a term or&lt;br /&gt;
-- specified using langN= or &amp;lt;lang:CODE&amp;gt;.&lt;br /&gt;
local function get_parsed_part(template, args, term_index, i)&lt;br /&gt;
	local part = {}&lt;br /&gt;
	local term = args[term_index][i]&lt;br /&gt;
&lt;br /&gt;
	if not (term or args[&amp;quot;alt&amp;quot;][i] or args[&amp;quot;tr&amp;quot;][i] or args[&amp;quot;ts&amp;quot;][i]) then&lt;br /&gt;
		require(&amp;quot;Module:debug/track&amp;quot;)(template .. &amp;quot;/no term or alt or tr&amp;quot;)&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Parse all the term-specific parameters and store in `part`.&lt;br /&gt;
	for param_mod, param_mod_spec in pairs(param_mods) do&lt;br /&gt;
		local dest = param_mod_spec.item_dest or param_mod&lt;br /&gt;
		local param_key = param_mod_spec.param_key or param_mod&lt;br /&gt;
		local arg = args[param_key][i]&lt;br /&gt;
		if arg then&lt;br /&gt;
			if param_mod_spec.convert then&lt;br /&gt;
				arg = param_mod_spec.convert(arg, false, term_index, i)&lt;br /&gt;
			end&lt;br /&gt;
			part[dest] = arg&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Remove and remember an initial exclamation point from the term, and parse off an initial language code (e.g.&lt;br /&gt;
	-- &amp;#039;la:minūtia&amp;#039; or &amp;#039;grc:[[σκῶρ|σκατός]]&amp;#039;).&lt;br /&gt;
	if term then&lt;br /&gt;
		local termlang, actual_term = term:match(&amp;quot;^([A-Za-z0-9._-]+):(.*)$&amp;quot;)&lt;br /&gt;
		if termlang and termlang ~= &amp;quot;w&amp;quot; then -- special handling for w:... links to Wikipedia&lt;br /&gt;
			-- -1 since i is one-based&lt;br /&gt;
			termlang = m_languages.getByCode(termlang, term_index + i - 1, &amp;quot;allow etym&amp;quot;)&lt;br /&gt;
			term = actual_term&lt;br /&gt;
		else&lt;br /&gt;
			termlang = nil&lt;br /&gt;
		end&lt;br /&gt;
		if part.lang and termlang then&lt;br /&gt;
			error((&amp;quot;Both lang%s= and a language in %s= given; specify one or the other&amp;quot;):format(i, i + 1))&lt;br /&gt;
		end&lt;br /&gt;
		part.lang = part.lang or termlang&lt;br /&gt;
		part.term = term&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Check for inline modifier, e.g. מרים&amp;lt;tr:Miryem&amp;gt;. But exclude HTML entry with &amp;lt;span ...&amp;gt;, &amp;lt;i ...&amp;gt;, &amp;lt;br/&amp;gt; or&lt;br /&gt;
	-- similar in it, caused by wrapping an argument in {{l|...}}, {{af|...}} or similar. Basically, all tags of&lt;br /&gt;
	-- the sort we parse here should consist of a less-than sign, plus letters, plus a colon, e.g. &amp;lt;tr:...&amp;gt;, so if&lt;br /&gt;
	-- we see a tag on the outer level that isn&amp;#039;t in this format, we don&amp;#039;t try to parse it. The restriction to the&lt;br /&gt;
	-- outer level is to allow generated HTML inside of e.g. qualifier tags, such as foo&amp;lt;q:similar to {{m|fr|bar}}&amp;gt;.&lt;br /&gt;
	if term and term:find(&amp;quot;&amp;lt;&amp;quot;) and not term:find(&amp;quot;^[^&amp;lt;]*&amp;lt;[a-z]*[^a-z:]&amp;quot;) then&lt;br /&gt;
		if not put then&lt;br /&gt;
			put = require(&amp;quot;Module:parse utilities&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
		local run = put.parse_balanced_segment_run(term, &amp;quot;&amp;lt;&amp;quot;, &amp;quot;&amp;gt;&amp;quot;)&lt;br /&gt;
		local function parse_err(msg)&lt;br /&gt;
			error(msg .. &amp;quot;: &amp;quot; .. (i + 1) .. &amp;quot;=&amp;quot; .. table.concat(run))&lt;br /&gt;
		end&lt;br /&gt;
		part.term = run[1]&lt;br /&gt;
&lt;br /&gt;
		for j = 2, #run - 1, 2 do&lt;br /&gt;
			if run[j + 1] ~= &amp;quot;&amp;quot; then&lt;br /&gt;
				parse_err(&amp;quot;Extraneous text &amp;#039;&amp;quot; .. run[j + 1] .. &amp;quot;&amp;#039; after modifier&amp;quot;)&lt;br /&gt;
			end&lt;br /&gt;
			local modtext = run[j]:match(&amp;quot;^&amp;lt;(.*)&amp;gt;$&amp;quot;)&lt;br /&gt;
			if not modtext then&lt;br /&gt;
				parse_err(&amp;quot;Internal error: Modifier &amp;#039;&amp;quot; .. modtext .. &amp;quot;&amp;#039; isn&amp;#039;t surrounded by angle brackets&amp;quot;)&lt;br /&gt;
			end&lt;br /&gt;
			local prefix, arg = modtext:match(&amp;quot;^([a-z]+):(.*)$&amp;quot;)&lt;br /&gt;
			if not prefix then&lt;br /&gt;
				parse_err((&amp;quot;Modifier %s lacks a prefix, should begin with one of %s followed by a colon&amp;quot;):format(&lt;br /&gt;
					run[j], table.concat(get_valid_prefixes(), &amp;quot;,&amp;quot;)))&lt;br /&gt;
			end&lt;br /&gt;
			if not param_mods[prefix] then&lt;br /&gt;
				parse_err((&amp;quot;Unrecognized prefix &amp;#039;%s&amp;#039; in modifier %s, should be one of %s&amp;quot;):format(&lt;br /&gt;
					prefix, run[j], table.concat(get_valid_prefixes(), &amp;quot;,&amp;quot;)))&lt;br /&gt;
			end&lt;br /&gt;
			local dest = param_mods[prefix].item_dest or prefix&lt;br /&gt;
			if part[dest] then&lt;br /&gt;
				parse_err(&amp;quot;Modifier &amp;#039;&amp;quot; .. prefix .. &amp;quot;&amp;#039; occurs twice, second occurrence &amp;quot; .. run[j])&lt;br /&gt;
			end&lt;br /&gt;
			if param_mods[prefix].convert then&lt;br /&gt;
				arg = param_mods[prefix].convert(arg, true, term_index, i)&lt;br /&gt;
			end&lt;br /&gt;
			part[dest] = arg&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return part&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Return an array of objects describing all the terms specified by the user. The meat of the work is done by&lt;br /&gt;
-- get_parsed_part(). `template`, `args` and `term_index` are as in get_parsed_part() and are required. Optional&lt;br /&gt;
-- `max_terms_allowed` restricts the number of terms that can be specified, and optional `start_index` specifies the&lt;br /&gt;
-- first index in the user-specified terms under the `term_index` argument to pull terms out of, defaulting to 1.&lt;br /&gt;
-- Currently only suffix() specifies a value for `start_index`, because the first term is handled differently by&lt;br /&gt;
-- suffix() compared with all the remaining terms.&lt;br /&gt;
local function get_parsed_parts(template, args, term_index, max_terms_allowed, start_index)&lt;br /&gt;
	local parts = {}&lt;br /&gt;
	start_index = start_index or 1&lt;br /&gt;
&lt;br /&gt;
	-- Find the maximum index among any of the list parameters.&lt;br /&gt;
	local maxmaxindex = 0&lt;br /&gt;
	for k, v in pairs(args) do&lt;br /&gt;
		if type(v) == &amp;quot;table&amp;quot; and v.maxindex and v.maxindex &amp;gt; maxmaxindex then&lt;br /&gt;
			if max_terms_allowed and v.maxindex &amp;gt; max_terms_allowed then&lt;br /&gt;
				-- Try to determine the original parameter name associated with v.maxindex.&lt;br /&gt;
				if type(k) == &amp;quot;number&amp;quot; then&lt;br /&gt;
					-- Subtract one because e.g. if terms start at 2, the 4th term is in 5=.&lt;br /&gt;
					arg = k + v.maxindex - 1&lt;br /&gt;
				else&lt;br /&gt;
					arg = k .. v.maxindex&lt;br /&gt;
				end&lt;br /&gt;
				error((&amp;quot;In [[Template:%s|%s]], at most %s terms can be specified but argument %s specified, corresponding to term #%s&amp;quot;)&lt;br /&gt;
					:format(template, template, max_terms_allowed, arg, v.maxindex))&lt;br /&gt;
			end&lt;br /&gt;
			maxmaxindex = v.maxindex&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	for index = start_index, maxmaxindex do&lt;br /&gt;
		local part = get_parsed_part(template, args, term_index, index)&lt;br /&gt;
		parts[index - start_index + 1] = part&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return parts&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function export.affix(frame)&lt;br /&gt;
	local function extra_params(params)&lt;br /&gt;
		params[&amp;quot;type&amp;quot;] = {}&lt;br /&gt;
		params[&amp;quot;nocap&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;notext&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;nocat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;force_cat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local args, term_index, lang, sc = parse_args(frame:getParent().args, extra_params)&lt;br /&gt;
&lt;br /&gt;
	if args[&amp;quot;type&amp;quot;] and not m_affix.compound_types[args[&amp;quot;type&amp;quot;]] then&lt;br /&gt;
		error(&amp;quot;Unrecognized compound type: &amp;#039;&amp;quot; .. args[&amp;quot;type&amp;quot;] .. &amp;quot;&amp;#039;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local parts = get_parsed_parts(&amp;quot;affix&amp;quot;, args, term_index)&lt;br /&gt;
&lt;br /&gt;
	-- There must be at least one part to display. If there are gaps, a term&lt;br /&gt;
	-- request will be shown.&lt;br /&gt;
	if not next(parts) and not args[&amp;quot;type&amp;quot;] then&lt;br /&gt;
		if mw.title.getCurrentTitle().nsText == &amp;quot;Template&amp;quot; then&lt;br /&gt;
			parts = { {term = &amp;quot;prefix-&amp;quot;}, {term = &amp;quot;base&amp;quot;}, {term = &amp;quot;-suffix&amp;quot;} }&lt;br /&gt;
		else&lt;br /&gt;
			error(&amp;quot;You must provide at least one part.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return m_affix.show_affix {&lt;br /&gt;
		lang = lang, sc = sc, parts = parts, pos = args[&amp;quot;pos&amp;quot;], sort_key = args[&amp;quot;sort&amp;quot;], type = args[&amp;quot;type&amp;quot;],&lt;br /&gt;
		nocap = args[&amp;quot;nocap&amp;quot;], notext = args[&amp;quot;notext&amp;quot;], nocat = args[&amp;quot;nocat&amp;quot;], lit = args[&amp;quot;lit&amp;quot;],&lt;br /&gt;
		force_cat = args[&amp;quot;force_cat&amp;quot;]&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function export.compound(frame)&lt;br /&gt;
	local function extra_params(params)&lt;br /&gt;
		params[&amp;quot;type&amp;quot;] = {}&lt;br /&gt;
		params[&amp;quot;nocap&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;notext&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;nocat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;force_cat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local args, term_index, lang, sc = parse_args(frame:getParent().args, extra_params)&lt;br /&gt;
&lt;br /&gt;
	if args[&amp;quot;type&amp;quot;] and not m_affix.compound_types[args[&amp;quot;type&amp;quot;]] then&lt;br /&gt;
		error(&amp;quot;Unrecognized compound type: &amp;#039;&amp;quot; .. args[&amp;quot;type&amp;quot;] .. &amp;quot;&amp;#039;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local parts = get_parsed_parts(&amp;quot;compound&amp;quot;, args, term_index)&lt;br /&gt;
&lt;br /&gt;
	-- There must be at least one part to display. If there are gaps, a term&lt;br /&gt;
	-- request will be shown.&lt;br /&gt;
	if not next(parts) and not args[&amp;quot;type&amp;quot;] then&lt;br /&gt;
		if mw.title.getCurrentTitle().nsText == &amp;quot;Template&amp;quot; then&lt;br /&gt;
			parts = { {term = &amp;quot;first&amp;quot;}, {term = &amp;quot;second&amp;quot;} }&lt;br /&gt;
		else&lt;br /&gt;
			error(&amp;quot;You must provide at least one part of a compound.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return m_affix.show_compound {&lt;br /&gt;
		lang = lang, sc = sc, parts = parts, pos = args[&amp;quot;pos&amp;quot;], sort_key = args[&amp;quot;sort&amp;quot;], type = args[&amp;quot;type&amp;quot;],&lt;br /&gt;
		nocap = args[&amp;quot;nocap&amp;quot;], notext = args[&amp;quot;notext&amp;quot;], nocat = args[&amp;quot;nocat&amp;quot;], lit = args[&amp;quot;lit&amp;quot;],&lt;br /&gt;
		force_cat = args[&amp;quot;force_cat&amp;quot;]&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function export.compound_like(frame)&lt;br /&gt;
	local iparams = {&lt;br /&gt;
		[&amp;quot;lang&amp;quot;] = {},&lt;br /&gt;
		[&amp;quot;template&amp;quot;] = {},&lt;br /&gt;
		[&amp;quot;text&amp;quot;] = {},&lt;br /&gt;
		[&amp;quot;oftext&amp;quot;] = {},&lt;br /&gt;
		[&amp;quot;cat&amp;quot;] = {},&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local iargs = require(&amp;quot;Module:parameters&amp;quot;).process(frame.args, iparams, nil, &amp;quot;affix/templates&amp;quot;, &amp;quot;compound_like&amp;quot;)&lt;br /&gt;
	local parent_args = frame:getParent().args&lt;br /&gt;
&lt;br /&gt;
	local function extra_params(params)&lt;br /&gt;
		params[&amp;quot;pos&amp;quot;] = nil&lt;br /&gt;
		params[&amp;quot;nocap&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;notext&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;nocat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;force_cat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local args, term_index, lang, sc = parse_args(parent_args, extra_params, nil, iargs.lang)&lt;br /&gt;
&lt;br /&gt;
	local template = iargs[&amp;quot;template&amp;quot;]&lt;br /&gt;
	local nocat = args[&amp;quot;nocat&amp;quot;]&lt;br /&gt;
	local notext = args[&amp;quot;notext&amp;quot;]&lt;br /&gt;
	local text = not notext and iargs[&amp;quot;text&amp;quot;]&lt;br /&gt;
	local oftext = not notext and (iargs[&amp;quot;oftext&amp;quot;] or text and &amp;quot;of&amp;quot;)&lt;br /&gt;
	local cat = not nocat and iargs[&amp;quot;cat&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
	local parts = get_parsed_parts(template, args, term_index)&lt;br /&gt;
&lt;br /&gt;
	if not next(parts) then&lt;br /&gt;
		if mw.title.getCurrentTitle().nsText == &amp;quot;Template&amp;quot; then&lt;br /&gt;
			parts = { {term = &amp;quot;first&amp;quot;}, {term = &amp;quot;second&amp;quot;} }&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return m_affix.show_compound_like {&lt;br /&gt;
		lang = lang, sc = sc, parts = parts, sort_key = args[&amp;quot;sort&amp;quot;], text = text, oftext = oftext, cat = cat,&lt;br /&gt;
		nocat = args[&amp;quot;nocat&amp;quot;], lit = args[&amp;quot;lit&amp;quot;], force_cat = args[&amp;quot;force_cat&amp;quot;]&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function export.surface_analysis(frame)&lt;br /&gt;
	local function ine(arg)&lt;br /&gt;
		-- Since we&amp;#039;re operating before calling [[Module:parameters]], we need to imitate how that module processes arguments,&lt;br /&gt;
		-- including trimming since numbered arguments don&amp;#039;t have automatic whitespace trimming.&lt;br /&gt;
		if not arg then&lt;br /&gt;
			return arg&lt;br /&gt;
		end&lt;br /&gt;
		arg = mw.text.trim(arg)&lt;br /&gt;
		if arg == &amp;quot;&amp;quot; then&lt;br /&gt;
			arg = nil&lt;br /&gt;
		end&lt;br /&gt;
		return arg&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local parent_args = frame:getParent().args&lt;br /&gt;
	local etymtext&lt;br /&gt;
	local arg1 = ine(parent_args[1])&lt;br /&gt;
	if not arg1 then&lt;br /&gt;
		-- Allow omitted first argument to just display &amp;quot;By surface analysis&amp;quot;.&lt;br /&gt;
		etymtext = &amp;quot;&amp;quot;&lt;br /&gt;
	elseif arg1:find(&amp;quot;^%+&amp;quot;) then&lt;br /&gt;
		-- If the first argument (normally a language code) is prefixed with a +, it&amp;#039;s a template name.&lt;br /&gt;
		local template_name = arg1:sub(2)&lt;br /&gt;
		local new_args = {}&lt;br /&gt;
		for i, v in pairs(parent_args) do&lt;br /&gt;
			if type(i) == &amp;quot;number&amp;quot; then&lt;br /&gt;
				if i &amp;gt; 1 then&lt;br /&gt;
					new_args[i - 1] = v&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				new_args[i] = v&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		new_args.nocap = true&lt;br /&gt;
		etymtext = &amp;quot;, &amp;quot; .. frame:expandTemplate { title = template_name, args = new_args }&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if etymtext then&lt;br /&gt;
		return (ine(parent_args.nocap) and &amp;quot;b&amp;quot; or &amp;quot;B&amp;quot;) .. &amp;quot;y [[Appendix:Glossary#surface analysis|surface analysis]]&amp;quot; .. etymtext&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function extra_params(params)&lt;br /&gt;
		params[&amp;quot;type&amp;quot;] = {}&lt;br /&gt;
		params[&amp;quot;nocap&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;notext&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;nocat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;force_cat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local args, term_index, lang, sc = parse_args(parent_args, extra_params)&lt;br /&gt;
&lt;br /&gt;
	if args[&amp;quot;type&amp;quot;] and not m_affix.compound_types[args[&amp;quot;type&amp;quot;]] then&lt;br /&gt;
		error(&amp;quot;Unrecognized compound type: &amp;#039;&amp;quot; .. args[&amp;quot;type&amp;quot;] .. &amp;quot;&amp;#039;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local parts = get_parsed_parts(&amp;quot;surface analysis&amp;quot;, args, term_index)&lt;br /&gt;
&lt;br /&gt;
	-- There must be at least one part to display. If there are gaps, a term&lt;br /&gt;
	-- request will be shown.&lt;br /&gt;
	if not next(parts) then&lt;br /&gt;
		if mw.title.getCurrentTitle().nsText == &amp;quot;Template&amp;quot; then&lt;br /&gt;
			parts = { {term = &amp;quot;first&amp;quot;}, {term = &amp;quot;second&amp;quot;} }&lt;br /&gt;
		else&lt;br /&gt;
			error(&amp;quot;You must provide at least one part.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return m_affix.show_surface_analysis {&lt;br /&gt;
		lang = lang, sc = sc, parts = parts, pos = args[&amp;quot;pos&amp;quot;], sort_key = args[&amp;quot;sort&amp;quot;], type = args[&amp;quot;type&amp;quot;],&lt;br /&gt;
		nocap = args[&amp;quot;nocap&amp;quot;], notext = args[&amp;quot;notext&amp;quot;], nocat = args[&amp;quot;nocat&amp;quot;], lit = args[&amp;quot;lit&amp;quot;],&lt;br /&gt;
		force_cat = args[&amp;quot;force_cat&amp;quot;]&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function export.circumfix(frame)&lt;br /&gt;
	local function extra_params(params)&lt;br /&gt;
		params[&amp;quot;nocat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;force_cat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local args, term_index, lang, sc = parse_args(frame:getParent().args, extra_params)&lt;br /&gt;
&lt;br /&gt;
	local parts = get_parsed_parts(&amp;quot;circumfix&amp;quot;, args, term_index, 3)&lt;br /&gt;
	local prefix = parts[1]&lt;br /&gt;
	local base = parts[2]&lt;br /&gt;
	local suffix = parts[3]&lt;br /&gt;
&lt;br /&gt;
	-- Just to make sure someone didn&amp;#039;t use the template in a silly way&lt;br /&gt;
	if not (prefix and base and suffix) then&lt;br /&gt;
		if mw.title.getCurrentTitle().nsText == &amp;quot;Template&amp;quot; then&lt;br /&gt;
			prefix = {term = &amp;quot;circumfix&amp;quot;, alt = &amp;quot;prefix&amp;quot;}&lt;br /&gt;
			base = {term = &amp;quot;base&amp;quot;}&lt;br /&gt;
			suffix = {term = &amp;quot;circumfix&amp;quot;, alt = &amp;quot;suffix&amp;quot;}&lt;br /&gt;
		else&lt;br /&gt;
			error(&amp;quot;You must specify a prefix part, a base term and a suffix part.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return m_affix.show_circumfix {&lt;br /&gt;
		lang = lang, sc = sc, prefix = prefix, base = base, suffix = suffix, pos = args[&amp;quot;pos&amp;quot;], sort_key = args[&amp;quot;sort&amp;quot;],&lt;br /&gt;
		nocat = args[&amp;quot;nocat&amp;quot;], lit = args[&amp;quot;lit&amp;quot;], force_cat = args[&amp;quot;force_cat&amp;quot;]&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function export.confix(frame)&lt;br /&gt;
	local function extra_params(params)&lt;br /&gt;
		params[&amp;quot;nocat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;force_cat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local args, term_index, lang, sc = parse_args(frame:getParent().args, extra_params)&lt;br /&gt;
&lt;br /&gt;
	local parts = get_parsed_parts(&amp;quot;confix&amp;quot;, args, term_index, 3)&lt;br /&gt;
	local prefix = parts[1]&lt;br /&gt;
	local base = #parts &amp;gt;= 3 and parts[2] or nil&lt;br /&gt;
	local suffix = #parts &amp;gt;= 3 and parts[3] or parts[2]&lt;br /&gt;
&lt;br /&gt;
	-- Just to make sure someone didn&amp;#039;t use the template in a silly way&lt;br /&gt;
	if not (prefix and suffix) then&lt;br /&gt;
		if mw.title.getCurrentTitle().nsText == &amp;quot;Template&amp;quot; then&lt;br /&gt;
			prefix = {term = &amp;quot;prefix&amp;quot;}&lt;br /&gt;
			suffix = {term = &amp;quot;suffix&amp;quot;}&lt;br /&gt;
		else&lt;br /&gt;
			error(&amp;quot;You must specify a prefix part, an optional base term and a suffix part.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return m_affix.show_confix {&lt;br /&gt;
		lang = lang, sc = sc, prefix = prefix, base = base, suffix = suffix, pos = args[&amp;quot;pos&amp;quot;], sort_key = args[&amp;quot;sort&amp;quot;],&lt;br /&gt;
		nocat = args[&amp;quot;nocat&amp;quot;], lit = args[&amp;quot;lit&amp;quot;], force_cat = args[&amp;quot;force_cat&amp;quot;]&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function export.pseudo_loan(frame)&lt;br /&gt;
	local function extra_params(params)&lt;br /&gt;
		params[&amp;quot;pos&amp;quot;] = nil&lt;br /&gt;
		params[&amp;quot;nocap&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;notext&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;nocat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;force_cat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local args, term_index, lang, sc, source = parse_args(frame:getParent().args, extra_params, &amp;quot;has source&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	local parts = get_parsed_parts(&amp;quot;pseudo-loan&amp;quot;, args, term_index)&lt;br /&gt;
&lt;br /&gt;
	return require(pseudo_loan_module).show_pseudo_loan {&lt;br /&gt;
		lang = lang, source = source, sc = sc, parts = parts, sort_key = args[&amp;quot;sort&amp;quot;], nocap = args[&amp;quot;nocap&amp;quot;],&lt;br /&gt;
		notext = args[&amp;quot;notext&amp;quot;], nocat = args[&amp;quot;nocat&amp;quot;], lit = args[&amp;quot;lit&amp;quot;], force_cat = args[&amp;quot;force_cat&amp;quot;]&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function export.infix(frame)&lt;br /&gt;
	local function extra_params(params)&lt;br /&gt;
		params[&amp;quot;nocat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;force_cat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local args, term_index, lang, sc = parse_args(frame:getParent().args, extra_params)&lt;br /&gt;
&lt;br /&gt;
	local parts = get_parsed_parts(&amp;quot;infix&amp;quot;, args, term_index, 2)&lt;br /&gt;
	local base = parts[1]&lt;br /&gt;
	local infix = parts[2]&lt;br /&gt;
&lt;br /&gt;
	-- Just to make sure someone didn&amp;#039;t use the template in a silly way&lt;br /&gt;
	if not (base and infix) then&lt;br /&gt;
		if mw.title.getCurrentTitle().nsText == &amp;quot;Template&amp;quot; then&lt;br /&gt;
			base = {term = &amp;quot;base&amp;quot;}&lt;br /&gt;
			infix = {term = &amp;quot;infix&amp;quot;}&lt;br /&gt;
		else&lt;br /&gt;
			error(&amp;quot;You must provide a base term and an infix.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return m_affix.show_infix {&lt;br /&gt;
		lang = lang, sc = sc, base = base, infix = infix, pos = args[&amp;quot;pos&amp;quot;], sort_key = args[&amp;quot;sort&amp;quot;],&lt;br /&gt;
		nocat = args[&amp;quot;nocat&amp;quot;], lit = args[&amp;quot;lit&amp;quot;], force_cat = args[&amp;quot;force_cat&amp;quot;]&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function export.prefix(frame)&lt;br /&gt;
	local function extra_params(params)&lt;br /&gt;
		params[&amp;quot;nocat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;force_cat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local args, term_index, lang, sc = parse_args(frame:getParent().args, extra_params)&lt;br /&gt;
&lt;br /&gt;
	local prefixes = get_parsed_parts(&amp;quot;prefix&amp;quot;, args, term_index)&lt;br /&gt;
	local base = nil&lt;br /&gt;
&lt;br /&gt;
	if #prefixes &amp;gt;= 2 then&lt;br /&gt;
		base = prefixes[#prefixes]&lt;br /&gt;
		prefixes[#prefixes] = nil&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Just to make sure someone didn&amp;#039;t use the template in a silly way&lt;br /&gt;
	if #prefixes == 0 then&lt;br /&gt;
		if mw.title.getCurrentTitle().nsText == &amp;quot;Template&amp;quot; then&lt;br /&gt;
			base = {term = &amp;quot;base&amp;quot;}&lt;br /&gt;
			prefixes = { {term = &amp;quot;prefix&amp;quot;} }&lt;br /&gt;
		else&lt;br /&gt;
			error(&amp;quot;You must provide at least one prefix.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return m_affix.show_prefix {&lt;br /&gt;
		lang = lang, sc = sc, prefixes = prefixes, base = base, pos = args[&amp;quot;pos&amp;quot;], sort_key = args[&amp;quot;sort&amp;quot;],&lt;br /&gt;
		nocat = args[&amp;quot;nocat&amp;quot;], lit = args[&amp;quot;lit&amp;quot;], force_cat = args[&amp;quot;force_cat&amp;quot;]&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function export.suffix(frame)&lt;br /&gt;
	local function extra_params(params)&lt;br /&gt;
		params[&amp;quot;nocat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
		params[&amp;quot;force_cat&amp;quot;] = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local args, term_index, lang, sc = parse_args(frame:getParent().args, extra_params)&lt;br /&gt;
&lt;br /&gt;
	local base = get_parsed_part(&amp;quot;suffix&amp;quot;, args, term_index, 1)&lt;br /&gt;
	local suffixes = get_parsed_parts(&amp;quot;suffix&amp;quot;, args, term_index, nil, 2)&lt;br /&gt;
&lt;br /&gt;
	-- Just to make sure someone didn&amp;#039;t use the template in a silly way&lt;br /&gt;
	if #suffixes == 0 then&lt;br /&gt;
		if mw.title.getCurrentTitle().nsText == &amp;quot;Template&amp;quot; then&lt;br /&gt;
			base = {term = &amp;quot;base&amp;quot;}&lt;br /&gt;
			suffixes = { {term = &amp;quot;suffix&amp;quot;} }&lt;br /&gt;
		else&lt;br /&gt;
			error(&amp;quot;You must provide at least one suffix.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return m_affix.show_suffix {&lt;br /&gt;
		lang = lang, sc = sc, base = base, suffixes = suffixes, pos = args[&amp;quot;pos&amp;quot;], sort_key = args[&amp;quot;sort&amp;quot;],&lt;br /&gt;
		nocat = args[&amp;quot;nocat&amp;quot;], lit = args[&amp;quot;lit&amp;quot;], force_cat = args[&amp;quot;force_cat&amp;quot;]&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function export.derivsee(frame)&lt;br /&gt;
	local iargs = frame.args&lt;br /&gt;
	local iparams = {&lt;br /&gt;
		[&amp;quot;derivtype&amp;quot;] = {},&lt;br /&gt;
		[&amp;quot;mode&amp;quot;] = {},&lt;br /&gt;
	}&lt;br /&gt;
	local iargs = require(&amp;quot;Module:parameters&amp;quot;).process(frame.args, iparams)&lt;br /&gt;
&lt;br /&gt;
	local params = {&lt;br /&gt;
		[&amp;quot;head&amp;quot;] = {},&lt;br /&gt;
		[&amp;quot;id&amp;quot;] = {},&lt;br /&gt;
		[&amp;quot;sc&amp;quot;] = {},&lt;br /&gt;
		[&amp;quot;pos&amp;quot;] = {},&lt;br /&gt;
	}&lt;br /&gt;
	local derivtype = iargs.derivtype&lt;br /&gt;
	if derivtype == &amp;quot;PIE root&amp;quot; then&lt;br /&gt;
		params[1] = {}&lt;br /&gt;
	else&lt;br /&gt;
		params[1] = {required = &amp;quot;true&amp;quot;, default = &amp;quot;und&amp;quot;}&lt;br /&gt;
		params[2] = {}&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local args = require(&amp;quot;Module:parameters&amp;quot;).process(frame:getParent().args, params)&lt;br /&gt;
&lt;br /&gt;
	local lang&lt;br /&gt;
	local term&lt;br /&gt;
&lt;br /&gt;
	if derivtype == &amp;quot;PIE root&amp;quot; then&lt;br /&gt;
		lang = m_languages.getByCode(&amp;quot;ine-pro&amp;quot;)&lt;br /&gt;
		term = args[1] or args[&amp;quot;head&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
		if term then&lt;br /&gt;
			term = &amp;quot;*&amp;quot; .. term .. &amp;quot;-&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		lang = m_languages.getByCode(args[1], 1)&lt;br /&gt;
		term = args[2] or args[&amp;quot;head&amp;quot;]&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local id = args.id&lt;br /&gt;
	local sc = fetch_script(args.sc, &amp;quot;sc&amp;quot;)&lt;br /&gt;
	local pos = require(&amp;quot;Module:string utilities&amp;quot;).pluralize(args.pos or &amp;quot;term&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	if not term then&lt;br /&gt;
		local SUBPAGE = mw.ustring.lower(mw.title.getCurrentTitle().subpageText)&lt;br /&gt;
		if lang:hasType(&amp;quot;reconstructed&amp;quot;) or mw.title.getCurrentTitle().nsText == &amp;quot;Reconstruction&amp;quot; then&lt;br /&gt;
			term = &amp;quot;*&amp;quot; .. SUBPAGE&lt;br /&gt;
		elseif lang:hasType(&amp;quot;appendix-constructed&amp;quot;) then&lt;br /&gt;
			term = SUBPAGE&lt;br /&gt;
		else&lt;br /&gt;
			term = SUBPAGE&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if derivtype == &amp;quot;PIE root&amp;quot; then&lt;br /&gt;
		return frame:callParserFunction{&lt;br /&gt;
			name = &amp;quot;#categorytree&amp;quot;,&lt;br /&gt;
			args = {&lt;br /&gt;
				&amp;quot;Terms derived from the Proto-Indo-European root &amp;quot; .. term .. (id and &amp;quot; (&amp;quot; .. id .. &amp;quot;)&amp;quot; or &amp;quot;&amp;quot;),&lt;br /&gt;
				depth = 0,&lt;br /&gt;
				class = &amp;quot;\&amp;quot;derivedterms\&amp;quot;&amp;quot;,&lt;br /&gt;
				mode = iargs.mode,&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local category = nil&lt;br /&gt;
	local langname = lang:getCanonicalName()&lt;br /&gt;
	if (derivtype == &amp;quot;compound&amp;quot; and pos == nil) then&lt;br /&gt;
		category = langname .. &amp;quot; compounds with &amp;quot; .. term&lt;br /&gt;
	elseif derivtype == &amp;quot;compound&amp;quot; then&lt;br /&gt;
		category = langname .. &amp;quot; compound &amp;quot; .. pos .. &amp;quot; with &amp;quot; .. term&lt;br /&gt;
	else&lt;br /&gt;
		category = langname .. &amp;quot; &amp;quot; .. pos .. &amp;quot; &amp;quot; .. derivtype .. &amp;quot;ed with &amp;quot; .. term .. (id and &amp;quot; (&amp;quot; .. id .. &amp;quot;)&amp;quot; or &amp;quot;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return frame:callParserFunction{&lt;br /&gt;
		name = &amp;quot;#categorytree&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			category,&lt;br /&gt;
			depth = 0,&lt;br /&gt;
			class = &amp;quot;\&amp;quot;derivedterms&amp;quot; .. (sc and &amp;quot; &amp;quot; .. sc:getCode() or &amp;quot;&amp;quot;) .. &amp;quot;\&amp;quot;&amp;quot;,&lt;br /&gt;
			namespaces = &amp;quot;-&amp;quot; .. (mw.title.getCurrentTitle().nsText == &amp;quot;Reconstruction&amp;quot; and &amp;quot; Reconstruction&amp;quot; or &amp;quot;&amp;quot;),&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return export&lt;/div&gt;</summary>
		<author><name>bob&gt;Juelos</name></author>
	</entry>
</feed>