Wiksiyonaryo
tlwiktionary
https://tl.wiktionary.org/wiki/Wiksiyonaryo:Unang_Pahina
MediaWiki 1.47.0-wmf.20
case-sensitive
Midya
Natatangi
Usapan
Tagagamit
Usapang tagagamit
Wiksiyonaryo
Usapang Wiksiyonaryo
Talaksan
Usapang talaksan
MediaWiki
Usapang MediaWiki
Padron
Usapang padron
Tulong
Usapang tulong
Kategorya
Usapang kategorya
TimedText
TimedText talk
Module
Module talk
Event
Event talk
Padron:Click
10
2463
178027
159539
2026-09-21T16:51:26Z
Yivan000
4078
Pinagsanib ang [[:Padron:Click]] sa [[:Padron:mapipindot na boton]]: [[Padron:Click]] is older; merging to preserve history
178027
wikitext
text/x-wiki
#REDIRECT [[Padron:mapipindot na boton]]
0t3xw2n2ulvog2etcgndq2e31jn4ysf
Padron:policy
10
2465
178028
159566
2026-09-21T16:58:33Z
Yivan000
4078
Nilipat ni Yivan000 ang pahinang [[Padron:Policy]] sa [[Padron:policy]] mula sa redirect
159566
wikitext
text/x-wiki
{| style="border:1px solid #aaa; background-color:#F3F9FF; width:100%; text-align:justify; margin-bottom:0.5em"
|-
| [[Image:Green check.svg|30px]]
|align=center| '''Ang pahinang ito ay isang [[Wiktionary:Patakaran|patakaran]] ng Wiktionary.'''<br>Tinatanggap ito ng nakararaming mga manggagamit ng Wiktionary at ay tinatanggap bilang isang pamantayan na dapat sinusundan ng lahat ng mga manggagamit. Dapat hindi ito binabago nang walang pagkakasundo (''consensus''). Maaaring usapan ang patakarang ito sa pahinang usapan nito.
|}
2f1226w333nhpseax4u0l40mvdcc5gh
pinagbuhatan
0
3261
178031
9482
2026-09-22T04:45:08Z
Yivan000
4078
Inilipat ni Yivan000 ang pahinang [[Pinagbuhatan]] sa [[pinagbuhatan]]
9482
wikitext
text/x-wiki
"PINAGBUHATAN" salitang may dalawang kahulugan, una ay pinagmula o pinaggalingan at ang ikalawa ay sinampal o sinaktan gamit ang kamay.Halimbawa; 1.) Ang mga salitang Tagalog ay may pinagbuhatan sa salitang Dumagat. 2. ) Pinagbuhatan niya ang kabit niya dahil masyadong nagpapahalata kapag nasa harap ng tunay na asawa niya.
etxme0036y8gw3syy62tf88xru2nmq3
Module:parameters
828
30841
178035
171248
2026-09-22T05:00:33Z
Yivan000
4078
merge changes
178035
Scribunto
text/plain
--[==[TODO:
* Change certain flag names, as some are misnomers:
* Change `allow_holes` to `keep_holes`, because it's not the inverse of `disallow_holes`.
* Change `allow_empty` to `keep_empty`, as it causes them to be kept as "" instead of deleted.
* Sort out all the internal error calls. Manual error(format()) calls are used when certain parameters shouldn't be dumped, so find a way to avoid that.
]==]
local export = {}
local collation_module = "Module:collation"
local families_module = "Module:families"
local functions_module = "Module:fun"
local gender_and_number_utilities_module = "Module:gender and number utilities"
local labels_module = "Module:labels"
local languages_module = "Module:languages"
local math_module = "Module:math"
local pages_module = "Module:pages"
local parameters_finalize_set_module = "Module:parameters/finalizeSet"
local parameters_track_module = "Module:parameters/track"
local parse_utilities_module = "Module:parse utilities"
local references_module = "Module:references"
local scribunto_module = "Module:Scribunto"
local scripts_module = "Module:scripts"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local wikimedia_languages_module = "Module:wikimedia languages"
local yesno_module = "Module:yesno"
local mw = mw
local mw_title = mw.title
local string = string
local table = table
local dump = mw.dumpObject
local find = string.find
local format = string.format
local gsub = string.gsub
local insert = table.insert
local ipairs = ipairs
local list_to_text = mw.text.listToText
local make_title = mw_title.makeTitle
local match = string.match
local max = math.max
local new_title = mw_title.new
local next = next
local pairs = pairs
local pcall = pcall
local require = require
local sub = string.sub
local tonumber = tonumber
local type = type
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
local current_title_text, current_namespace, sets -- Defined when needed.
local namespaces = mw.site.namespaces
--[==[
Loaders for functions in other modules, which overwrite themselves with the target function when called. This ensures modules are only loaded when needed, retains the speed/convenience of locally-declared pre-loaded functions, and has no overhead after the first call, since the target functions are called directly in any subsequent calls.]==]
local function decode_entities(...)
decode_entities = require(string_utilities_module).decode_entities
return decode_entities(...)
end
local function extend(...)
extend = require(table_module).extend
return extend(...)
end
local function finalize_set(...)
finalize_set = require(parameters_finalize_set_module)
return finalize_set(...)
end
local function get_family_by_code(...)
get_family_by_code = require(families_module).getByCode
return get_family_by_code(...)
end
local function get_family_by_name(...)
get_family_by_name = require(families_module).getByCanonicalName
return get_family_by_name(...)
end
local function get_language_by_code(...)
get_language_by_code = require(languages_module).getByCode
return get_language_by_code(...)
end
local function get_language_by_name(...)
get_language_by_name = require(languages_module).getByCanonicalName
return get_language_by_name(...)
end
local function get_script_by_code(...)
get_script_by_code = require(scripts_module).getByCode
return get_script_by_code(...)
end
local function get_script_by_name(...)
get_script_by_name = require(scripts_module).getByCanonicalName
return get_script_by_name(...)
end
local function get_wm_lang_by_code(...)
get_wm_lang_by_code = require(wikimedia_languages_module).getByCode
return get_wm_lang_by_code(...)
end
local function get_wm_lang_by_code_with_fallback(...)
get_wm_lang_by_code_with_fallback = require(wikimedia_languages_module).getByCodeWithFallback
return get_wm_lang_by_code_with_fallback(...)
end
local function gsplit(...)
gsplit = require(string_utilities_module).gsplit
return gsplit(...)
end
local function is_callable(...)
is_callable = require(functions_module).is_callable
return is_callable(...)
end
local function is_integer(...)
is_integer = require(math_module).is_integer
return is_integer(...)
end
local function is_internal_title(...)
is_internal_title = require(pages_module).is_internal_title
return is_internal_title(...)
end
local function is_positive_integer(...)
is_positive_integer = require(math_module).is_positive_integer
return is_positive_integer(...)
end
local function iterate_list(...)
iterate_list = require(table_module).iterateList
return iterate_list(...)
end
local function num_keys(...)
num_keys = require(table_module).numKeys
return num_keys(...)
end
local function parse_gender_and_number_spec(...)
parse_gender_and_number_spec = require(gender_and_number_utilities_module).parse_gender_and_number_spec
return parse_gender_and_number_spec(...)
end
local function parse_references(...)
parse_references = require(references_module).parse_references
return parse_references(...)
end
local function pattern_escape(...)
pattern_escape = require(string_utilities_module).pattern_escape
return pattern_escape(...)
end
local function php_trim(...)
php_trim = require(scribunto_module).php_trim
return php_trim(...)
end
local function scribunto_parameter_key(...)
scribunto_parameter_key = require(scribunto_module).scribunto_parameter_key
return scribunto_parameter_key(...)
end
local function sort(...)
sort = require(collation_module).sort
return sort(...)
end
local function sorted_pairs(...)
sorted_pairs = require(table_module).sortedPairs
return sorted_pairs(...)
end
local function split(...)
split = require(string_utilities_module).split
return split(...)
end
local function split_labels_on_comma(...)
split_labels_on_comma = require(labels_module).split_labels_on_comma
return split_labels_on_comma(...)
end
local function split_on_comma(...)
split_on_comma = require(parse_utilities_module).split_on_comma
return split_on_comma(...)
end
local function tonumber_extended(...)
tonumber_extended = require(math_module).tonumber_extended
return tonumber_extended(...)
end
local function track(...)
track = require(parameters_track_module)
return track(...)
end
local function yesno(...)
yesno = require(yesno_module)
return yesno(...)
end
--[==[ intro:
This module is used to standardize template argument processing and checking. A typical workflow is as follows (based
on [[Module:translations]]):
{
...
local parent_args = frame:getParent().args
local params = {
[1] = {required = true, type = "language", default = "und"},
[2] = true,
[3] = {list = true},
["alt"] = true,
["id"] = true,
["sc"] = {type = "script"},
["tr"] = true,
["ts"] = true,
["lit"] = true,
}
local args = require("Module:parameters").process(parent_args, params)
-- Do further processing of the parsed arguments in `args`.
...
}
The `params` table should have the parameter names as the keys, and a (possibly empty) table of parameter tags as the
value. An empty table as the value merely states that the parameter exists, but should not receive any special
treatment; if desired, empty tables can be replaced with the value `true` as a perforamnce optimization.
Possible parameter tags are listed below:
; {required = true}
: The parameter is required; an error is shown if it is not present. The template's page itself is an exception; no
error is shown there.
; {default =}
: Specifies a default input value for the parameter, if it is absent or empty. This will be processed as though it were
the input instead, so (for example) {default = "und"} with the type {"language"} will return a language object for
[[:Category:Undetermined language|Undetermined language]] if no language code is provided. When used on list
parameters, this specifies a default value for the first item in the list only. Note that it is not possible to
generate a default that depends on the value of other parameters. If used together with {required = true}, the default
applies only to template pages (see the following entry), as a side effect of the fact that "required" parameters
aren't actually required on template pages. This can be used to show an example of the template in action when the
template page is visited; however, it is preferred to use `template_default` for this purpose, for clarity.
; {template_default =}
: Specifies a default input value for absent or empty parameters only on the template demo invocation (the invocation of
the template that is displayed when the template page that implements the template is viewed). Template pages are
pages in template space that invoke (through {{tl|#invoke:}}) the module that implements the template and calls
[[Module:parameters]]. For example, the page [[Template:en-noun]] implements the {{tl|en-noun}} template, which in
turn invokes [[Module:en-headword]], and is a template page for [[Module:en-headword]]. When the template page
[[Template:en-noun]] is visited, the {{tl|#invoke:}} of the template's module is expanded as if the template were
called without arguments, and the output is inserted at that point into the processed page. This output serves as a
sort of demo of the template's functionality. `template_default` can be used to supply default values for use only in
this demo. Since the template page may also contain other invocations of the same template (e.g. on the template's
documentation page, which is typically transcluded into the template page itself), `template_default` does not apply
if there are any arguments passed to the template or if the template is invoked on any other page but its own template
page (which is checked by comparing the name of the invoking template to the current pagename). Both
`template_default` and `default` can be specified for the same parameter. If this is done, `template_default` applies
for the argumentless template invocation on the template page, and `default` in all other circumstances As an example,
{{tl|cs-IPA}} uses the equivalent of {[1] = {default = "+", template_default = "příklad"}} to supply a default of
{"+"} for mainspace and documentation pages (which tells the module to use the value of the {{para|pagename}}
parameter, falling back to the actual pagename), but {"příklad"} (which means "example"), on [[Template:cs-IPA]].
; {alias_of =}
: Treat the parameter as an alias of another. When arguments are specified for this parameter, they will automatically
be renamed and stored under the alias name. This allows for parameters with multiple alternative names, while still
treating them as if they had only one name. The conversion-related properties of an aliased parameter (e.g. `type`,
`set`, `convert`, `sublist`) are taken from the aliasee, and the corrresponding properties set on the alias itself
are ignored; but other properties on the alias are taken from the alias's spec and not from the aliasee's spec. This
means, for example, that if you create an alias of a list parameter, the alias must also specify the `list` property
or it is not a list. (In such a case, a value specified for the alias goes into the first item of the aliasee's list.
You cannot make a list alias of a non-list parameter; this causes an error to be thrown.) Similarly, if you specify
`separate_no_index` on an aliasee but not on the alias, uses of the unindexed aliasee parameter are stored into the
`.default` key, but uses of the unindexed alias are stored into the first numbered key of the aliasee's list.
Aliases cannot be required, as this prevents the other name or names of the parameter from being used. Parameters
that are aliases and required at the same time cause an error to be thrown.
; {allow_empty = true}
: If the argument is an empty string value, it is not converted to {nil}, but kept as-is. The use of `allow_empty` is
disallowed if a type has been specified, and causes an error to be thrown.
; {no_trim = true}
: Spacing characters such as spaces and newlines at the beginning and end of a positional parameter are not removed.
(MediaWiki itself automatically trims spaces and newlines at the edge of named parameters.) The use of `no_trim` is
disallowed if a type has been specified, and causes an error to be thrown.
; {type =}
: Specifies what value type to convert the argument into. The default is to leave it as a text string. Alternatives are:
:; {type = "boolean"}
:: The value is treated as a boolean value, either true or false. No value, the empty string, and the strings {"0"},
{"no"}, {"n"}, {"false"}, {"f"} and {"off"} are treated as {false}, all other values are considered {true}.
:; {type = "number"}
:: The value is converted into a number, and throws an error if the value is not parsable as a number. Input values may
be signed (`+` or `-`), and may contain decimal points and leading zeroes. If {allow_hex = true}, then hexadecimal
values in the form {"0x100"} may optionally be used instead, which otherwise have the same syntax restrictions
(including signs, decimal digits, and leading zeroes after {"0x"}). Hexadecimal inputs are not case-sensitive. Lua's
special number values (`inf` and `nan`) are not possible inputs.
:; {type = "range"}
:: The value is interpreted as a hyphen-separated range of two numbers (e.g. {"2-4"} is interpreted as the range from
{2} to {4}). A number input without a hyphen is interpreted as a range from that number to itself (e.g. the input {"1"} is interpreted as the range from {1} to {1}). Any optional flags which are available for numbers will also work for ranges.
:; {type = "language"}
:: The value is interpreted as a full or [[Wiktionary:Languages#Etymology-only languages|etymology-only language]] code
language code (or name, if {method = "name"}) and converted into the corresponding object (see [[Module:languages]]).
If the code or name is invalid, then an error is thrown. The additional setting {family = true} can be given to allow
[[Wiktionary:Language families|language family codes]] to be considered valid and the corresponding object returned.
Note that to distinguish an etymology-only language object from a full language object, use
{object:hasType("language", "etymology-only")}.
:; {type = "full language"}
:: The value is interpreted as a full language code (or name, if {method = "name"}) and converted into the corresponding
object (see [[Module:languages]]). If the code or name is invalid, then an error is thrown. Etymology-only languages
are not allowed. The additional setting {family = true} can be given to allow
[[Wiktionary:Language families|language family codes]] to be considered valid and the corresponding object returned.
:; {type = "Wikimedia language"}
:: The value is interpreted as a code and converted into a Wikimedia language object. If the code is invalid, then an
error is thrown. If {fallback = true} is specified, conventional language codes which are different from their
Wikimedia equivalent will also be accepted as a fallback.
:; {type = "family"}
:: The value is interpreted as a language family code (or name, if {method = "name"}) and converted into the
corresponding object (see [[Module:families]]). If the code or name is invalid, then an error is thrown.
:; {type = "script"}
:: The value is interpreted as a script code (or name, if {method = "name"}) and converted into the corresponding object
(see [[Module:scripts]]). If the code or name is invalid, then an error is thrown.
:; {type = "title"}
:: The value is interpreted as a page title and converted into the corresponding object (see the
[[mw:Extension:Scribunto/Lua_reference_manual#Title_library|Title library]]). If the page title is invalid, then an
error is thrown; by default, external titles (i.e. those on other wikis) are not treated as valid. Options are:
::; {namespace = n}
::: The default namespace, where {n} is a namespace number; this is treated as {0} (the mainspace) if not specified.
::; {allow_external = true}
::: External titles are treated as valid.
::; {prefix = "namespace override"} (default)
::: The default namespace prefix will be prefixed to the value is already prefixed by a namespace prefix. For instance,
the input {"Foo"} with namespace {10} returns {"Template:Foo"}, {"Wiktionary:Foo"} returns {"Wiktionary:Foo"}, and
{"Template:Foo"} returns {"Template:Foo"}. Interwiki prefixes cannot act as overrides, however: the input {"fr:Foo"}
returns {"Template:fr:Foo"}.
::; {prefix = "force"}
::: The default namespace prefix will be prefixed unconditionally, even if the value already appears to be prefixed.
This is the way that {{tl|#invoke:}} works when calling modules from the module namespace ({828}): the input {"Foo"}
returns {"Module:Foo"}, {"Wiktionary:Foo"} returns {"Module:Wiktionary:Foo"}, and {"Module:Foo"} returns
{"Module:Module:Foo"}.
::; {prefix = "full override"}
::: The same as {prefix = "namespace override"}, except that interwiki prefixes can also act as overrides. For instance,
{"el:All topics"} with namespace {14} returns {"el:Category:All topics"}. Due to the limitations of MediaWiki, only
the first prefix in the value may act as an override, so the namespace cannot be overridden if the first prefix is
an interwiki prefix: e.g. {"el:Template:All topics"} with namespace {14} returns {"el:Category:Template:All topics"}.
:; {type = "parameter"}
:: The value is interpreted as the name of a parameter, and will be normalized using the method that Scribunto uses when
constructing a {frame.args} table of arguments. This means that integers will be converted to numbers, but all other
arguments will remain as strings (e.g. {"1"} will be normalized to {1}, but {"foo"} and {"1.5"} will remain
unchanged). Note that Scribunto also trims parameter names, following the same trimming method that this module
applies by default to all parameter types.
:: This type is useful when one set of input arguments is used to construct a {params} table for use in a subsequent
{export.process()} call with another set of input arguments; for instance, the set of valid parameters for a template
might be defined as {{tl|#invoke:[some module]|args=}} in the template, where {args} is a sublist of valid parameters
for the template.
:; {type = "qualifier"}
:: The value is interpreted as a qualifier and converted into the correct format for passing into `format_qualifiers()`
in [[Module:qualifier]] (which currently just means converting it to a one-item list).
:; {type = "labels"}
:: The value is interpreted as a comma-separated list of labels and converted into the correct format for passing into
`show_labels()` in [[Module:labels]] (which is currently a list of strings). Splitting is done on commas not followed
by whitespace, except that commas inside of double angle brackets do not count even if not followed by whitespace.
This type should be used by for normal labels (typically specified using {{para|l}} or {{para|ll}}) and accent
qualifiers (typically specified using {{para|a}} and {{para|aa}}).
:; {type = "references"}
:: The value is interpreted as one or more references, in the format prescribed by `parse_references()` in
[[Module:references]], and converted into a list of objects of the form accepted by `format_references()` in the same
module. If a syntax error is found in the reference format, an error is thrown.
:; {type = "genders"}
:: The value is interpreted as one or more comma-separated gender/number specs, in the format prescribed by
[[Module:gender and number]]. Inline modifiers (`<q:...>`, `<qq:...>`, `<l:...>`, `<ll:...>` or `<ref:...>`) may be
attached to a gender/number spec.
:; {type = "form of tags"}
:: The value is interpreted as an ampersand-separated list of grammar tags and converted into the correct format
for passing as `tags` into `tagged_inflections()` in [[Module:form of]] (which is currently a list of strings).
Splitting is always done by ampersands. This type should be used by for inflection qualifiers that act as
grammar tags (typically specified using {{para|infl}}).
:; {type = function(val) ... end}
:: `type` may be set to a function (or callable table), which must take the argument value as its sole argument, and must
output one of the other recognized types. This is particularly useful for lists (see below), where certain values need
to be interpreted differently to others.
; {list =}
: Treat the parameter as a list of values, each having its own parameter name, rather than a single value. The
parameters will have a number at the end, except optionally for the first (but see also {require_index = true}). For
example, {list = true} on a parameter named "head" will include the parameters {{para|head}} (or {{para|head1}}),
{{para|head2}}, {{para|head3}} and so on. If the parameter name is a number, another number doesn't get appended, but
the counting simply continues, e.g. for parameter {3} the sequence is {{para|3}}, {{para|4}}, {{para|5}} etc. List
parameters are returned as numbered lists, so for a template that is given the parameters `|head=a|head2=b|head3=c`,
the processed value of the parameter {"head"} will be { { "a", "b", "c" }}}.
: The value for {list =} can also be a string. This tells the module that parameters other than the first should have a
different name, which is useful when the first parameter in a list is a number, but the remainder is named. An example
would be for genders: {list = "g"} on a parameter named {1} would have parameters {{para|1}}, {{para|g2}}, {{para|g3}}
etc.
: If the number is not located at the end, it can be specified by putting {"\1"} at the number position. For example,
parameters {{para|f1accel}}, {{para|f2accel}}, ... can be captured by using the parameter name {"f\1accel"}, as is
done in [[Module:headword/templates]].
; {set =}
: Require that the value of the parameter be one of the specified values (or omitted, if {required = true} isn't given).
Two formats are allowed; either a list of possible values can be supplied, or a table can be supplied where the keys
are allowed values and the values are either `true` or a string naming a value found elsewhere in the table as a key.
In the latter case, the key is an alias and the value is the canonical value, and if the user uses the alias, it will
automatically be mapped to the canonical value. In such a case, the canonical value cannot itself be an alias. The use
of `set` is disallowed if {type = "boolean"} and causes an error to be thrown.
; {sublist =}
: The value of the parameter is a delimiter-separated list of individual raw values. The resulting field in `args` will
be a Lua list (i.e. a table with numeric indices) of the converted values. If {sublist = true} is given, the values
will be split on commas (possibly with whitespace on one or both sides of the comma, which is ignored). If
{sublist = "comma without whitespace"} is given, the values will be split on commas which are not followed by whitespace,
and which aren't preceded by an escaping backslash. Otherwise, the value of `sublist` should be either a Lua pattern
specifying the delimiter(s) to split on or a function (or callable table) to do the splitting, which is passed two values
(the value to split and a function to signal an error) and should return a list of the split values.
; {convert =}
: If given, this specifies a function (or callable table) to convert the raw parameter value into the Lua object used
during further processing. The function is passed two arguments, the raw parameter value itself and a function used to
signal an error during parsing or conversion, and should return one value, the converted parameter. The error-signaling
function contains the name and raw value of the parameter embedded into the message it generates, so these do not need to
specified in the message passed into it. If `type` is specified in conjunction with `convert`, the processing by
`type` happens first. If `sublist` is given in conjunction with `convert`, the raw parameter value will be split
appropriately and `convert` called on each resulting item.
; {allow_hex = true}
: When used in conjunction with {type = "number"}, allows hexadecimal numbers as inputs, in the format {"0x100"} (which is
not case-sensitive).
; {family = true}
: When used in conjunction with {type = "language"}, allows [[Wiktionary:Language families|language family codes]] to be
returned. To check if a given object refers to a language family, use {object:hasType("family")}.
; {method = "name"}
: When used in conjunction with {type = "language"}, {type = "family"} or {type = "script"}, checks for and parses a
language, family or script name instead of a code.
; {allow_holes = true}
: This is used in conjunction with list-type parameters. By default, the values are tightly packed in the resulting
list. This means that if, for example, an entry specified `head=a|head3=c` but not {{para|head2}}, the returned list
will be { {"a", "c"}}}, with the values stored at the indices {1} and {2}, not {1} and {3}. If it is desirable to keep
the numbering intact, for example if the numbers of several list parameters correlate with each other (like those of
{{tl|affix}}), then this tag should be specified.
: If {allow_holes = true} is given, there may be {nil} values in between two real values, which makes many of Lua's
table processing functions no longer work, like {#} or {ipairs()}. To remedy this, the resulting table will contain an
additional named value, `maxindex`, which tells you the highest numeric index that is present in the table. In the
example above, the resulting table will now be { { "a", nil, "c", maxindex = 3}}}. That way, you can iterate over the
values from {1} to `maxindex`, while skipping {nil} values in between.
; {disallow_holes = true}
: This is used in conjunction with list-type parameters. As mentioned above, normally if there is a hole in the source
arguments, e.g. `head=a|head3=c` but not {{para|head2}}, it will be removed in the returned list. If
{disallow_holes = true} is specified, however, an error is thrown in such a case. This should be used whenever there
are multiple list-type parameters that need to line up (e.g. both {{para|head}} and {{para|tr}} are available and
{{para|head3}} lines up with {{para|tr3}}), unless {allow_holes = true} is given and you are prepared to handle the
holes in the returned lists.
; {disallow_missing = true}
: This is similar to {disallow_holes = true}, but an error will not be thrown if an argument is blank, rather than
completely missing. This may be used to tolerate intermediate blank numerical parameters, which sometimes occur in list
templates. For instance, `head=a|head2=|head3=c` will not throw an error, but `head=a|head3=c` will.
; {require_index = true}
: This is used in conjunction with list-type parameters. By default, the first parameter can have its index omitted.
For example, a list parameter named `head` can have its first parameter specified as either {{para|head}} or
{{para|head1}}. If {require_index = true} is specified, however, only {{para|head1}} is recognized, and {{para|head}}
will be treated as an unknown parameter. {{tl|affixusex}} (and variants {{tl|suffixusex}}, {{tl|prefixusex}}) use
this, for example, on all list parameters.
; {separate_no_index = true}
: This is used to distinguish between {{para|head}} and {{para|head1}} as different parameters. For example, in
{{tl|affixusex}}, to distinguish between {{para|sc}} (a script code for all elements in the usex's language) and
{{para|sc1}} (the script code of the first element, used when the first element is prefixed with a language code to
indicate that it is in a different language). When this is used, the resulting table will contain an additional named
value, `default`, which contains the value for the indexless argument.
; {flatten = true}
: This is used in conjunction with list-type parameters when `sublist` or a list-generating type such as {"labels"} or
{"genders"} is also specified, and causes the resulting list to be flattened. Not currently compatible with
{allow_holes = true}.
; {replaced_by =}
: Specifies that the parameter is no longer valid, and has been replaced by some other mechanism. If the value of
`replaced_by` is a string, it is the name of the new parameter to use instead. Use the `reason` tag to specify the
reason why this change has been made, e.g.
{reason = "for consistency with the corresponding parameter in other Romance-language headword templates"}. If the
value of `replaced_by` is {false}, there is no replacement parameter. In this case, `instead` should be supplied
with a description of what to do instead, e.g.
{instead = "use an inline modifier on |2= such as <q:...>, <qq:...>, <l:...> or <ll:...>"}. You can also supply a
justification in `reason` if you feel it is appropriate or necessary to do so.
; {reason =}
: When used in conjunction with `replaced_by`, specifies the reason for the parameter replacement.
; {instead =}
: When used in conjunction with {replaced_by = false}, specifies what to do instead of using the removed parameter.
; {demo = true}
: This is used as a way to ensure that the parameter is only enabled on the template's own page (and its documentation
page), and in the User: namespace; otherwise, it will be treated as an unknown parameter. This should only be used if
special settings are required to showcase a template in its documentation (e.g. adjusting the pagename or disabling
categorization). In most cases, it should be possible to do this without using demo parameters, but they may be
required if a template/documentation page also contains real uses of the same template as well (e.g. {{tl|shortcut}}),
as a way to distinguish them.
; {deprecated = true}
: This is for tracking the use of deprecated parameters, including any aliases that are being brought out of use. See
[[Wiktionary:Tracking]] for more information.
]==]
-- Returns true if the current page is a template or module containing the current {{#invoke}}.
-- If the include_documentation argument is given, also returns true if the current page is either page's documentation page.
local own_page, own_page_or_documentation
local function is_own_page(include_documentation)
if own_page == nil then
if current_namespace == nil then
local current_title = mw_title.getCurrentTitle()
current_title_text, current_namespace = current_title.prefixedText, current_title.namespace
end
local frame = current_namespace == 828 and mw.getCurrentFrame() or
current_namespace == 10 and mw.getCurrentFrame():getParent()
if frame then
local frame_title_text = frame:getTitle()
own_page = current_title_text == frame_title_text
own_page_or_documentation = own_page or current_title_text == frame_title_text .. "/documentation"
else
own_page, own_page_or_documentation = false, false
end
end
return include_documentation and own_page_or_documentation or own_page
end
-------------------------------------- Some helper functions -----------------------------
-- Convert a list in `list` to a string, separating the final element from the preceding one(s) by `conjunction`. If
-- `dump_vals` is given, pass all values in `list` through mw.dumpObject() (WARNING: this destructively modifies
-- `list`). This is similar to serialCommaJoin() in [[Module:table]] when used with the `dontTag = true` option, but
-- internally uses mw.text.listToText().
local function concat_list(list, conjunction, dump_vals)
if dump_vals then
for k, v in pairs(list) do
list[k] = dump(v)
end
end
return list_to_text(list, nil, conjunction)
end
-- A helper function for use with generating error-signaling functions in the presence of raw value conversion. Format a
-- message `msg`, including the processed value `processed` if it is different from the raw value `rawval`; otherwise,
-- just return `msg`.
local function msg_with_processed(msg, rawval, processed)
if rawval == processed then
return msg
end
local processed_type = type(processed)
return format("%s (processed value %s)",
msg, (processed_type == "string" or processed_type == "number") and processed or dump(processed)
)
end
-- Separate form of tags with ampersand (&).
local function split_tags_on_ampersand(tags)
return split(tags, "&")
end
-------------------------------------- Error handling -----------------------------
local function process_error(fmt, ...)
local args = {...}
for i, val in ipairs(args) do
args[i] = dump(val)
end
if type(fmt) == "table" then
-- hacky signal that we're called from internal_process_error(), and not to omit stack frames
return error(format(fmt[1], unpack(args)))
end
return error(format(fmt, unpack(args)), 3)
end
local function internal_process_error(fmt, ...)
process_error({"Internal error in `params` table: " .. fmt}, ...)
end
-- Check that a parameter or argument is in the form form Scribunto normalizes input argument keys into (e.g. 1 not "1", "foo" not " foo "). Otherwise, it won't be possible to normalize inputs in the expected way. Unless is_argument is set, also check that the name only contains one placeholder at most, and that strings don't resolve to numeric keys once the placeholder has been substituted.
local function validate_name(name, desc, extra_name, is_argument)
local normalized = scribunto_parameter_key(name)
if name and name == normalized then
if is_argument or type(name) ~= "string" then
return
end
local placeholder = find(name, "\1", nil, true)
if not placeholder then
return
elseif find(name, "\1", placeholder + 1, true) then
error(format(
"Internal error: expected %s to only contain one placeholder, but saw %s",
extra_name and (desc .. dump(extra_name)) or desc, dump(name)
))
end
local first_name = gsub(name, "\1", "1")
normalized = scribunto_parameter_key(first_name)
if first_name == normalized then
return
end
error(format(
"Internal error: %s cannot resolve to numeric parameters once any placeholder has been substituted, but %s resolves to %s",
extra_name and (desc .. dump(extra_name)) or desc, dump(name), dump(normalized)
))
elseif normalized == nil then
error(format(
"Internal error: expected %s to be of type string or number, but saw %s",
extra_name and (desc .. dump(extra_name)) or desc, type(name)
))
end
error(format(
"Internal error: expected %s to be Scribunto-compatible: %s (a %s) should be %s (a %s)",
extra_name and (desc .. dump(extra_name)) or desc, dump(name), type(name), dump(normalized), type(normalized)
))
end
local function validate_alias_options(...)
local invalid = {
required = true,
default = true,
template_default = true,
allow_holes = true,
disallow_holes = true,
disallow_missing = true,
}
function validate_alias_options(param, name, main_param, alias_of)
for k in pairs(param) do
if invalid[k] then
track("bad alias option")
-- internal_process_error(
-- "parameter %s cannot have the option %s, as it is an alias of parameter %s.",
-- name, option, alias_of
-- )
end
end
-- Soon, aliases will inherit options from the main parameter via __index. Track cases where this would happen.
if main_param ~= true then
for k in pairs(main_param) do
if param[k] == nil and not invalid[k] then
if k == "list" then -- these need to be changed to list = false to retain current behaviour
track("mismatched list alias option")
elseif not (k == "type" or k == "set" or k == "sublist") then -- rarely specified on aliases, as they're effectively inherited already
track("mismatched alias option")
end
end
end
end
end
validate_alias_options(...)
end
-- TODO: give ranges instead of long lists, if possible.
--[==[ func: export.params_list_error(params, msg)
Given a key-value table of raw parameters `params`, display an error message about all the parameters seen in the table.
The parameter names are displayed in sorted order. `msg` should be e.g. {"required"} or {"not used by this template"}.
This is used internally to display error messages about required or invalid parameters, and can be used for the same
purpose by code that processes its own parameters (e.g. if the `return_unknown` flag is specified to `process`).
]==]
local function params_list_error(params, msg)
local list, n = {}, 0
for name in sorted_pairs(params) do
n = n + 1
list[n] = name
end
error(format(
"Parameter%s %s.",
format(n == 1 and " %s is" or "s %s are", concat_list(list, " and ", true)),
msg
), 3)
end
export.params_list_error = params_list_error
-- Helper function for use with convert_val_error(). Format a list of possible choices using `concat_list` and
-- conjunction "or", displaying "either " before the choices if there's more than one.
local function format_choice_list(valid)
return (#valid > 1 and "either " or "") .. concat_list(valid, " or ")
end
-- Signal an error for a value `val` that is not of the right type `valid` (which is either a string specifying a type, or
-- a list of possible values, in the case where `set` was used). `name` is the name of the parameter and can be a
-- function to signal an error (which is assumed to automatically display the parameter's name and value). `seetext` is
-- an optional additional explanatory link to display (e.g. [[WT:LOL]], the list of possible languages and codes).
local function convert_val_error(val, name, valid, seetext)
if is_callable(name) then
if type(valid) == "table" then
valid = "choice, must be " .. format_choice_list(valid)
end
name(format("Invalid %s; the value %s is not valid%s", valid, val, seetext and "; see " .. seetext or ""))
else
if type(valid) == "table" then
valid = format_choice_list(valid)
else
valid = "a valid " .. valid
end
error(format("Parameter %s must be %s; the value %s is not valid.%s", dump(name), valid, dump(val),
seetext and " See " .. seetext .. "." or ""))
end
end
-- Generate the appropriate error-signaling function given parameter value `val` and name `name`. If `name` is already
-- a function, it is just returned; otherwise a function is generated and returned that displays the passed-in messaeg
-- along with the parameter's name and value.
local function make_parse_err(val, name)
if is_callable(name) then
return name
end
return function(msg)
error(format("%s: parameter %s=%s", msg, name, val))
end
end
-------------------------------------- Value conversion -----------------------------
-- For a list parameter `name` and corresponding value `list_name` of the `list` field (which should have the same value
-- as `name` if `list = true` was given), generate a pattern to match parameters of the list and store the pattern as a
-- key in `patterns`, with corresponding value set to `name`. For example, if `list_name` is "tr", the pattern will
-- match "tr" as well as "tr1", "tr2", ..., "tr10", "tr11", etc. If the `list_name` contains a \1 in it, the numeric
-- portion goes in place of the \1. For example, if `list_name` is "f\1accel", the pattern will match "faccel",
-- "f1accel", "f2accel", etc. Any \1 in `name` is removed before storing into `patterns`.
local function save_pattern(name, list_name, patterns)
name = type(name) == "string" and gsub(name, "\1", "") or name
if find(list_name, "\1", nil, true) then
patterns["^" .. gsub(pattern_escape(list_name), "\1", "([1-9]%%d*)") .. "$"] = name
else
patterns["^" .. pattern_escape(list_name) .. "([1-9]%d*)$"] = name
list_name = list_name .. "\1"
end
validate_name(list_name, "the list field of parameter ", name)
return patterns
end
-- A helper function for use with `sublist`. It is an iterator function for use in a for-loop that returns split
-- elements of `val` using `sublist` (a Lua split pattern; boolean `true` to split on commas optionally surrounded by
-- whitespace; "comma without whitespace" to split only on commas not followed by whitespace which have not been escaped
-- by a backslash; or a function to do the splitting, which is passed two values, the value to split and a function to
-- signal an error, and should return a list of the split elements). `name` is the parameter name or error-signaling
-- function passed into convert_val().
local function split_sublist(val, name, sublist)
if sublist == true then
return gsplit(val, "%s*,%s*")
-- Split an argument on comma, but not comma followed by whitespace.
elseif sublist == "comma without whitespace" then
-- If difficult cases, use split_on_comma.
if find(val, "\\", nil, true) or match(val, ",%s") then
return iterate_list(split_on_comma(val))
end
-- Otherwise, use gsplit.
return gsplit(val, ",")
elseif type(sublist) == "string" then
return gsplit(val, sublist)
elseif not is_callable(sublist) then
error(format('Internal error: expected `sublist` to be of type "string" or "function" or boolean `true`, but saw %s', dump(sublist)))
end
return iterate_list(sublist(val, make_parse_err(val, name)))
end
-- For parameter named `name` with value `val` and param spec `param`, if the `set` field is specified, verify that the
-- value is one of the one specified in `set`, and throw an error otherwise. `name` is taken directly from the
-- corresponding parameter passed into convert_val() and may be a function to signal an error. Optional `param_type` is
-- a string specifying the conversion type of `val` and is used for special-casing: If `param_type` is "boolean", an
-- internal error is thrown (since `set` cannot be used in conjunction with booleans) and if `param_type` is "number",
-- no checking happens because in this case `set` contains numbers and is checked inside the number conversion function
-- itself, after converting `val` to a number. Return the canonical value of `val` (which may be different from `val`
-- if an alias map is given).
local function check_set(val, name, param, param_type)
if param_type == "boolean" then
error(format('Internal error: cannot use `set` with `type = "%s"`', param_type))
-- Needs to be special cased because the check happens after conversion to numbers.
elseif param_type == "number" then
return val
end
local set, map = param.set
if sets == nil then
map = finalize_set(set, name)
sets = {[set] = map}
else
map = sets[set]
if map == nil then
map = finalize_set(set, name)
sets[set] = map
end
end
local newval = map[val]
if newval == true then
return val
elseif newval ~= nil then
return newval
end
local list = {}
for k, v in sorted_pairs(map) do
if v == true then
insert(list, dump(k))
else
insert(list, ("%s (alias of %s)"):format(dump(k), dump(v)))
end
end
-- If the parameter is not required then put "or empty" at the end of the list, to avoid implying the parameter is actually required.
if not param.required then
insert(list, "empty")
end
convert_val_error(val, name, list)
end
local function convert_language(val, name, param, allow_etym)
local method, func = param.method
if method == nil or method == "code" then
func, method = get_language_by_code, "code"
elseif method == "name" then
func, method = get_language_by_name, "name"
else
error(format('Internal error: expected `method` for type `language` to be "code", "name" or undefined, but saw %s', dump(method)))
end
local lang = func(val, nil, allow_etym, param.family)
if lang then
return lang
end
local list, links = {"language"}, {"[[WT:LOL]]"}
if allow_etym then
insert(list, "etymology language")
insert(links, "[[WT:LOL/E]]")
end
if param.family then
insert(list, "family")
insert(links, "[[WT:LOF]]")
end
convert_val_error(val, name, concat_list(list, " or ") .. " " .. (method == "name" and "name" or "code"), concat_list(links, " and "))
end
local function convert_number(val, allow_hex)
-- Call tonumber_extended with the `real_finite` flag, which filters out ±infinity and NaN.
-- By default, specify base 10, which prevents 0x hex inputs from being converted.
-- If `allow_hex` is set, then don't give a base, which means 0x hex inputs will work.
local num = tonumber_extended(val, not allow_hex and 10 or nil, "finite_real")
if not num then
return num
end
if match(val, "[eEpP.]") then -- float
track("number not an integer")
end
if find(val, "+", nil, true) then
track("number with +")
end
-- Track various unusual number inputs to determine if it should be restricted to positive integers by default (possibly including 0).
if not is_positive_integer(num) then
track("number not a positive integer")
if num == 0 then
track("number is 0")
elseif not is_integer(num) then
track("number not an integer")
end
end
return num
end
-- TODO: validate parameter specs separately, as it's making the handler code really messy at the moment.
local type_handlers = setmetatable({
["boolean"] = function(val)
return yesno(val, true)
end,
["family"] = function(val, name, param)
local method, func = param.method
if method == nil or method == "code" then
func, method = get_family_by_code, "code"
elseif method == "name" then
func, method = get_family_by_name, "name"
else
error(format('Internal error: expected `method` for type `family` to be "code", "name" or undefined, but saw %s', dump(method)))
end
return func(val) or convert_val_error(val, name, "family " .. method, "[[WT:LOF]]")
end,
["labels"] = function(val, name, param)
-- FIXME: Should be able to pass in a parse_err function.
return split_labels_on_comma(val)
end,
["form of tags"] = function(val, name, param)
return split_tags_on_ampersand(val)
end,
["language"] = function(val, name, param)
return convert_language(val, name, param, true)
end,
["full language"] = convert_language,
["number"] = function(val, name, param)
local allow_hex = param.allow_hex
if allow_hex and allow_hex ~= true then
error(format(
'Internal error: expected `allow_hex` for type `number` to be of type "boolean" or undefined, but saw %s',
dump(allow_hex)
))
end
local num = convert_number(val, allow_hex)
if param.set then
-- Don't pass in "number" here; otherwise no checking will happen.
num = check_set(num, name, param)
end
if num then
return num
end
convert_val_error(val, name, (allow_hex and "decimal or hexadecimal " or "") .. "number")
end,
["range"] = function(val, name, param)
local allow_hex = param.allow_hex
if allow_hex and allow_hex ~= true then
error(format(
'Internal error: expected `allow_hex` for type `range` to be of type "boolean" or undefined, but saw %s',
dump(allow_hex)
))
end
-- Pattern ensures leading minus signs are accounted for.
local m1, m2 = match(val, "^(%s*%S.-)%-(%s*%S.*)")
if m1 then
m1 = convert_number(m1, allow_hex)
if m1 then
m2 = convert_number(m2, allow_hex)
if m2 then
return {m1, m2}
end
end
end
-- Try `val` if it couldn't be split into a range, and return a range of `val` to `val` if possible.
local num = convert_number(val, allow_hex)
if num then
return {num, num}
end
convert_val_error(val, name, (allow_hex and "decimal or hexadecimal " or "") .. "number or a hyphen-separated range of two numbers")
end,
["parameter"] = function(val, name, param)
-- Use the `no_trim` option, as any trimming will have already been done.
return scribunto_parameter_key(val, true)
end,
["qualifier"] = function(val, name, param)
return {val}
end,
["references"] = function(val, name, param)
return parse_references(val, make_parse_err(val, name))
end,
["genders"] = function(val, name, param)
if not val:find("[,<]") then
return {{spec = val}}
end
-- NOTE: We don't pass in allow_space_around_comma. Consistent with other comma-separated types, there shouldn't
-- be spaces around the comma.
return parse_gender_and_number_spec {
spec = val,
parse_err = make_parse_err(val, name),
allow_multiple = true,
}
end,
["script"] = function(val, name, param)
local method, func = param.method
if method == nil or method == "code" then
func, method = get_script_by_code, "code"
elseif method == "name" then
func, method = get_script_by_name, "name"
else
error(format('Internal error: expected `method` for type `script` to be "code", "name" or undefined, but saw %s', dump(method)))
end
return func(val) or convert_val_error(val, name, "script " .. method, "[[WT:LOS]]")
end,
["string"] = function(val, name, param) -- To be removed as unnecessary.
track("string")
return val
end,
-- TODO: add support for resolving to unsupported titles.
-- TODO: split this into "page name" (i.e. internal) and "link target" (i.e. external as well), which is more intuitive.
["title"] = function(val, name, param)
local namespace = param.namespace
if namespace == nil then
namespace = 0
else
local valid_type = type(namespace) ~= "number" and 'of type "number" or undefined' or
not namespaces[namespace] and "a valid namespace number" or
nil
if valid_type then
error(format('Internal error: expected `namespace` for type `title` to be %s, but saw %s', valid_type, dump(namespace)))
end
end
-- Decode entities. WARNING: mw.title.makeTitle must be called with `decoded` (as it doesn't decode) and mw.title.new must be called with `val` (as it does decode, so double-decoding needs to be avoided).
local decoded, prefix, title = decode_entities(val), param.prefix
-- If the input is a fragment, treat the title as the current title with the input fragment.
if sub(decoded, 1, 1) == "#" then
-- If prefix is "force", only get the current title if it's in the specified namespace. current_title includes the namespace prefix.
if current_namespace == nil then
local current_title = mw_title.getCurrentTitle()
current_title_text, current_namespace = current_title.prefixedText, current_title.namespace
end
if not (prefix == "force" and namespace ~= current_namespace) then
title = new_title(current_title_text .. val)
end
elseif prefix == "force" then
-- Unconditionally add the namespace prefix (mw.title.makeTitle).
title = make_title(namespace, decoded)
elseif prefix == "full override" then
-- The first input prefix will be used as an override (mw.title.new). This can be a namespace or interwiki prefix.
title = new_title(val, namespace)
elseif prefix == nil or prefix == "namespace override" then
-- Only allow namespace prefixes to override. Interwiki prefixes therefore need to be treated as plaintext (e.g. "el:All topics" with namespace 14 returns "el:Category:All topics", but we want "Category:el:All topics" instead; if the former is really needed, then the input ":el:Category:All topics" will work, as the initial colon overrides the namespace). mw.title.new can take namespace names as well as numbers in the second argument, and will throw an error if the input isn't a valid namespace, so this can be used to determine if a prefix is for a namespace, since mw.title.new will return successfully only if there's either no prefix or the prefix is for a valid namespace (in which case we want the override).
local success
success, title = pcall(new_title, val, match(decoded, "^.-%f[:]") or namespace)
-- Otherwise, get the title with mw.title.makeTitle, which unconditionally adds the namespace prefix, but behaves like mw.title.new if the namespace is 0.
if not success then
title = make_title(namespace, decoded)
end
else
error(format('Internal error: expected `prefix` for type `title` to be "force", "full override", "namespace override" or undefined, but saw %s', dump(prefix)))
end
local allow_external = param.allow_external
if allow_external == true then
return title or convert_val_error(val, name, "Wiktionary or external page title")
elseif not allow_external then
return title and is_internal_title(title) and title or convert_val_error(val, name, "Wiktionary page title")
end
error(format('Internal error: expected `allow_external` for type `title` to be of type "boolean" or undefined, but saw %s', dump(allow_external)))
end,
["Wikimedia language"] = function(val, name, param)
local fallback = param.fallback
if fallback == true then
return get_wm_lang_by_code_with_fallback(val) or convert_val_error(val, name, "Wikimedia language or language code")
elseif not fallback then
return get_wm_lang_by_code(val) or convert_val_error(val, name, "Wikimedia language code")
end
error(format('Internal error: expected `fallback` for type `Wikimedia language` to be of type "boolean" or undefined, but saw %s', dump(fallback)))
end,
}, {
-- TODO: decode HTML entities in all input values. Non-trivial to implement, because we need to avoid any downstream functions decoding the output from this module, which would be double-decoding. Note that "title" has this implemented already, and it needs to have both the raw input and the decoded input to avoid double-decoding by me.title.new, so any implementation can't be as simple as decoding in __call then passing the result to the handler.
__call = function(self, val, name, param, param_type, default)
local val_type = type(val)
-- TODO: check this for all possible parameter types.
if val_type == param_type then
return val
elseif val_type ~= "string" then
local expected = "string"
if default and (param_type == "boolean" or param_type == "number") then
expected = param_type .. " or " .. expected
end
error(format(
"Internal error: %sargument %s has the type %s; expected a %s.",
default and (default .. " for ") or "", name, dump(val_type), expected
))
end
local func = self[param_type]
if func == nil then
error(format("Internal error: %s is not a recognized parameter type.", dump(param_type)))
end
return func(val, name, param)
end
})
--[==[ func: export.convert_val(val, name, param)
Convert a parameter value according to the associated specs listed in the `params` table passed to
[[Module:parameters]]. `val` is the value to convert for a parameter whose name is `name` (used only in error messages).
`param` is the spec (the value part of the `params` table for the parameter). In place of passing in the parameter name,
`name` can be a function that throws an error, displaying the specified message along with the parameter name and value.
This function processes all the conversion-related fields in `param`, including `type`, `set`, `sublist`, `convert`,
etc. It returns the converted value.
]==]
local function convert_val(val, name, param, default)
local param_type = param.type or "string"
-- If param.type is a function, resolve it to a recognized type.
if is_callable(param_type) then
param_type = param_type(val)
end
local convert, sublist = param.convert, param.sublist
-- `val` might not be a string if it's the default value.
if sublist and type(val) == "string" then
local retlist, set = {}, param.set
if convert then
local thisindex, thisval, insval, parse_err = 0
if is_callable(name) then
-- We assume the passed-in error function in `name` already shows the parameter name and raw value.
function parse_err(msg)
name(format("%s: item #%s=%s",
msg_with_processed(msg, thisval, insval), thisindex, thisval)
)
end
else
function parse_err(msg)
error(format("%s: item #%s=%s of parameter %s=%s",
msg_with_processed(msg, thisval, insval), thisindex, thisval, name, val)
)
end
end
for v in split_sublist(val, name, sublist) do
thisindex, thisval = thisindex + 1, v
if set then
v = check_set(v, name, param, param_type)
end
insert(retlist, convert(type_handlers(v, name, param, param_type, default), parse_err))
end
else
for v in split_sublist(val, name, sublist) do
if set then
v = check_set(v, name, param, param_type)
end
insert(retlist, type_handlers(v, name, param, param_type, default))
end
end
return retlist
elseif param.set then
val = check_set(val, name, param, param_type)
end
local retval = type_handlers(val, name, param, param_type, default)
if convert then
local parse_err
if is_callable(name) then
-- We assume the passed-in error function in `name` already shows the parameter name and raw value.
if retval == val then
-- This is an optimization to avoid creating a closure. The second arm works correctly even
-- when retval == val.
parse_err = name
else
function parse_err(msg)
name(msg_with_processed(msg, val, retval))
end
end
else
function parse_err(msg)
error(format("%s: parameter %s=%s", msg_with_processed(msg, val, retval), name, val))
end
end
retval = convert(retval, parse_err)
end
-- If `sublist` is set but the input wasn't a string, return `retval` as a one-item list.
if sublist then
retval = {retval}
end
return retval
end
export.convert_val = convert_val -- used by [[Module:parameter utilities]]
local function unknown_param(name, val, args_unknown)
track("unknown parameters")
args_unknown[name] = val
return args_unknown
end
local function check_string_param_modifier(param_type, name, tag)
if param_type and not (param_type == "string" or param_type == "parameter" or is_callable(param_type)) then
internal_process_error(
"%s cannot be set unless %s is set to %s (the default), %s or a function: parameter %s has the type %s.",
tag, "type", "string", "parameter", name, param_type
)
end
end
local function hole_error(params, name, listname, this, nxt, extra)
-- `process_error` calls `dump` on values to be inserted into
-- error messages, but with numeric lists this causes "numeric"
-- to look like the name of the list rather than a description,
-- as `dump` adds quote marks. Insert it early to avoid this,
-- but add another %s specifier in all other cases, so that
-- actual list names will be displayed properly.
local offset, specifier, starting_from = 0, "%s", ""
local msg = "Item %%d in the list of %s parameters must be given if item %%d is given, because %sthere shouldn't be any gaps due to missing%s parameters."
local specs = {}
if type(listname) == "string" then
specs[2] = listname
elseif type(name) == "number" then
offset = name - 1 -- To get the original parameter.
specifier = "numeric"
-- If the list doesn't start at parameter 1, avoid implying
-- there can't be any gaps in the numeric parameters if
-- some parameter with a lower key is optional.
for j = name - 1, 1, -1 do
local _param = params[j]
if not (_param and _param.required) then
starting_from = format("(starting from parameter %d) ", dump(j + 1))
break
end
end
else
specs[2] = name
end
specs[1] = this + offset -- Absolute index for this item.
insert(specs, nxt + offset) -- Absolute index for the next item.
process_error(format(msg, specifier, starting_from, extra or ""), unpack(specs))
end
local function check_disallow_holes(params, val, name, listname, extra)
for i = 1, val.maxindex do
if val[i] == nil then
hole_error(params, name, listname, i, num_keys(val)[i], extra)
end
end
end
local function handle_holes(params, val, name)
local param = params[name]
local disallow_holes = param.disallow_holes
-- Iterate up the list, and throw an error if a hole is found.
if disallow_holes then
check_disallow_holes(params, val, name, param.list, " or empty")
end
-- Iterate up the list, and throw an error if a hole is found due to a
-- missing parameter, treating empty parameters as part of the list. This
-- applies beyond maxindex if blank arguments are supplied beyond it, so
-- isn't mutually exclusive with `disallow_holes`.
local empty = val.empty
if param.disallow_missing then
if empty then
-- Remove `empty` from `val`, so it doesn't get returned.
val.empty = nil
for i = 1, max(val.maxindex, empty.maxindex) do
if val[i] == nil and not empty[i] then
local keys = extend(num_keys(val), num_keys(empty))
sort(keys)
hole_error(params, name, param.list, i, keys[i])
end
end
-- If there's no table of empty parameters, the check is identical to
-- `disallow_holes`, except that the error message only refers to
-- missing parameters, not missing or empty ones. If `disallow_holes` is
-- also set, there's no point checking again.
elseif not disallow_holes then
check_disallow_holes(params, val, name, param.list)
end
end
-- If `allow_holes` is set, there's nothing left to do.
if param.allow_holes then
-- do nothing
-- Otherwise, remove any holes: `pairs` won't work, as it's unsorted, and
-- iterating from 1 to `maxindex` times out with inputs like |100000000000=,
-- so use num_keys to get a list of numerical keys sorted from lowest to
-- highest, then iterate up the list, moving each value in `val` to the
-- lowest unused positive integer key. This also avoids the need to create a
-- new table. If `disallow_holes` is specified, then there can't be any
-- holes in the list, so there's no reason to check again; this doesn't
-- apply to `disallow_missing`, however.
else
if not disallow_holes then
local keys, i = num_keys(val), 0
while true do
i = i + 1
local key = keys[i]
if key == nil then
break
elseif i ~= key then
track("holes compressed")
val[i], val[key] = val[key], nil
end
end
end
-- Some code depends on only numeric params being present when no holes are
-- allowed (e.g. by checking for the presence of arguments using next()), so
-- remove `maxindex`.
val.maxindex = nil
end
end
local function maybe_flatten(params, val, name)
local param = params[name]
if param.flatten then
if param.allow_holes then
process_error("For parameter %s, can't set both `allow_holes` and `flatten`", name)
end
if not param.sublist and param.type ~= "genders" and param.type ~= "labels" and
param.type ~= "references" and param.type ~= "qualifier" and param.type ~= "form of tags" then
process_error("For parameter %s, can only set `flatten` along with `sublist` or a list-generating type", name)
end
-- Do the flattening ourselves rather than calling flatten() in [[Module:table]], which will attempt to
-- flatten non-list objects like title objects, and cause an error in the process.
-- FIXME: We should do this in-place if possible.
local newlist = {}
for _, sublist in ipairs(val) do
for _, item in ipairs(sublist) do
insert(newlist, item)
end
end
val = newlist
end
return val
end
-- If both `template_default` and `default` are given, `template_default` takes precedence, but only on the template or
-- module page. This means a different default can be specified for the template or module page example. However,
-- `template_default` doesn't apply if any args are set, which helps (somewhat) with examples on documentation pages
-- transcluded into the template page. HACK: We still run into problems on documentation pages transcluded into the
-- template page when pagename= is set. Check this on the assumption that pagename= is fairly standard.
local function convert_default_val(name, param, pagename_set, any_args_set, add_empty_sublist)
if not pagename_set then
local val = param.template_default
if val ~= nil and not any_args_set and is_own_page() then
return convert_val(val, name, param, "template default")
end
end
local val = param.default
if val ~= nil then
return convert_val(val, name, param, "default")
-- Sublist parameters should return an empty table if not given, but only do
-- this if the parameter isn't also a list (in which case it will already
-- be an empty table).
-- FIXME: do this once all modules that pass in a sublist parameter treat an empty sublist identically to a nil argument; some currently do things based on the fact an argument exists at all.
-- elseif add_empty_sublist and param.sublist then
--return {}
end
end
--[==[
Process arguments with a given list of parameters. Return a table containing the processed arguments. The `args`
parameter specifies the arguments to be processed; they are the arguments you might retrieve from
{frame:getParent().args} (the template arguments) or in some cases {frame.args} (the invocation arguments). The `params`
parameter specifies a list of valid parameters, and consists of a table. If an argument is encountered that is not in
the parameter table, an error is thrown.
The structure of the `params` table is as described above in the intro comment.
'''WARNING:''' The `params` table is destructively modified to save memory. Nonetheless, different keys can share the
same value objects in memory without causing problems.
The `return_unknown` parameter, if set to {true}, prevents the function from triggering an error when it comes across an
argument with a name that it doesn't recognise. Instead, the return value is a pair of values: the first is the
processed arguments as usual, while the second contains all the unrecognised arguments that were left unprocessed. This
allows you to do multi-stage processing, where the entire set of arguments that a template should accept is not known at
once. For example, an inflection-table might do some generic processing on some arguments, but then defer processing of
the remainder to the function that handles a specific inflectional type.
]==]
function export.process(args, params, return_unknown)
-- Process parameters for specific properties
local args_new, args_unknown, any_args_set, required, patterns, list_args, index_list, args_placeholders, placeholders_n = {}
-- TODO: memoize the processing of each unique `param` value, since it's common for the same value to be used for many parameter names.
for name, param in pairs(params) do
validate_name(name, "parameter names")
if param ~= true then
local spec_type = type(param)
if type(param) ~= "table" then
internal_process_error(
"spec for parameter %s must be a table of specs or the value true, but found %s.",
name, spec_type ~= "boolean" and spec_type or param
)
end
-- Populate required table, and make sure aliases aren't set to required.
if param.required then
if required == nil then
required = {}
end
required[name] = true
end
local listname, alias_of = param.list, param.alias_of
if alias_of then
validate_name(alias_of, "the alias_of field of parameter ", name)
if alias_of == name then
internal_process_error(
"parameter %s cannot be an alias of itself.",
name
)
end
local main_param = params[alias_of]
-- Check that the alias_of is set to a valid parameter.
if not (main_param == true or type(main_param) == "table") then
internal_process_error(
"parameter %s is an alias of an invalid parameter.",
name
)
end
validate_alias_options(param, name, main_param, alias_of)
-- Aliases can't be lists unless the canonical parameter is also a list.
if listname and (main_param == true or not main_param.list) then
internal_process_error(
"list parameter %s is set as an alias of %s, which is not a list parameter.", name, alias_of
)
-- Can't be an alias of an alias.
elseif main_param ~= true then
local main_alias_of = main_param.alias_of
if main_alias_of ~= nil then
internal_process_error(
"alias_of cannot be set to another alias: parameter %s is set as an alias of %s, which is in turn an alias of %s. Set alias_of for %s to %s.",
name, alias_of, main_alias_of, name, main_alias_of
)
end
end
end
local replaced_by = param.replaced_by
if replaced_by then -- replaced_by can be `false`, which is OK
validate_name(replaced_by, "the replaced_by field of parameter ", name)
if replaced_by == name then
internal_process_error(
"parameter %s cannot be replaced by itself.",
name
)
end
local main_param = params[replaced_by]
-- Check that the replaced_by is set to a valid parameter.
if not (main_param == true or type(main_param) == "table") then
internal_process_error(
"parameter %s is set to be replaced by an invalid parameter.",
name
)
end
-- Can't be a replaced-by of a replaced-by.
if main_param ~= true then
local main_replaced_by = main_param.replaced_by
if main_replaced_by ~= nil then
internal_process_error(
"replaced_by cannot be set to another replaced-by parameter: parameter %s is set as replaced by %s, which is in turn replaced by %s. Set replaced_by for %s to %s.",
name, replaced_by, main_replaced_by, name, main_replaced_by
)
end
end
if param.instead ~= nil then
internal_process_error("the `instead` tag can only be given when `replaced_by` is set to `false`.")
end
elseif replaced_by == false then
if param.instead ~= nil and type(param.instead) ~= "string" then
internal_process_error(
"the `instead` tag must be a string, but saw %s.",
param.instead
)
end
end
if replaced_by ~= nil then
if param.reason ~= nil and type(param.reason) ~= "string" then
internal_process_error(
"the `reason` tag must be a string, but saw %s.",
param.reason
)
end
end
if listname then
if not alias_of then
local key = name
if type(name) == "string" then
key = gsub(name, "\1", "")
end
local list_arg = {maxindex = 0}
args_new[key] = list_arg
if list_args == nil then
list_args = {}
end
list_args[key] = list_arg
end
local list_type = type(listname)
if list_type == "string" then
-- If the list property is a string, then it represents the name
-- to be used as the prefix for list items. This is for use with lists
-- where the first item is a numbered parameter and the
-- subsequent ones are named, such as 1, pl2, pl3.
patterns = save_pattern(name, listname, patterns or {})
elseif listname ~= true then
internal_process_error(
"list field for parameter %s must be a boolean, string or undefined, but saw a %s.",
name, list_type
)
elseif type(name) == "number" then
if index_list ~= nil then
internal_process_error(
"only one numeric parameter can be a list, unless the list property is a string."
)
end
-- If the name is a number, then all indexed parameters from
-- this number onwards go in the list.
index_list = name
else
patterns = save_pattern(name, name, patterns or {})
end
if find(name, "\1", nil, true) then
if args_placeholders then
placeholders_n = placeholders_n + 1
args_placeholders[placeholders_n] = name
else
args_placeholders, placeholders_n = {name}, 1
end
end
end
end
end
--Process required changes to `params`.
if args_placeholders then
for i = 1, placeholders_n do
local name = args_placeholders[i]
params[gsub(name, "\1", "")], params[name] = params[name], nil
end
end
-- Process the arguments
for name, val in pairs(args) do
any_args_set = true
validate_name(name, "argument names", nil, true)
-- Guaranteeing that all values are strings avoids issues with type coercion being inconsistent between functions.
local val_type = type(val)
if val_type ~= "string" then
internal_process_error(
"argument %s has the type %s; all arguments must be strings.",
name, val_type
)
end
local orig_name, raw_type, index, canonical = name, type(name)
if raw_type == "number" then
if index_list and name >= index_list then
index = name - index_list + 1
name = index_list
end
elseif patterns then
-- Does this argument name match a pattern?
for pattern, pname in next, patterns do
index = match(name, pattern)
-- It matches, so store the parameter name and the
-- numeric index extracted from the argument name.
if index then
index = tonumber(index)
name = pname
break
end
end
end
local param = params[name]
-- If the argument is not in the list of parameters, store it in a separate list.
if not param then
args_unknown = unknown_param(name, val, args_unknown or {})
elseif param == true then
canonical = orig_name
val = php_trim(val)
if val ~= "" then
-- If the parameter is duplicated, throw an error.
if args_new[name] ~= nil then
process_error(
"Parameter %s has been entered more than once. This is probably because a parameter alias has been used.",
canonical
)
end
args_new[name] = val
end
else
if param.replaced_by == false then
process_error(
("Parameter %%s has been removed and is no longer valid%s.%s"):format(
param.reason and ", " .. param.reason or "",
param.instead and " Instead, " .. param.instead .. "." or ""),
name
)
elseif param.replaced_by then
process_error(
("Parameter %%s has been replaced by %%s%s."):format(
param.reason and ", " .. param.reason or ""),
name, param.replaced_by
)
end
if param.deprecated then
track("deprecated parameter", name)
end
if param.require_index then
-- Disallow require_index for numeric parameter names, as this doesn't make sense.
if raw_type == "number" then
internal_process_error(
"cannot set require_index for numeric parameter %s.",
name
)
-- If a parameter without the trailing index was found, and
-- require_index is set on the param, treat it
-- as if it isn't recognized.
elseif not index then
args_unknown = unknown_param(name, val, args_unknown or {})
end
end
-- Check that separate_no_index is not being used with a numeric parameter.
if param.separate_no_index then
if raw_type == "number" then
internal_process_error(
"cannot set separate_no_index for numeric parameter %s.",
name
)
elseif type(param.alias_of) == "number" then
internal_process_error(
"cannot set separate_no_index for parameter %s, as it is an alias of numeric parameter %s.",
name, param.alias_of
)
end
end
-- If no index was found, use 1 as the default index.
-- This makes list parameters like g, g2, g3 put g at index 1.
-- If `separate_no_index` is set, then use 0 as the default instead.
if not index and param.list then
index = param.separate_no_index and 0 or 1
end
-- Normalize to the canonical parameter name. If it's a list, but the alias is not, then determine the index.
local raw_name = param.alias_of
if raw_name then
raw_type = type(raw_name)
if raw_type == "number" then
name = raw_name
local main_param = params[raw_name]
if main_param ~= true and main_param.list then
if not index then
index = param.separate_no_index and 0 or 1
end
canonical = raw_name + index - 1
else
canonical = raw_name
end
else
name = gsub(raw_name, "\1", "")
local main_param = params[name]
if not index and main_param ~= true and main_param.list then
index = param.separate_no_index and 0 or 1
end
if not index or index == 0 then
canonical = name
elseif name == raw_name then
canonical = name .. index
else
canonical = gsub(raw_name, "\1", index)
end
end
else
canonical = orig_name
end
-- Only recognize demo parameters if this is the current template or module's
-- page, or its documentation page.
if param.demo and not is_own_page("include_documentation") then
args_unknown = unknown_param(name, val, args_unknown or {})
end
-- Remove leading and trailing whitespace unless no_trim is true.
if param.no_trim then
check_string_param_modifier(param.type, name, "no_trim")
else
val = php_trim(val)
end
-- Empty string is equivalent to nil unless allow_empty is true.
if param.allow_empty then
check_string_param_modifier(param.type, name, "allow_empty")
elseif val == "" then
-- If `disallow_missing` is set, keep track of empty parameters
-- via the `empty` field in `arg`, which will be used by the
-- `disallow_missing` check. This will be deleted before
-- returning.
if index and param.disallow_missing then
local arg = args_new[name]
local empty = arg.empty
if empty == nil then
empty = {maxindex = 0}
arg.empty = empty
end
empty[index] = true
if index > empty.maxindex then
empty.maxindex = index
end
end
val = nil
end
-- Allow boolean false.
if val ~= nil then
-- Convert to proper type if necessary.
local main_param = params[raw_name]
if main_param ~= true then
val = convert_val(val, orig_name, main_param or param)
end
-- Mark it as no longer required, as it is present.
if required then
required[name] = nil
end
-- Store the argument value.
if index then
local arg = args_new[name]
-- If the parameter is duplicated, throw an error.
if arg[index] ~= nil then
process_error(
"Parameter %s has been entered more than once. This is probably because a list parameter has been entered without an index and with index 1 at the same time, or because a parameter alias has been used.",
canonical
)
end
arg[index] = val
-- Store the highest index we find.
local maxindex = arg.maxindex
if index > maxindex then
maxindex = index
end
if arg[0] ~= nil then
arg.default, arg[0] = arg[0], nil
if maxindex < 1 then
maxindex = 1
end
end
arg.maxindex = maxindex
if not params[name].list then
args_new[name] = val
-- Don't store index 0, as it's a proxy for the default.
elseif index > 0 then
arg[index] = val
end
else
-- If the parameter is duplicated, throw an error.
if args_new[name] ~= nil then
process_error(
"Parameter %s has been entered more than once. This is probably because a parameter alias has been used.",
canonical
)
end
if not raw_name then
args_new[name] = val
else
local main_param = params[raw_name]
if main_param ~= true and main_param.list then
local main_arg = args_new[raw_name]
main_arg[1] = val
-- Store the highest index we find.
if main_arg.maxindex < 1 then
main_arg.maxindex = 1
end
else
args_new[raw_name] = val
end
end
end
end
end
end
-- Remove holes in any list parameters if needed. This must be handled
-- straight after the previous loop, as any instances of `empty` need to be
-- converted to nil.
if list_args then
for name, val in next, list_args do
handle_holes(params, val, name)
end
end
-- If the current page is the template which invoked this Lua instance, then ignore the `require` flag, as it
-- means we're viewing the template directly. Required parameters sometimes have a `template_default` key set,
-- which gets used in such cases as a demo.
-- Note: this won't work on other pages in the Template: namespace (including the /documentation subpage),
-- or if the #invoke: is on a page in another namespace.
local pagename_set = args_new.pagename
-- Handle defaults.
for name, param in pairs(params) do
if param ~= true then
local arg_new = args_new[name]
if arg_new == nil then
args_new[name] = convert_default_val(name, param, pagename_set, any_args_set, true)
elseif param.list and arg_new[1] == nil then
local default_val = convert_default_val(name, param, pagename_set, any_args_set)
if default_val ~= nil then
arg_new[1] = default_val
if arg_new.maxindex == 0 then
arg_new.maxindex = 1
end
end
end
end
end
-- Flatten nested lists if called for. This must come after setting the default.
if list_args then
for name, val in next, list_args do
args_new[name] = maybe_flatten(params, val, name)
end
end
-- The required table should now be empty.
-- If any parameters remain, throw an error, unless we're on the current template or module's page.
if required and next(required) ~= nil and not is_own_page() then
params_list_error(required, "required")
-- Return the arguments table.
-- If there are any unknown parameters, throw an error, unless return_unknown is set, in which case return args_unknown as a second return value.
elseif return_unknown then
return args_new, args_unknown or {}
elseif args_unknown and next(args_unknown) ~= nil then
params_list_error(args_unknown, "not used by this template")
end
return args_new
end
return export
c23kzesggrlowmn06oii7zu1bbzht4t
Padron:tempn
10
31082
178026
155332
2026-09-21T16:42:26Z
Yivan000
4078
wtf is this page, hardcoded lua error?!
178026
wikitext
text/x-wiki
#REDIRECT [[Template:temp]]
fpcs31dezxxqooyf29i9shtdyjaue69
Padron:workgroup ping
10
31097
178024
155360
2026-09-21T16:38:19Z
Yivan000
4078
Inilipat ni Yivan000 ang pahinang [[Padron:wgping]] sa [[Padron:workgroup ping]]
155360
wikitext
text/x-wiki
{{safesubst:<noinclude/>#invoke:workgroup ping|ping}}<noinclude>{{documentation}}</noinclude>
ib4h6arkzp1nefke7t2s4fwzq56y45q
saligang-batas
0
31615
178036
157118
2026-09-22T08:36:58Z
Yivan000
4078
Inilipat ni Yivan000 ang pahinang [[Saliga'ng Batas]] sa [[saligang-batas]] nang walang iniwang redirect
157118
wikitext
text/x-wiki
<span style="font-variant: small-caps;">Saligan Ng Batas</span> o <b><i>Saliga'ng Batas</i></b> ay isa'ng kasulata'ng pormal na nilikha at pinagtibay bilang batayan ng batas kung saan nasasalig ang bawat pananagutan at karapatan.ang
06f4ir0nuxk1fls4tjwo26b17lfquoe
Module:languages/data/3/c
828
32632
178030
175572
2026-09-22T01:30:43Z
Yivan000
4078
178030
Scribunto
text/plain
local m_langdata = require("Module:languages/data")
-- Loaded on demand, as it may not be needed (depending on the data).
local function u(...)
u = require("Module:string utilities").char
return u(...)
end
local c = m_langdata.chars
local p = m_langdata.puaChars
local s = m_langdata.shared
local m = {}
m["caa"] = {
"Ch'orti'",
35177,
"myn",
"Latn",
}
m["cab"] = {
"Garifuna",
35490,
"awd-taa",
"Latn",
ancestors = "crb",
}
m["cac"] = {
"Chuj",
35233,
"myn",
"Latn",
}
m["cad"] = {
"Caddo",
56756,
"cdd",
"Latn",
}
m["cae"] = {
"Laalaa",
35564,
"alv-cng",
"Latn",
}
m["caf"] = {
"Southern Carrier",
12953426,
"ath-nor",
"Latn",
}
m["cag"] = {
"Nivaclé",
3182557,
"sai-mtc",
"Latn",
}
m["cah"] = {
"Cahuarano",
2933175,
"sai-zap",
"Latn",
}
m["caj"] = {
"Chané",
56721,
"awd",
"Latn",
}
m["cak"] = {
"Kaqchikel",
35115,
"myn",
"Latn",
}
m["cal"] = {
"Carolinian",
28427,
"poz-mic",
"Latn",
}
m["cam"] = {
"Cèmuhî",
3009690,
"poz-cln",
"Latn",
}
m["can"] = {
"Chambri",
5069707,
"paa-lse",
"Latn",
}
m["cao"] = {
"Chácobo",
2591202,
"sai-pan",
"Latn",
}
m["cap"] = {
"Chipaya",
35235,
"sai-ucp",
"Latn",
}
m["caq"] = {
"Car Nicobarese",
35156,
"aav-nic",
"Latn, Deva",
}
m["car"] = {
"Karîña", --TLCHANGE use î since it has a glottal stop after it
56611,
"sai-gui",
"Latn",
sort_key = {remove_diacritics = c.grave .. c.acute .. c.circ .. "`" .. "'%-%s"},
strip_diacritics = {
remove_diacritics = c.acute,
from = {"â", "ê", "î", "ô", "û", "ŷ"},
to = {"à", "è", "ì", "ò", "ù", "ỳ"}
},
english_name = "Kari'na", --TLCHANGE
spanish_name = "Kariña", --TLCHANGE
}
m["cas"] = {
"Tsimané",
35950,
"qfa-dis", -- isolate or in a putative Putative Mosetan-Chonan family
"Latn",
}
m["cav"] = {
"Cavineña",
524102,
"sai-tac",
"Latn",
}
m["caw"] = {
"Kallawaya",
266417,
"qfa-mix",
"Latn",
}
m["cax"] = {
"Chiquitano",
1844993,
"qfa-iso", -- isolate or Macro-Jê
"Latn",
}
m["cay"] = {
"Cayuga",
32967,
"iro-nor",
"Latn",
}
m["caz"] = {
"Canichana",
2936374,
"qfa-dis", -- isolate, unclassified or in a putative Tequiraca-Canichana family
"Latn",
}
m["cbb"] = {
"Cabiyarí",
3450660,
"awd-nwk",
"Latn",
}
m["cbc"] = {
"Carapana",
924405,
"sai-tuc",
"Latn",
}
m["cbd"] = {
"Carijona",
3446655,
"sai-tar",
"Latn",
}
m["cbg"] = {
"Chimila",
2963680,
"cba",
"Latn",
}
m["cbi"] = {
"Chachi",
2591329,
"sai-bar",
"Latn",
}
m["cbj"] = {
"Ede Cabe",
33112829,
"alv-ede",
"Latn",
}
m["cbk"] = {
"Chabacano", --"Chavacano",
33281,
"crp",
"Latn",
ancestors = "es",
strip_diacritics = {remove_diacritics = c.grave .. c.acute .. c.circ .. c.diaer},
sort_key = {
from = {"ch", "ll", "ñ", "r"},
to = {"c" .. p[1], "l" .. p[1], "n" .. p[1], "r" .. p[1]}
},
standard_chars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnÑñOoPpQqRrSsTtUuVvWwXxYyZz" .. c.punc,
is_official_kwf_name = "https://kwfwikaatkultura.ph/chabacano/", --TLCHANGE
english_name = "Chavacano", --TLCHANGE
}
m["cbl"] = {
"Bualkhaw Chin",
9229830,
"tbq-kuk",
"Latn",
}
m["cbn"] = {
"Nyah Kur",
116849,
"mkh-mnc",
"Thai",
ancestors = "omx",
sort_key = "Thai-sortkey",
}
m["cbo"] = {
"Izora",
3915454,
"nic-jer",
"Latn",
}
m["cbq"] = {
"Tsucuba",
62603062,
"nic-knj",
"Latn",
}
m["cbr"] = {
"Cashibo-Cacataibo",
5359560,
"sai-pan",
"Latn",
}
m["cbs"] = {
"Cashinahua",
2591230,
"sai-pan",
"Latn",
}
m["cbt"] = {
"Chayahuita",
1526525,
"sai-cah",
"Latn",
}
m["cbu"] = {
"Candoshi-Shapra",
642843,
"qfa-dis", -- isolate or related to extinct Chirino; Kaufman (2007) puts it in Saparo-Yawan, Jolkesky (2016) as
-- Macro-Arawakan
"Latn",
}
m["cbv"] = {
"Cacua",
3192052,
"sai-nad",
"Latn",
ancestors = "mbr",
}
m["cbw"] = {
"Kabalianon", --"Kinabalian",
6410324,
"phi",
"Latn",
is_official_kwf_name = "https://kwfwikaatkultura.ph/kabalianon/", --TLCHANGE
english_name = "Kinabalian" --TLCHANGE
}
m["cby"] = {
"Carabayo",
3441762,
"sai-tyu",
"Latn",
}
m["cca"] = {
"Cauca",
5054242,
"sai-chc",
"Latn",
}
m["ccc"] = {
"Chamicuro",
2155119,
"awd",
"Latn",
}
m["ccd"] = {
"Cafundó",
3331506,
"roa-gap",
"Latn",
ancestors = "pt",
}
m["cce"] = {
"Chopi",
3437616,
"bnt-bso",
"Latn",
}
m["ccg"] = {
"Chamba Daka",
33120805,
"nic-dak",
"Latn",
}
m["cch"] = {
"Atsam",
34794,
"nic-kne",
"Latn",
}
m["ccj"] = {
"Kasanga",
35542,
"alv-nyn",
"Latn",
}
m["ccl"] = {
"Cutchi-Swahili",
5196729,
"crp",
"Latn",
ancestors = "sw",
}
m["ccm"] = {
"Malaccan Creole Malay",
12636092,
"crp",
"Latn",
ancestors = "ms",
}
m["cco"] = {
"Comaltepec Chinantec",
2963735,
"omq-chi",
"Latn",
}
m["ccp"] = {
"Chakma",
32952,
"inc-bas",
"Cakm, Beng, Latn",
ancestors = "inc-obn",
translit = {
Cakm = "Cakm-translit",
--Beng = "Beng-translit",
},
}
m["ccr"] = {
"Cacaopera",
3438338,
"nai-min",
"Latn",
}
m["cda"] = {
"Choni",
2964447,
"sit-tib",
}
m["cde"] = {
"Chenchu",
32981,
"dra-tel",
"Telu",
}
m["cdf"] = {
"Chiru",
5102016,
"tbq-kuk",
"Latn, Beng",
}
m["cdh"] = {
"Chambeali",
12953424,
"him",
"Deva, Takr",
translit = {
Deva = "hi-translit"
},
}
m["cdi"] = {
"Chodri",
5103788,
"inc-bhi",
"Gujr",
}
m["cdj"] = {
"Churahi",
12629039,
"him",
"Deva, Takr",
translit = {
Deva = "hi-translit"
},
}
m["cdm"] = {
"Chepang",
5091700,
"sit-gma",
"Deva",
}
m["cdn"] = {
"Chaudangsi",
5088056,
"sit-alm",
}
m["cdo"] = {
"Silanganang Min", --TLCHANGE
36455,
"zhx-com",
"Hants",
generate_forms = "zh-generateforms",
translit = "zh-translit",
sort_key = "Hani-sortkey",
english_name = "Eastern Min", --TLCHANGE
}
m["cdr"] = {
"Cinda-Regi-Tiyal",
35596,
"nic-kmk",
"Latn",
}
m["cds"] = {
"Chadian Sign Language",
10322099,
"sgn",
"Latn", -- when documented
}
m["cdy"] = {
"Chadong",
926742,
"qfa-kms",
}
m["cdz"] = {
"Koda",
6425038,
"mun",
"Beng",
}
m["cea"] = {
"Lower Chehalis",
6693377,
"sal",
"Latn",
}
m["ceb"] = {
"Sebwano", --"Cebuano",
33239,
"phi",
"Latn, Tglg",
translit = {
Tglg = "ceb-translit"
},
override_translit = true,
strip_diacritics = {
Latn = {
remove_diacritics = c.grave .. c.acute .. c.circ
}
},
sort_key = {
Latn = "tl-sortkey",
},
standard_chars = {
Latn = "AaBbKkDdEeGgHhIiLlMmNnOoPpRrSsTtUuWwYy",
c.punc
},
is_official_kwf_name = "https://kwfwikaatkultura.ph/sebwano-2/", --TLCHANGE
english_name = "Cebuano" --TLCHANGE
}
m["ceg"] = {
"Chamacoco",
3436637,
"sai-zam",
"Latn",
}
m["cen"] = {
"Cen",
12628777,
"nic-plc",
"Latn",
ancestors = "izr",
}
m["cet"] = {
"Centúúm",
33608,
"qfa-iso", -- northeastern Nigeria
"Latn",
}
m["cfa"] = {
"Dijim-Bwilim",
3438350,
"alv-wjk",
"Latn",
}
m["cfd"] = {
"Cara",
35048,
"nic-beo",
"Latn",
}
m["cfg"] = {
"Como Karim",
35304,
"nic-jkn",
"Latn",
}
m["cfm"] = {
"Falam Chin",
56815,
"tbq-kuk",
"Beng, Latn",
}
m["cga"] = {
"Changriwa",
5072105,
"paa-yua",
"Latn",
}
m["cgc"] = {
"Kagayanën", --"Kagayanen",
6346422,
"mno",
"Latn",
is_official_kwf_name = "https://kwfwikaatkultura.ph/kagayanen/", --TLCHANGE
english_name = "Kagayanen" --TLCHANGE
}
m["cgg"] = {
"Rukiga",
3270727,
"bnt-nyg",
"Latn",
}
m["cgk"] = {
"Chocangaca",
56604,
"sit-tib",
"Tibt",
ancestors = "xct",
override_translit = true,
-- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]]
}
m["chb"] = {
"Chibcha",
2356431,
"cba",
"Latn",
}
m["chc"] = {
"Catawba",
5051602,
"nai-cat",
"Latn",
}
m["chd"] = {
"Highland Oaxaca Chontal",
2964457,
"nai-tqn",
"Latn",
}
m["chf"] = {
"Chontal Maya",
35175,
"myn",
"Latn",
}
m["chg"] = {
"Chagatai",
36831,
"trk-kar",
"Arab, Ougr",
ancestors = "zkh",
strip_diacritics = {
remove_diacritics = c.kashida .. c.fathatan .. c.dammatan .. c.kasratan .. c.fatha .. c.damma .. c.kasra .. c.shadda .. c.sukun .. c.superalef,
from = {u(0x0671)},
to = {u(0x0627)}
},
translit = {
Arab = "chg-translit",
Ougr = "Ougr-translit",
},
}
m["chh"] = {
"Chinook",
6693380,
"nai-ckn",
"Latn",
}
m["chj"] = {
"Ojitlán Chinantec",
5100110,
"omq-chi",
"Latn",
}
m["chk"] = {
"Chuukese",
33161,
"poz-mic",
"Latn",
}
m["chl"] = {
"Cahuilla",
56438,
"azc-cup",
"Latn",
strip_diacritics = {remove_diacritics = c.acute .. c.macron},
}
-- chm "Mari" is not recognized as a language, but it is a family code
m["chn"] = {
"Chinook Jargon",
35173,
"crp",
"Latn, Dupl",
ancestors = "chh, nuk",
}
m["cho"] = {
"Choctaw",
32979,
"nai-mus",
"Latn",
sort_key = {remove_diacritics = c.macronbelow .. "-"},
strip_diacritics = {remove_diacritics = c.acute .. c.dotbelow},
}
m["chp"] = {
"Chipewyan",
27692,
"ath-nor",
"Latn, Cans",
}
m["chq"] = {
"Quiotepec Chinantec",
5758709,
"omq-chi",
"Latn",
}
m["chr"] = {
"Tseroki", --TLCHANGE
33388,
"iro",
"Cher",
translit = "Cher-translit",
english_name = "Cherokee", --TLCHANGE
spanish_name = "Cheroqui", --TLCHANGE
}
m["cht"] = {
"Cholón",
2591243,
"qfa-unc", -- poorly attested; possibly in a Hibito-Cholon or Cholonan family
"Latn",
}
m["chw"] = {
"Chuabo",
5118412,
"bnt-mak",
"Latn",
}
m["chx"] = {
"Chantyal",
4926344,
"sit-tam",
"Deva",
}
m["chy"] = {
"Tseyene", --TLCHANGE
33265,
"alg",
"Latn",
sort_key = {remove_diacritics = c.grave .. c.acute .. c.macron .. c.dotabove .. "-"},
standard_chars = "AaÁáÀàĀāȦȧEeÉéÈèĒēĖėHhKkMmNnOoÓóÒòŌōȮȯPpSsŠšTtVvXx" .. c.punc, --umlaut and circumflex not allowed
english_name = "Cheyenne", --TLCHANGE
spanish_name = "Cheyene", --TLCHANGE
}
m["chz"] = {
"Ozumacín Chinantec",
5100111,
"omq-chi",
"Latn",
}
m["cia"] = {
"Cia-Cia",
35284,
"poz-mun",
"Hang, Latn, Arab",
}
m["cib"] = {
"Ci Gbe",
12952445,
"alv-gbe",
"Latn",
}
m["cic"] = {
"Tsikasaw", --TLCHANGE
33192,
"nai-mus",
"Latn",
english_name = "Chickasaw", --TLCHANGE
}
m["cid"] = {
"Chimariko",
1294251,
"qfa-iso", -- possibly Hokan
"Latn",
}
m["cie"] = {
"Cineni",
56243,
"cdc-cbm",
"Latn",
}
m["cih"] = {
"Chinali",
11855245,
"inc",
"Deva",
ancestors = "sa",
}
m["cik"] = {
"Chitkuli Kinnauri",
15615982,
"sit-kin",
}
m["cim"] = {
"Simbriyano", --TLCHANGE
37053,
"gmw-hgm",
"Latn",
ancestors = "bar",
sort_key = {remove_diacritics = c.grave .. c.acute .. c.circ .. c.diaer .. c.ringabove .. c.caron},
english_name = "Cimbrian", --TLCHANGE
spanish_name = "Cimbriano", --TLCHANGE
}
m["cin"] = {
"Cinta Larga",
5121095,
"tup",
"Latn",
}
m["cip"] = {
"Chiapanec",
3364475,
"omq",
"Latn",
}
m["cir"] = {
"Tinrin",
7862281,
"poz-cln",
"Latn",
}
m["ciy"] = {
"Chaima",
12628867,
"sai-ven",
"Latn",
}
m["cja"] = {
"Western Cham",
12645578,
"cmc",
"Latn, Arab, Khmr, Cham", -- Western Cham script is not yet available. Also, Arabic script is missing some glyphs.
}
m["cje"] = {
"Chru",
2967321,
"cmc",
"Latn",
}
m["cjh"] = {
"Upper Chehalis",
2962074,
"sal",
"Latn",
}
m["cji"] = {
"Chamalal",
56567,
"cau-and",
"Cyrl",
translit = "cau-nec-translit",
override_translit = true,
display_text = s["cau-Cyrl-displaytext"],
strip_diacritics = s["cau-Cyrl-stripdiacritics"],
}
m["cjk"] = {
"Chokwe",
2422065,
"bnt-clu",
"Latn",
}
m["cjm"] = {
"Eastern Cham",
2948019,
"cmc",
"Latn, Cham",
}
m["cjn"] = {
"Chenapian",
5091044,
"paa-sep",
"Latn",
}
m["cjo"] = {
"Pajonal Ashéninka",
3450481,
"awd",
"Latn",
}
m["cjp"] = {
"Cabécar",
27878,
"cba",
"Latn",
}
m["cjs"] = {
"Shor",
34139,
"trk-ssb",
"Cyrl",
}
m["cjv"] = {
"Chuave",
5115226,
"ngf-sim",
"Latn",
}
m["cjy"] = {
"Jin",
56479,
"zhx",
"Hants",
ancestors = "ltc",
generate_forms = "zh-generateforms",
translit = "zh-translit",
sort_key = "Hani-sortkey",
}
m["ckb"] = {
"Kurdo Sentral", --TLCHANGE
36811,
"ku",
"ku-Arab",
translit = "ckb-translit",
strip_diacritics = {remove_diacritics = c.kasra .. c.sukun},
english_name = "Central Kurdish", --TLCHANGE
spanish_name = "Kurdo central", --TLCHANGE
}
m["ckh"] = {
"Chak",
12628870,
"sit-luu",
"Latn",
ancestors = "kdv",
}
m["ckl"] = {
"Cibak",
56279,
"cdc-cbm",
"Latn",
}
m["ckn"] = {
"Kaang Chin",
6343432,
"tbq-kuk",
"Latn",
}
m["cko"] = {
"Anufo",
34845,
"alv-ctn",
"Latn",
}
m["ckq"] = {
"Kajakse",
3440422,
"cdc-est",
"Latn",
}
m["ckr"] = {
"Kairak",
3503002,
"paa-bai",
"Latn",
}
m["cks"] = {
"Tayo",
1133089,
"crp",
"Latn",
ancestors = "fr",
sort_key = s["roa-oil-sortkey"],
}
m["ckt"] = {
"Chukchi",
33170,
"qfa-ckn",
"Cyrl, Latn", -- Latn is obsolete
strip_diacritics = {
from = {"['’]"},
to = {"ʼ"}
},
sort_key = {
from = {"ё", "ӄ", "ԓ", "ӈ"},
to = {"е" .. p[1], "к" .. p[1], "л" .. p[1], "н" .. p[1]}
},
}
m["cku"] = {
"Koasati",
35162,
"nai-mus",
"Latn",
}
m["ckv"] = {
"Kavalan",
716627,
"map",
"Latn",
}
m["ckx"] = {
"Caka",
5018037,
"nic-tvc",
"Latn",
}
m["cky"] = {
"Cakfem-Mushere",
3441199,
"cdc-wst",
"Latn",
}
m["ckz"] = {
"Kaqchikel-K'iche' Mixed Language",
5054550,
"qfa-mix",
"Latn",
ancestors = "cak, quc"
}
m["cla"] = {
"Ron",
3440432,
"cdc-wst",
"Latn",
}
m["clc"] = {
"Chilcotin",
28535,
"ath-nor",
"Latn",
}
m["cld"] = {
"Chaldean Neo-Aramaic",
33236,
"sem-are",
"Syrc",
strip_diacritics = "Syrc-stripdiacritics",
}
m["cle"] = {
"Lealao Chinantec",
6509365,
"omq-chi",
"Latn",
}
m["clh"] = {
"Chilisso",
3250629,
"inc-koh",
"ur-Arab",
}
m["cli"] = {
"Chakali",
35206,
"nic-gnw",
"Latn",
}
m["clj"] = {
"Laitu Chin",
6474196,
"tbq-kuk",
}
m["clk"] = {
"Idu",
56412,
"sit-gsi",
"Tibt, Deva",
override_translit = true,
-- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]]
}
m["cll"] = {
"Chala",
35190,
"nic-gne",
"Latn",
}
m["clm"] = {
"Klallam",
33404,
"sal",
"Latn",
}
m["clo"] = {
"Lowland Oaxaca Chontal",
2964450,
"nai-tqn",
"Latn",
}
m["clt"] = {
"Lutuv",
6502107,
"tbq-kuk",
"Latn",
}
m["clu"] = {
"Kaluyanën", --"Caluyanun",
32964,
"phi",
"Latn",
is_official_kwf_name = "https://kwfwikaatkultura.ph/kaluyanen/", --TLCHANGE
english_name = "Caluyanun" --TLCHANGE
}
m["clw"] = {
"Chulym",
33125,
"trk-ssb",
"Latn, Cyrl",
}
m["cly"] = {
"Eastern Highland Chatino",
12642078,
"omq-cha",
"Latn",
}
m["cma"] = {
"Mạ",
12953680,
"mkh-ban",
"Latn",
}
m["cme"] = {
"Cerma",
35074,
"nic-gur",
"Latn",
}
m["cmg"] = {
"Classical Mongolian",
5128303,
"xgn-cen",
"Mong, Soyo, Zanb",
-- Mong translit, display_text and strip_diacritics in [[Module:scripts/data]]
}
m["cmi"] = {
"Emberá-Chamí",
3052042,
"sai-chc",
"Latn",
}
m["cml"] = {
"Campalagian",
5027893,
"poz-ssw",
"Latn",
}
m["cmm"] = {
"Michigamea",
12636809,
"sio-msv",
"Latn",
}
m["cmn"] = {
"Mandarin",
9192,
"zhx-man",
"Hants, Latn, Bopo, Brai",
wikimedia_codes = "zh",
generate_forms = "zh-generateforms",
translit = {
Hani = "zh-translit",
Bopo = "zh-translit",
},
sort_key = {
Hani = "Hani-sortkey",
Latn = {
from = {
-- Sort terms with tone numbers immediately after equivalent terms with diacritics.
"[aeiouv][" .. c.circ .. c.diaer .. "]?[nr]?g?[0-5]",
-- Add temporary breaks between syllables.
"([aeiouvmn][" .. c.circ .. c.diaer .. "]?[" .. c.macron .. c.acute .. c.caron .. c.grave .. "]?n?ŋ?g?r?)([bpmfdtnlgkhjqxzcsywrv']h?[aeiouvmn ])", p[1] .. "([ngr])$", p[1] .. "([ngr][%s%-'" .. p[1] .. "])",
-- Substitute diacritics for syllable-final tone numbers, and add tone 0 where necessary.
c.macron, c.acute, c.caron, c.grave, "([1-4])([^%s%p" .. p[1] .. "]+)", "([^0-5])%f[%z%s%p" .. p[1] .. "]",
-- Substitute "v" shorthand for "ü" for a temporary placeholder, so that the (very rare) "v" initial is not affected by the later shorthand substitutions.
"([^ " .. p[1] .. "])v",
-- Remove temporary breaks.
p[1],
-- Substitute shorthands for full forms, and sort them immediately after equivalent terms.
"%S*[csz]" .. c.circ .. "%S*", "%S*[ŋ" .. p[2] .. "]%S*", "ĉ", "ŝ", "ŋ", p[2], "ẑ",
-- "ê" comes after "e", "ü" comes after "u" and apostrophes are removed (as their function is replaced by tone numbers).
"[" .. c.circ .. c.diaer .. "]", "'",
-- Sort numbered tone 5 after tone 0.
"5!"
},
to = {
"%0!",
"%1" .. p[1] .. "%2", "%1", "%1",
"1", "2", "3", "4", "%2%1", "%10",
"%1" .. p[2],
"",
"%0\"", "%0\"", "ch", "sh", "ng", "ü", "zh",
p[1], "",
"0!!"
}
},
},
}
m["cmo"] = {
"Central Mnong",
33369881,
"mkh-ban",
"Khmr, Latn",
}
m["cmr"] = {
"Mro Chin",
16889978,
"tbq-kuk",
}
m["cms"] = {
"Messapic",
36383,
"ine",
"Ital, Latn, Polyt",
-- Ital translit in [[Module:scripts/data]]
-- Polyt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]]
}
m["cmt"] = {
"Camtho",
10441336,
"crp",
"Latn",
ancestors = "fly, zu"
}
m["cna"] = {
"Changthang",
12952322,
"sit-lab",
"Tibt",
override_translit = true,
-- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]]
}
m["cnb"] = {
"Chinbon Chin",
12952327,
"tbq-kuk",
"Latn",
}
m["cnc"] = {
"Cốông",
5202780,
"tbq-bis",
"Latn",
}
m["cng"] = {
"Northern Qiang",
56559,
"sit-qia",
"Latn",
}
m["cnh"] = {
"Lai",
3250286,
"tbq-kuk",
"Latn, Mymr",
}
m["cni"] = {
"Asháninka",
3437230,
"awd",
"Latn",
}
m["cnk"] = {
"Khumi Chin",
56308,
"tbq-kuk",
"Latn",
}
m["cnl"] = {
"Lalana Chinantec",
12953437,
"omq-chi",
"Latn",
}
m["cno"] = {
"Con",
3440883,
"mkh-pal",
}
m["cnp"] = {
"Northern Pinghua",
84302463,
"zhx-pin",
"Hants",
generate_forms = "zh-generateforms",
sort_key = "Hani-sortkey",
}
m["cns"] = {
"Central Asmat",
11732048,
"ngf-asm",
"Latn",
}
m["cnt"] = {
"Tepetotutla Chinantec",
5100113,
"omq-chi",
"Latn",
}
m["cnu"] = {
"Chenoua",
33276,
"ber",
"Latn",
}
m["cnw"] = {
"Ngawn Chin",
6583675,
"tbq-kuk",
}
m["cnx"] = {
"Middle Cornish",
12642603,
"cel-brs",
"Latn",
ancestors = "oco",
}
m["coa"] = {
"Cocos Islands Malay",
3441699,
"crp",
"Latn",
ancestors = "ms",
}
m["cob"] = {
"Chicomuceltec",
3307204,
"myn",
"Latn",
}
m["coc"] = {
"Cocopa",
33044,
"nai-yuc",
"Latn",
}
m["cod"] = {
"Cocama",
33317,
"tup",
"Latn",
}
m["coe"] = {
"Koreguaje",
3198924,
"sai-tuc",
"Latn",
}
m["cof"] = {
"Tsafiki",
2567055,
"sai-bar",
"Latn",
}
m["cog"] = {
"Chong",
3914630,
"mkh-pea",
"Thai, Khmr",
sort_key = {
Thai = "Thai-sortkey"
},
}
m["coh"] = {
"Chichonyi-Chidzihana-Chikauma",
12629011,
"bnt-mij",
"Latn",
}
m["coj"] = {
"Cochimi",
3915551,
"nai-yuc",
"Latn",
}
m["cok"] = {
"Santa Teresa Cora",
12641754,
"azc",
"Latn",
}
m["col"] = {
"Columbia-Wenatchi",
3324744,
"sal",
"Latn",
}
m["com"] = {
"Comanche",
32972,
"azc-num",
"Latn",
}
m["con"] = {
"Cofán",
2669254,
"qfa-iso",
"Latn",
}
m["coo"] = {
"Comox",
13583746,
"sal",
"Latn",
}
m["cop"] = {
"Coptic",
36155,
"egx",
"Copt",
translit = "Copt-translit",
ancestors = "egx-dem",
strip_diacritics = {remove_diacritics = c.grave .. c.macron .. c.overline .. c.diaer .. "ˋ"},
sort_key = "Copt-sortkey",
}
m["coq"] = {
"Coquille",
12953452,
"ath-pco",
"Latn",
}
m["cot"] = {
"Caquinte",
3915557,
"awd",
"Latn",
}
m["cou"] = {
"Wamey",
36935,
"alv-ten",
"Latn",
}
m["cov"] = {
"Cao Miao",
2936935,
"qfa-tak",
}
m["cow"] = {
"Cowlitz",
3001877,
"sal",
"Latn",
}
m["cox"] = {
"Nanti",
15342275,
"awd",
"Latn",
}
m["coy"] = {
"Coyaima",
56450,
"sai-car",
"Latn",
}
m["coz"] = {
"Chochotec",
2964262,
"omq-pop",
"Latn",
}
m["cpa"] = {
"Palantla Chinantec",
5100112,
"omq-chi",
"Latn",
}
m["cpb"] = {
"Ucayali-Yurúa Ashéninka",
3501858,
"awd",
"Latn",
}
m["cpc"] = {
"Apurucayali Ashéninka",
3327405,
"awd",
"Latn",
}
m["cpg"] = {
"Cappadocian Greek",
853414,
"grk",
"Grek, fa-Arab",
ancestors = "gkm",
translit = {
Grek = "el-translit",
},
-- Grek display_text, strip_diacritics, sort_key in [[Module:scripts/data]]
}
m["cpi"] = {
"Chinese Pidgin English",
3435078,
"crp",
"Latn, Hant",
ancestors = "en",
sort_key = {
Hant = "Hani-sortkey"
},
}
m["cpn"] = {
"Cherepon",
35181,
"alv-gng",
"Latn",
}
m["cpo"] = {
"Kpee",
6435722,
"dmn-jje",
}
m["cps"] = {
"Capiznon",
2937525,
"phi",
"Latn",
}
m["cpu"] = {
"Pichis Ashéninka",
7190661,
"awd",
"Latn",
}
m["cpx"] = {
"Puxian Min",
56583,
"zhx-com",
"Hants",
generate_forms = "zh-generateforms",
sort_key = "Hani-sortkey",
}
m["cpy"] = {
"South Ucayali Ashéninka",
3501868,
"awd",
"Latn",
}
m["cqd"] = {
"Chuanqiandian Cluster Miao",
121627627,
"hmn",
"Latn, Plrd",
}
m["cra"] = {
"Chara",
5073694,
"omv",
"Latn",
}
m["crb"] = {
"Kalinago",
3450735,
"awd-taa",
"Latn",
}
m["crc"] = {
"Lonwolwol",
3259216,
"poz-vnc",
"Latn",
}
m["crd"] = {
"Coeur d'Alene",
32915,
"sal",
"Latn",
}
m["crf"] = {
"Caramanta",
3504195,
"sai-chc",
"Latn",
}
m["crg"] = {
"Michif",
13315,
"qfa-mix",
"Latn",
ancestors = "cr, fr",
}
m["crh"] = {
"Crimean Tatar",
33357,
"trk-kcu",
"Latn, Cyrl",
dotted_dotless_i = true,
sort_key = {
Latn = {
from = {
"[ıi]" .. c.breve, -- Convert ĭ into PUA so that the decomposed form does not get caught by the next step. Also cover decomposed forms with ı and i, as decomposed Ĭ is converted to ı + ̆ due to the dotted dotless I logic).
"i", -- Ensure "i" comes after "ı".
"â", "ç", "ğ", "ı", p[3], "ñ", "ö", "ş", "ü"
},
to = {
p[3],
"i" .. p[1],
"a", "c" .. p[1], "g" .. p[1], "i", "i" .. p[2], "n" .. p[1], "o" .. p[1], "s" .. p[1], "u" .. p[1],
}
},
Cyrl = {
from = {"гъ", "ё", "къ", "нъ", "дж"},
to = {"г" .. p[1], "е" .. p[1], "к" .. p[1], "н" .. p[1], "ч" .. p[1]}
},
},
}
m["cri"] = {
"Sãotomense",
36536,
"crp",
"Latn",
ancestors = "pt",
}
m["crj"] = {
"Southern East Cree",
12953464,
"alg",
"Latn, Cans",
ancestors = "cr",
translit = {
Cans = "cr-translit"
},
}
m["crk"] = {
"Plains Cree",
56699,
"alg",
"Latn, Cans",
ancestors = "cr",
}
m["crl"] = {
"Northern East Cree",
12642195,
"alg",
"Latn, Cans",
ancestors = "cr",
translit = {
Cans = "cr-translit"
},
}
m["crm"] = {
"Moose Cree",
3446671,
"alg",
"Latn, Cans",
ancestors = "cr",
}
m["crn"] = {
"Cora",
12953454,
"azc",
"Latn",
}
m["cro"] = {
"Crow",
1207611,
"sio-mor",
"Latn",
}
m["crq"] = {
"Iyo'wujwa Chorote",
3540927,
"sai-mtc",
"Latn",
}
m["crr"] = {
"Carolina Algonquian",
16113723,
"alg-eas",
"Latn",
}
m["crs"] = {
"Seychellois Creole",
34015,
"crp",
"Latn",
ancestors = "fr",
sort_key = s["roa-oil-sortkey"],
}
m["crt"] = {
"Chorote Iyojwa'ja", --TLCHANGE
3504118,
"sai-mtc",
"Latn",
english_name = "Iyojwa'ja Chorote", --TLCHANGE
}
m["crv"] = {
"Chaura",
2605680,
"aav-nic",
"Latn",
}
m["crw"] = {
"Chrau",
5105629,
"mkh-ban",
"Latn",
}
m["crx"] = {
"Carrier",
12953431,
"ath-nor",
"Latn, Cans",
}
m["cry"] = {
"Cori",
35204,
"nic-plc",
"Latn",
}
m["crz"] = {
"Cruzeño",
2967636,
"nai-chu",
"Latn",
}
m["csa"] = {
"Chiltepec Chinantec",
12953435,
"omq-chi",
"Latn",
}
m["csb"] = {
"Kashubian",
33690,
"zlw-pom",
"Latn",
}
m["csc"] = {
"Catalan Sign Language",
35768,
"sgn",
"Latn", -- when documented
}
m["csd"] = {
"Chiangmai Sign Language",
5095211,
"sgn",
}
m["cse"] = {
"Czech Sign Language",
5201809,
"sgn",
"Latn", -- when documented
}
m["csf"] = {
"Cuban Sign Language",
5192046,
"sgn",
"Latn", -- when documented
}
m["csg"] = {
"Chilean Sign Language",
3322112,
"sgn",
"Latn", -- when documented
}
m["csh"] = {
"Asho Chin",
12627282,
"tbq-kuk",
"Latn, Mymr",
}
m["csi"] = {
"Coast Miwok",
2981109,
"nai-utn",
"Latn",
}
m["csj"] = {
"Songlai Chin",
7561280,
"tbq-kuk",
}
m["csk"] = {
"Jola-Kasa",
3446622,
"alv-jol",
"Latn",
}
m["csl"] = {
"Chinese Sign Language",
1094190,
"sgn",
}
m["csm"] = {
"Central Sierra Miwok",
2944443,
"nai-utn",
"Latn",
}
m["csn"] = {
"Colombian Sign Language",
2748229,
"sgn",
"Latn", -- when documented
}
m["cso"] = {
"Sochiapam Chinantec",
7550388,
"omq-chi",
"Latn",
}
m["csp"] = {
"Katimugang Pinghua", --TLCHANGE
84302019,
"zhx-pin",
"Hants",
generate_forms = "zh-generateforms",
translit = "zh-translit",
sort_key = "Hani-sortkey",
english_name = "Southern Pinghua", --TLCHANGE
}
m["csq"] = {
"Croatian Sign Language",
3507506,
"sgn",
}
m["csr"] = {
"Costa Rican Sign Language",
5174901,
"sgn",
"Latn", -- when documented
}
m["css"] = {
"Southern Ohlone",
25559664,
"nai-utn",
"Latn",
}
m["cst"] = {
"Northern Ohlone",
25559666,
"nai-utn",
"Latn",
}
m["csv"] = {
"Sumtu Chin",
7638087,
"tbq-kuk",
}
m["csw"] = {
"Swampy Cree",
56696,
"alg",
"Latn, Cans",
ancestors = "cr",
}
m["csx"] = {
"Cambodian Sign Language",
50934287,
"sgn",
}
m["csy"] = {
"Siyin Chin",
7533375,
"tbq-kuk",
}
m["csz"] = {
"Coos",
3126783,
"nai-coo",
"Latn",
}
m["cta"] = {
"Tataltepec Chatino",
7687853,
"omq-cha",
"Latn",
}
m["ctc"] = {
"Chetco-Tolowa",
12628946,
"ath-pco",
"Latn",
}
m["ctd"] = {
"Tedim Chin",
56357,
"tbq-kuk",
"Latn, Pauc",
}
m["cte"] = {
"Tepinapa Chinantec",
12953443,
"omq-chi",
"Latn",
}
m["ctg"] = {
"Chittagonian",
33173,
"inc-bas",
"Beng",
ancestors = "inc-obn",
}
m["cth"] = {
"Thaiphum Chin",
16912048,
"tbq-kuk",
}
m["ctl"] = {
"Tlacoatzintepec Chinantec",
12643657,
"omq-chi",
"Latn",
}
m["ctm"] = {
"Chitimacha",
1294227,
"qfa-iso", -- recently proposed to be in the Totozoquean family
"Latn",
}
m["ctn"] = {
"Chhintange",
32994,
"sit-kie",
"Deva",
}
m["cto"] = {
"Emberá-Catío",
3052039,
"sai-chc",
"Latn",
}
m["ctp"] = {
"Western Highland Chatino",
32861734,
"omq-cha",
"Latn",
strip_diacritics = {remove_diacritics = "¹²³⁴⁵"},
sort_key = {remove_diacritics = c.acute},
}
m["cts"] = {
"Bikol Kahilagaang Catanduanes", --TLCHANGE
7130477,
"phi",
"Latn",
english_name = "Northern Catanduanes Bikol", --TLCHANGE
}
m["ctt"] = {
"Wayanad Chetti",
7975850,
"dra-mal",
"Taml",
}
m["ctu"] = {
"Chol",
35179,
"myn",
"Latn",
}
m["ctz"] = {
"Zacatepec Chatino",
8063754,
"omq-cha",
"Latn",
}
m["cua"] = {
"Cua",
3441115,
"mkh-ban",
"Latn",
}
m["cub"] = {
"Cubeo",
3006705,
"sai-tuc",
"Latn",
}
m["cuc"] = {
"Usila Chinantec",
7901979,
"omq-chi",
"Latn",
}
m["cug"] = {
"Cung",
35194,
"nic-bbe",
"Latn",
}
m["cuh"] = {
"Chuka",
12952344,
"bnt-kka",
"Latn",
}
m["cui"] = {
"Cuiba",
2980421,
"sai-guh",
"Latn",
}
m["cuj"] = {
"Mashco Piro",
3446596,
"awd",
"Latn",
}
m["cuk"] = {
"Kuna",
12953659,
"cba",
"Latn",
}
m["cul"] = {
"Culina",
2475442,
"auf",
"Latn",
}
m["cuo"] = {
"Cumanagoto",
5193784,
"sai-cpc",
"Latn",
}
m["cup"] = {
"Cupeño",
143130,
"azc-cup",
"Latn",
}
m["cuq"] = {
"Cun",
2475478,
"qfa-lic",
"Latn",
}
m["cur"] = {
"Chhulung",
5116126,
"sit-kie",
"Deva",
}
m["cut"] = {
"Teutila Cuicatec",
12953453,
"omq-cui",
"Latn",
}
m["cuu"] = {
"Tai Ya",
3441122,
"qfa-tak",
"Latn",
}
m["cuv"] = {
"Cuvok",
3515056,
"cdc-cbm",
"Latn",
}
m["cuw"] = {
"Chukwa",
12629033,
"sit-kic",
}
m["cux"] = {
"Tepeuxila Cuicatec",
20527242,
"omq-cui",
"Latn",
}
m["cuy"] = {
"Cuitlatec",
2030998,
"qfa-iso",
"Latn",
}
m["cvg"] = {
"Chug",
47683644,
"sit-khc",
"Tibt, Latn",
-- Tibt translit, display_text, strip_diacritics, sort_key in [[Module:scripts/data]]
-- (NOTE: formerly not present, probably an accidental omission)
}
m["cvn"] = {
"Valle Nacional Chinantec",
12953442,
"omq-chi",
"Latn",
}
m["cwa"] = {
"Kabwa",
6344537,
"bnt-lok",
"Latn",
}
m["cwb"] = {
"Maindo",
11002891,
"bnt-mak",
"Latn",
ancestors = "chw",
}
m["cwd"] = {
"Woods Cree",
56305,
"alg",
"Latn, Cans",
ancestors = "cr",
}
m["cwe"] = {
"Kwere",
779632,
"bnt-ruv",
"Latn",
}
m["cwg"] = {
"Chewong",
646718,
"mkh-asl",
"Latn",
}
m["cwt"] = {
"Kuwaataay",
35699,
"alv-jol",
"Latn",
}
m["cya"] = {
"Nopala Chatino",
15616302,
"omq-cha",
"Latn",
}
m["cyb"] = {
"Cayubaba",
3183382,
"qfa-iso",
"Latn",
}
m["cyo"] = {
"Kuyunon", --"Cuyunon",
33153,
"phi",
"Latn",
is_official_kwf_name = "https://kwfwikaatkultura.ph/kuyunon/", --TLCHANGE
english_name = "Cuyunon" --TLCHANGE
}
m["czh"] = {
"Huizhou",
56546,
"zhx",
"Hants", -- ?
ancestors = "ltc",
generate_forms = "zh-generateforms",
sort_key = "Hani-sortkey",
}
m["czk"] = {
"Knaanic",
56384,
"zlw",
"Hebr",
ancestors = "zlw-ocs",
-- Hebr display_text, strip_diacritics, sort_key in [[Module:scripts/data]]
}
m["czn"] = {
"Zenzontepec Chatino",
603106,
"omq-cha",
"Latn",
}
m["czo"] = {
"Min Sentral", --TLCHANGE
56435,
"zhx-inm",
"Hants",
generate_forms = "zh-generateforms",
sort_key = "Hani-sortkey",
english_name = "Central Min", --TLCHANGE
}
m["czt"] = {
"Zotung Chin",
8074599,
"tbq-kuk",
"Latn",
}
return require("Module:languages").finalizeData(m, "language")
f6k7layov7hers9ran4y5nswqzwrphq
Padron:RQ:ojp:Man'yōshū
10
33064
178017
162423
2026-09-21T16:30:03Z
Yivan000
4078
Inilipat ni Yivan000 ang pahinang [[Padron:RQ:Man'yōshū]] sa [[Padron:RQ:ojp:Man'yōshū]]
162423
wikitext
text/x-wiki
{{#invoke:quote|call_quote_template
|ojp
|year = c. 759
|author =
|title = [[w:Man'yōshū|Man’yōshū]]
|section = {{#if: {{{1|}}}|book {{{1}}}{{#if: {{{2|}}}|, [https://oncoj.orinst.ox.ac.uk/cgi-bin/oncoj.sh?tree=MYS.{{{1}}}.{{{2}}}{{#if: {{{3|}}}|{{{3}}}}} poem {{{2}}}]}} {{#if: {{{4|}}}|{{{4}}}}}{{#if: {{{5|}}}|<nowiki>;</nowiki> {{{5}}}}}}}
|propagateparams = translation,t,transliteration,tr,url,ref
|allowparams=1,2,3,4,5
}}<noinclude>{{documentation}}[[Category:Old Japanese quotation templates|Man'yōshū]][[Category:Japanese quotation templates|Man'yōshū]]</noinclude>
4mrt25zy2h9i3lfh6tvkzmti0v1p3ig
Padron:quote-mailing list/documentation
10
33211
178020
162638
2026-09-21T16:33:06Z
Yivan000
4078
Inilipat ni Yivan000 ang pahinang [[Padron:quote-mailing list/doc]] sa [[Padron:quote-mailing list/documentation]] nang walang iniwang redirect
162638
wikitext
text/x-wiki
{{documentation subpage}}
{{uses lua|Module:quote}}
This template can be used in a dictionary entry to provide a quotation from an {{w|electronic mailing list}}. These are inherently ephemeral, so it's important to link to a durable archive, ideally {{w|Google Groups}} or [[w:MARC (archive)|MARC]].
While both Usenet newsgroups and mailing lists are archived on Google Groups, they're not the same. If the name of the group contains a <kbd>.</kbd>, like <kbd>alt.folklore.urban</kbd>, it's Usenet; please use {{temp|quote-newsgroup}}.
===Sample templates===
;Most basic parameters for English quotations
<syntaxhighlight lang="wikitext">
#* {{quote-mailing list|1=|date=|author=|title=|list=|url=|text=}}
</syntaxhighlight>
;Most basic parameters for non-English quotations
<syntaxhighlight lang="wikitext">
#* {{quote-mailing list|1=|date=|author=|title=|list=|url=|text=|t=}}
</syntaxhighlight>
;Commonly used parameters
<syntaxhighlight lang="wikitext">
#* {{quote-mailing list|1=|author=|authorlink=|email=|title=|list=|url=|date=|accessdate=|text=|t=|tr=}}
</syntaxhighlight>
;All available parameters
<syntaxhighlight lang="wikitext">
#* {{quote-mailing list|1=|indent=|author=|authorlink=|last=|first=|email=|title=|trans-title=|list=|url=|date=|year=|accessdate=|text=|passage=|lang=|brackets=|t=|translation=|lit=|tr=|transliteration=|subst=}}
</syntaxhighlight>
===Examples===
'''Wikitext''':
<syntaxhighlight lang="wikitext">{{quote-mailing list|en|author=John Naylor|title=Re: [Steam-Scholars] Hello again and a query|list=steam-scholars|url=https://groups.google.com/forum/#!msg/steam-scholars/bdMTIoChWyQ/pz5TAUpNxcYJ|date=24 September 2010|passage=It is extremely rare that you speak to someone who says "I want to be an ...." This would suggest that for the vast majority of '''steampunks''' their choice of outfit (at least intitially) is less a conscious attempt at portrayal and more of a spontaneous and potentially subconscious growth of an idea.}}</syntaxhighlight>
'''Output''':
* {{quote-mailing list|en|author=John Naylor|title=Re: [Steam-Scholars] Hello again and a query|list=steam-scholars|url=https://groups.google.com/forum/#!msg/steam-scholars/bdMTIoChWyQ/pz5TAUpNxcYJ|date=24 September 2010|passage=It is extremely rare that you speak to someone who says "I want to be an ...." This would suggest that for the vast majority of '''steampunks''' their choice of outfit (at least intitially) is less a conscious attempt at portrayal and more of a spontaneous and potentially subconscious growth of an idea.}}
===Parameters===
All parameters except {{para|1}} are optional, and may contain inline interwiki or external links as needed.
{| class="wikitable"
!Parameter
!Remarks
|- style="vertical-align:top;"
| style="text-align:center;" | <code>1</code>
| A comma-separated list of language codes indicating the language(s) of the quoted text; for a list of the codes, see [[Wiktionary:List of languages]]. If the language is other than English, the template will indicate this fact by displaying "(in [''language''])" (for one language), or "(in [''language''] and [''language''])" (for two languages), or "(in [''language''], [''language''] ... and [''language''])" (for three or more languages). The entry page will also be added to a category in the form "Category:[''Language''] terms with quotations" for the first listed language (unless <code>termlang</code> is specified, in which case that language is used for the category, or <code>nocat</code> is specified, in which case the page will not be added to any category). The first listed language also determines the font to use and the appropriate transliteration to display, if the text is in a non-Latin script.
Use {{para|worklang}} to specify the language(s) that the overall posting is written in: see below.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>author</code><br />or</br ><code>last</code> and <code>first</code>
| The name of the author of the newsgroup post quoted. Use either <code>author</code>, or <code>last</code> and <code>first</code> (for the first name, and middle names or initials), not both.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>authorlink</code>
| The name of an [https://en.wikipedia.org English Wikipedia] article about the author, which will be linked to the name(s) specified using <code>author</code>, or <code>last</code> and <code>first</code>. Do not add the prefix "<kbd>:en:</kbd>" or "<kbd>w:</kbd>". (Alternatively, link each person's name directly, like this: "<kbd><nowiki>author=[[w:Kathleen Taylor (biologist)|Kathleen Taylor]]</nowiki></kbd>" or "<kbd><nowiki>author={{w|Samuel Johnson}}</nowiki></kbd>".)
|- style="vertical-align:top;"
| style="text-align:center;" | <code>email</code>
| The author's e-mail address.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>title</code>
| The title of the newsgroup post, typically the "<kbd>Subject:</kbd>" header.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>trans-title</code>
| If the title of the newsgroup post is not in English, this parameter can be used to provide an English translation of the title.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>list</code>
| The mailing list the post was sent to. If it was sent to multiple mailing lists, indicate the main one.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>id</code>
| The message ID from the "<kbd>Message-ID:</kbd>" header of the post. Do not include the [[w:bracket#Angle brackets|angle brackets]] as these will be inserted by the template. Note that [[w:MARC (archive)|MARC]] obfuscates these; replace, e.g., <kbd>20181231222013.GH6707 () atomide ! com</kbd> with <kbd>20181231222013.GH6707@atomide.com</kbd>.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>url</code>
| The [[w:Universal Resource Locator|URL]] or web address of the archived message=, for example, on {{w|Google Groups}} or [[w:MARC (archive)|MARC]].
|- style="vertical-align:top;"
| style="text-align:center;" | <code>accessdate</code>
| The date when the URL was accessed.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>date</code><br />or<br /><code>year</code>
| The date or year that the message was posted. Use either <code>date</code>, or <code>year</code>, not both.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>text</code> or <code>passage</code>
| The portion of the message being quoted. Highlight the term defined in bold in the quoted text like this: "<kbd><nowiki>'''cyberspace'''</nowiki></kbd>".
|- style="vertical-align:top;"
| style="text-align:center;" | <code>worklang</code>
| A comma-separated list of language codes indicating the language(s) that the overall posting is written in, if different from the quoted text; for a list of the codes, see [[Wiktionary:List of languages]].
|- style="vertical-align:top;"
| style="text-align:center;" | <code>termlang</code>
| A language code indicating the language of the term being illustrated, if different from the quoted text; for a list of the codes, see [[Wiktionary:List of languages]]. If specified, this language is the one used when adding the page to a category of the form "Category:[''Language''] terms with quotations"; otherwise, the first listed language specified using <code>1</code> is used. Only specify this parameter if the language of the quotation is different from the term's language, e.g. a Middle English quotation used to illustrate a modern English term or an English definition of a Vietnamese term in a Vietnamese-English dictionary.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>nocat</code>
| Use <kbd>nocat=y</kbd> or <kbd>nocat=1</kbd> or <kbd>nocat=on</kbd> to suppress adding the page to a category of the form "Category:[''Language''] terms with quotations". This should not normally be done.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>brackets</code>
| Use "<kbd>brackets=on</kbd>" to surround a quotation with [[bracket]]s. This indicates that the quotation either contains a mere mention of a term (for example, "some people find the word '''''manoeuvre''''' hard to spell") rather than an actual use of it (for example, "we need to '''manoeuvre''' carefully to avoid causing upset"), or does not provide an actual instance of a term but provides information about related terms.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>t</code> or <code>translation</code>
| If the quoted text is not in English, this parameter can be used to provide an English [[translation]] of it.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>lit</code>
| If the quoted text is not in English and the translation supplied using <code>t</code> or <code>translation</code> is idiomatic, this parameter can be used to provide a [[literal]] English [[translation]].
|- style="vertical-align:top;"
| style="text-align:center;" | <code>footer</code>
| This parameter can be used to specify arbitrary text to insert in a separate line at the bottom, to specify a comment, footnote, etc.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>tr</code> or <code>transliteration</code>
| If the quoted text uses a different {{w|writing system}} from the {{w|Latin alphabet}} (the usual alphabet used in English), this parameter can be used to provide a [[transliteration]] of it into the Latin alphabet. Note that many languages provide an automatic transliteration if this argument is not specified.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>subst</code>
| Phonetic substitutions to be applied to handle irregular transliterations in certain languages with a non-Latin writing system and automatic transliteration (e.g. Russian and Yiddish). If specified, should be one or more substitution expressions separated by commas, where each substitution expression is of the form <code>FROM//TO</code> (<code>FROM/TO</code> is also accepted), where <code>FROM</code> specifies the source text in the source script (e.g. Cyrillic or Hebrew) and <code>TO</code> is the corresponding replacement text, also in the source script. The intent is to respell irregularly-pronounced words phonetically prior to transliteration, so that the transliteration reflects the pronunciation rather than the spelling. The substitutions are applied in order. Note that Lua patterns can be used in <code>FROM</code> and <code>TO</code> in lieu of literal text; see [[WT:LUA]]. See also {{temp|ux}} for an example of using <code>subst</code> (the usage is identical to that template).
|- style="vertical-align:top;"
| style="text-align:center;" | <code>indent</code>
| Instead of using wikitext outside the quotation template to indent it (for example, "<kbd><nowiki>#* {{quote-mailing list|...</nowiki></kbd>"), you can use this parameter to specify the indent inside the template (for example, "<kbd><nowiki>{{quote-mailing list|indent=#*|...</nowiki></kbd>")
|}
==See also==
* <code><nowiki>{{</nowiki>[[w:Template:Cite mailing list|cite mailing list]]<nowiki>}}</nowiki></code> – the English Wikipedia template that this template was originally based on
{{citation templates}}
<includeonly>
[[Category:Citation templates]]
</includeonly>
bbdm3lhhm2ofcqy6fu5grko9c6bd7kv
Padron:quote-newsgroup/documentation
10
33217
178019
162645
2026-09-21T16:32:31Z
Yivan000
4078
Inilipat ni Yivan000 ang pahinang [[Padron:quote-newsgroup/doc]] sa [[Padron:quote-newsgroup/documentation]] nang walang iniwang redirect
162645
wikitext
text/x-wiki
{{documentation subpage}}
{{uses lua|Module:quote}}
This template can be used in a dictionary entry to provide a quotation from a {{w|Usenet}} [[w:Usenet newsgroup|newsgroup]].
To create a citation in a "References" section or on a discussion page, use {{temp|cite-newsgroup}}.
===Sample templates===
;Most basic parameters for English quotations
<syntaxhighlight lang="wikitext">
#* {{quote-newsgroup|1=|date=|author=|title=|newsgroup=|url=|text=}}
</syntaxhighlight>
;Most basic parameters for non-English quotations
<syntaxhighlight lang="wikitext">
#* {{quote-newsgroup|1=|date=|author=|title=|newsgroup=|url=|text=|t=}}
</syntaxhighlight>
;Commonly used parameters
<syntaxhighlight lang="wikitext">
#* {{quote-newsgroup|1=|author=|authorlink=|email=|title=|newsgroup=|id=|url=|date=|accessdate=|text=|t=|tr=}}
</syntaxhighlight>
;All available parameters
<syntaxhighlight lang="wikitext">
#* {{quote-newsgroup|1=|indent=|author=|authorlink=|last=|first=|email=|title=|trans-title=|newsgroup=|id=|url=|date=|year=|accessdate=|text=|passage=|lang=|brackets=|t=|translation=|lit=|tr=|transliteration=|subst=}}
</syntaxhighlight>
===Examples===
<syntaxhighlight lang="wikitext">{{quote-newsgroup|en|author=Peter da Silva|title=Re:Microsoft versus Digital Equipment Corporation|newsgroup=alt.folklore.computers|id=g0hq1u$2hkn$3@monolith.in.taronga.com|url=http://groups.google.com/group/alt.folklore.computers/msg/032c30495567b213|date=16 March 2008|text={{...}} otherwise the pager needs to start doing a bunch of unnecessary '''yak shaving'''.}}</syntaxhighlight>
produces this:
:{{quote-newsgroup|en|author=Peter da Silva|title=Re:Microsoft versus Digital Equipment Corporation|newsgroup=alt.folklore.computers|id=g0hq1u$2hkn$3@monolith.in.taronga.com|url=http://groups.google.com/group/alt.folklore.computers/msg/032c30495567b213|date=16 March 2008|text={{...}} otherwise the pager needs to start doing a bunch of unnecessary '''yak shaving'''.}}
===Parameters===
All parameters are optional, and may contain inline interwiki or external links as needed.
{| class="wikitable"
!Parameter
!Remarks
|- style="vertical-align:top;"
| style="text-align:center;" | <code>1</code>
| A comma-separated list of language codes indicating the language(s) of the quoted text; for a list of the codes, see [[Wiktionary:List of languages]]. If the language is other than English, the template will indicate this fact by displaying "(in [''language''])" (for one language), or "(in [''language''] and [''language''])" (for two languages), or "(in [''language''], [''language''] ... and [''language''])" (for three or more languages). The entry page will also be added to a category in the form "Category:[''Language''] terms with quotations" for the first listed language (unless <code>termlang</code> is specified, in which case that language is used for the category, or <code>nocat</code> is specified, in which case the page will not be added to any category). The first listed language also determines the font to use and the appropriate transliteration to display, if the text is in a non-Latin script.
Use {{para|worklang}} to specify the language(s) that the overall posting is written in: see below.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>author</code><br />or</br ><code>last</code> and <code>first</code>
| The name of the author of the newsgroup post quoted. Use either <code>author</code>, or <code>last</code> and <code>first</code> (for the first name, and middle names or initials), not both.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>authorlink</code>
| The name of an [https://en.wikipedia.org English Wikipedia] article about the author, which will be linked to the name(s) specified using <code>author</code>, or <code>last</code> and <code>first</code>. Do not add the prefix "<kbd>:en:</kbd>" or "<kbd>w:</kbd>". (Alternatively, link each person's name directly, like this: "<kbd><nowiki>author=[[w:Kathleen Taylor (biologist)|Kathleen Taylor]]</nowiki></kbd>" or "<kbd><nowiki>author={{w|Samuel Johnson}}</nowiki></kbd>".)
|- style="vertical-align:top;"
| style="text-align:center;" | <code>email</code>
| The author's e-mail address.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>title</code>
| The title of the newsgroup post, typically the "<kbd>Subject:</kbd>" header.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>trans-title</code>
| If the title of the newsgroup post is not in English, this parameter can be used to provide an English translation of the title.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>newsgroup</code>
| The newsgroup the post was posted to. If it was posted to multiple newsgroups, indicate the main one.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>id</code>
| The message ID from the "<kbd>Message-ID:</kbd>" header of the post. Do not include the [[w:bracket#Angle brackets|angle brackets]] as these will be inserted by the template.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>url</code>
| The [[w:Universal Resource Locator|URL]] or web address of the newsgroup post, for example, on {{w|Google Groups}}.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>accessdate</code>
| The date when the URL was accessed.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>date</code><br />or<br /><code>year</code>
| The date or year that the newsgroup post was posted. Use either <code>date</code>, or <code>year</code>, not both.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>text</code> or <code>passage</code>
| The portion of the newsgroup post being quoted. Highlight the term defined in bold in the quoted text like this: "<kbd><nowiki>'''cyberspace'''</nowiki></kbd>".
|- style="vertical-align:top;"
| style="text-align:center;" | <code>worklang</code>
| A comma-separated list of language codes indicating the language(s) that the overall posting is written in, if different from the quoted text; for a list of the codes, see [[Wiktionary:List of languages]].
|- style="vertical-align:top;"
| style="text-align:center;" | <code>termlang</code>
| A language code indicating the language of the term being illustrated, if different from the quoted text; for a list of the codes, see [[Wiktionary:List of languages]]. If specified, this language is the one used when adding the page to a category of the form "Category:[''Language''] terms with quotations"; otherwise, the first listed language specified using <code>1</code> is used. Only specify this parameter if the language of the quotation is different from the term's language, e.g. a Middle English quotation used to illustrate a modern English term or an English definition of a Vietnamese term in a Vietnamese-English dictionary.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>nocat</code>
| Use <kbd>nocat=y</kbd> or <kbd>nocat=1</kbd> or <kbd>nocat=on</kbd> to suppress adding the page to a category of the form "Category:[''Language''] terms with quotations". This should not normally be done.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>brackets</code>
| Use "<kbd>brackets=on</kbd>" to surround a quotation with [[bracket]]s. This indicates that the quotation either contains a mere mention of a term (for example, "some people find the word '''''manoeuvre''''' hard to spell") rather than an actual use of it (for example, "we need to '''manoeuvre''' carefully to avoid causing upset"), or does not provide an actual instance of a term but provides information about related terms.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>t</code> or <code>translation</code>
| If the quoted text is not in English, this parameter can be used to provide an English [[translation]] of it.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>lit</code>
| If the quoted text is not in English and the translation supplied using <code>t</code> or <code>translation</code> is idiomatic, this parameter can be used to provide a [[literal]] English [[translation]].
|- style="vertical-align:top;"
| style="text-align:center;" | <code>footer</code>
| This parameter can be used to specify arbitrary text to insert in a separate line at the bottom, to specify a comment, footnote, etc.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>tr</code> or <code>transliteration</code>
| If the quoted text uses a different {{w|writing system}} from the {{w|Latin alphabet}} (the usual alphabet used in English), this parameter can be used to provide a [[transliteration]] of it into the Latin alphabet. Note that many languages provide an automatic transliteration if this argument is not specified.
|- style="vertical-align:top;"
| style="text-align:center;" | <code>subst</code>
| Phonetic substitutions to be applied to handle irregular transliterations in certain languages with a non-Latin writing system and automatic transliteration (e.g. Russian and Yiddish). If specified, should be one or more substitution expressions separated by commas, where each substitution expression is of the form <code>FROM//TO</code> (<code>FROM/TO</code> is also accepted), where <code>FROM</code> specifies the source text in the source script (e.g. Cyrillic or Hebrew) and <code>TO</code> is the corresponding replacement text, also in the source script. The intent is to respell irregularly-pronounced words phonetically prior to transliteration, so that the transliteration reflects the pronunciation rather than the spelling. The substitutions are applied in order. Note that Lua patterns can be used in <code>FROM</code> and <code>TO</code> in lieu of literal text; see [[WT:LUA]]. See also {{temp|ux}} for an example of using <code>subst</code> (the usage is identical to that template).
|- style="vertical-align:top;"
| style="text-align:center;" | <code>indent</code>
| Instead of using wikitext outside the quotation template to indent it (for example, "<kbd><nowiki>#* {{quote-newsgroup|...</nowiki></kbd>"), you can use this parameter to specify the indent inside the template (for example, "<kbd><nowiki>{{quote-newsgroup|indent=#*|...</nowiki></kbd>")
|}
==TemplateData==
{{TemplateData header}}
<templatedata>
{
"description": "This template can be used in a dictionary entry to provide a quotation from a Usenet newsgroup.",
"params": {
"1": {
"label": "Language",
"description": "A comma-separated list of language codes indicating the language(s) of the quoted text.",
"example": "en",
"type": "string",
"required": true,
"suggested": true
},
"url": {
"label": "Page URL",
"description": "The URL of the newsgroup post, for example, on Google Groups.",
"type": "url",
"required": false,
"example": "http://groups.google.com/group/alt.folklore.computers/msg/032c30495567b213"
},
"title": {
"label": "Post title",
"description": "The title of the newsgroup post, typically the \"Subject\" header.",
"type": "string",
"aliases": [],
"example": "Re:Microsoft versus Digital Equipment",
"required": false,
"suggested": true
},
"date": {
"label": "Publication date",
"description": "The date or year that the newsgroup post was posted.",
"type": "string",
"example": "16 March 2008",
"required": false,
"suggested": true
},
"newsgroup": {
"label": "Newsgroup",
"description": "The newsgroup the post was posted to. If it was posted to multiple newsgroups, indicate the main one.",
"type": "string",
"example": "alt.folklore.computers",
"required": true
},
"id": {
"label": "Post message ID",
"description": "The message ID from the \"Message-ID:\" header of the post. Do not include angle brackets.",
"type": "string",
"example": "g0hq1u$2hkn$3@monolith.in.taronga.com",
"required": false
},
"accessdate": {
"label": "Access date",
"description": "The date when the URL was accessed.",
"type": "string",
"required": false
},
"author": {
"label": "Post author",
"description": "The name of the author of the newsgroup post quoted.",
"type": "string",
"example": "Peter da Silva",
"required": false
},
"email": {
"label": "Author's email",
"description": "The author's e-mail address.",
"type": "string",
"example": "peterdasilva@example.com",
"required": false
},
"passage": {
"label": "Quoted text",
"description": "The portion of the newsgroup post being quoted. Highlight the term defined in bold.",
"aliases": ["text"],
"type": "content",
"example": "{{...}} otherwise the pager needs to start doing a bunch of unnecessary '''yak shaving'''.",
"required": true
},
"translation": {
"label": "Translation",
"description": "If the quoted text is not in English, this parameter can be used to provide an English translation of it.",
"aliases": ["t"],
"type": "string",
"required": false
}
},
"maps": {
"citoid": {
}
},
"paramOrder": [
"1",
"author",
"email",
"title",
"id",
"newsgroup",
"date",
"url",
"accessdate",
"passage",
"translation"
],
"format": "inline"
}
</templatedata>
==See also==
* {{temp|cite-newsgroup}} – for citations in "References" sections and discussion pages
* <code><nowiki>{{</nowiki>[[w:Template:Cite newsgroup|cite newsgroup]]<nowiki>}}</nowiki></code> – the English Wikipedia template that this template was originally based on
{{citation templates}}
<includeonly>
[[Category:Citation templates]]
</includeonly>
j8b0n4o3m05nhe1yoq18l7yrp5emcxe
Module:headword utilities
828
33386
178034
172555
2026-09-22T04:57:16Z
Yivan000
4078
merge changes
178034
Scribunto
text/plain
local export = {}
local require_when_needed = require("Module:utilities/require when needed")
local affix_module = "Module:affix"
local debug_track_module = "Module:debug/track"
local decorations_module = "Module:decorations"
local en_utilities_module = "Module:en-utilities"
local fun_is_callable_module = "Module:fun/isCallable"
local headword_module = "Module:headword"
local headword_data_module = "Module:headword/data"
local languages_module = "Module:languages"
local links_module = "Module:links"
local parameters_module = "Module:parameters"
local parse_interface_module = "Module:parse interface"
local parse_utilities_module = "Module:parse utilities"
local string_pattern_escape_module = "Module:string/patternEscape"
local string_replacement_escape_module = "Module:string/replacementEscape"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local yesno_module = "Module:yesno"
local dump = mw.dumpObject
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
local insert = table.insert
local concat = table.concat
local remove = table.remove
local sort = table.sort
local deep_equals = require_when_needed(table_module, "deepEquals")
local extend = require_when_needed(table_module, "extend")
local insert_if_not = require_when_needed(table_module, "insertIfNot")
local list_to_set = require_when_needed(table_module, "listToSet")
local serial_comma_join = require_when_needed(table_module, "serialCommaJoin")
local shallow_copy = require_when_needed(table_module, "shallowCopy")
local split = require_when_needed(string_utilities_module, "split")
local ugsub = require_when_needed(string_utilities_module, "gsub")
local umatch = require_when_needed(string_utilities_module, "match")
local pattern_escape = require_when_needed(string_pattern_escape_module)
local replacement_escape = require_when_needed(string_replacement_escape_module)
local escape_wikicode = require_when_needed(parse_utilities_module, "escape_wikicode")
local parse_inline_modifiers = require_when_needed(parse_utilities_module, "parse_inline_modifiers")
local term_contains_top_level_html = require_when_needed(parse_utilities_module, "term_contains_top_level_html")
local get_lang_by_code = require_when_needed(languages_module, "getByCode")
local is_callable = require_when_needed(fun_is_callable_module)
local format_decorations = require_when_needed(decorations_module, "format_decorations")
local function split_on_comma(val)
if val:find(",") then
return require(parse_interface_module).split_on_comma(val)
else
return {val}
end
end
local function ine(val)
if val == "" then return nil else return val end
end
--[=[
Add decorations to a term. `termobj` is the object describing the term, which should optionally contain:
* left qualifiers in `q`, an array of strings;
* right qualifiers in `qq`, an array of strings;
* left labels in `l`, an array of strings;
* right labels in `ll`, an array of strings;
* references in `refs`, an array either of strings (formatted reference text) or objects containing fields `text`
(formatted reference text) and optionally `name` and/or `group`;
`text` is the text of the term itself, and `lang` is the language object.
]=]
local function add_decorations(text, termobj, lang)
local function field_non_empty(field)
local list = termobj[field]
if not list then
return nil
end
if type(list) ~= "table" then
error(("Internal error: Wrong type for `termobj.%s`=%s, should be \"table\""):format(
field, mw.dumpObject(list)))
end
return list[1]
end
if field_non_empty("q") or field_non_empty("qq") or field_non_empty("l") or field_non_empty("ll") or
field_non_empty("refs") then
text = format_decorations {
lang = lang,
text = text,
q = termobj.q,
qq = termobj.qq,
l = termobj.l,
ll = termobj.ll,
refs = termobj.refs,
}
end
return text
end
local param_mods = {
id = {}, -- disabled when `is_head = true`
q = {type = "qualifier"},
qq = {type = "qualifier"},
l = {type = "labels"},
ll = {type = "labels"},
-- [[Module:headword]] expects part references in `.refs`.
ref = {item_dest = "refs", type = "references", store = "insert-flattened"},
}
local optional_param_mods = {
g = {item_dest = "genders", type = "genders"},
alt = {},
lang = {type = "language"},
sc = {type = "script"},
t = {item_dest = "gloss"},
gloss = {},
pos = {},
lit = {},
tr = {},
ts = {},
face = {},
nolinkinfl = {type = "boolean"},
}
local optional_headword_param_mods = {
sc = {type = "script"},
tr = {},
ts = {},
}
--[==[
Parse a single inflection or headword form or list of such forms. In either case, inline modifiers may be attached.
`data` is an object with the following fields:
* `val`: The raw value to parse. Required.
* `paramname`: The name of the parameter from which the value was taken; used in error messages. Required.
* `is_head`: We are parsing a headword parameter (a value which goes into the `heads` field of `data`). This changes
the allowed modifiers, disabling the `id` modifier and only allowing a subset of optional modifiers.
* `frob`: An optional function of one value to apply to the form after inline modifiers have been removed (i.e. to
apply to the `.term` field of the returned object).
* `include_mods`: List of extra inline modifiers to include, besides the default ones (see below). Each list item is
either a string specifying a recognized extra inline modifier (see `optional_param_mods` in the code), or a two-item
list of modifier name and modifier spec, where the spec should follow the syntax for modifier specs in
`parse_inline_modifiers` in [[Module:parse utilities]].
* `exclude_mods`: List of default inline modifiers to not include.
* `splitchar`: If specified, the value in `val` can be a list of forms to parse, separated by the value of `splitchar`
(which is a Lua pattern, as in `parse_inline_modifiers` in [[Module:parse utilities]]). Most commonly, `splitchar` is
a single comma and the values are comma-separated (in this case, splitting will not happen if a space follows the
comma).
* `parse_lang_prefix`: If specified, allow a language prefix to precede a form, and if found, store into the `.lang`
field of the returned object.
* `preserve_splitchar`, `delimiter_key`, `escape_fun`, `unescape_fun`, `pre_normalize_modifiers`: As in
`parse_inline_modifiers` in [[Module:parse utilities]].
Returns an object suitable for storing as one element of one of the lists in `headdata.inflections`, where `headdata`
is the structure passed to [[Module:headword]]. If `splitchar` is specified, howeve, the return value is a list of such
objects.
The following default inline modifiers are currently recognized:
* `q`: Left qualifier.
* `qq`: Right qualifier.
* `l`: Comma-separated list of left labels. No space should follow the comma.
* `ll`: Comma-separated list of right labels. No space should follow the comma.
* `ref`: Reference or references. See {{tl|IPA}} for the syntax.
* `id`: Sense ID, in case there are multiple senses. See {{tl|l}}.
The following are the recognized additional inline modifiers:
* `g`: Comma-separated list of genders.
* `alt`: Display text.
* `lang`: Language code of language of the form, if different from the language of the headword.
* `sc`: Script code of script of the form. Almost never needed.
* `t`: Gloss for the form.
* `gloss`: Gloss for the form (alias for `t`).
* `pos`: Part of speech of the form.
* `lit`: Literal meaning of the form.
* `tr`: Manual transliteration of the form.
* `ts`: Transcription of the form, for languages where the transliteration differs markedly from the pronunciation.
* `face`: Face to display the form in, e.g. {"hypothetical"} for a hypothetical form (unlinkable and displayed in italics).
* `nolinkinfl`: Make the form unlinkable.
]==]
function export.parse_term_with_modifiers(data)
local paramname, val, frob = data.paramname, data.val, data.frob
local function generate_obj(term, parse_err)
if frob then
term = frob(term, parse_err)
end
if data.parse_lang_prefix and term:find(":") then
return require(parse_utilities_module).generate_obj_maybe_parsing_lang_prefix {
term = term,
paramname = paramname,
parse_lang_prefix = true,
parse_err = parse_err,
}
else
return {term = term}
end
end
-- Check for inline modifier, e.g. מרים<tr:Miryem>. But exclude top-level HTML entry with <span ...>,
-- <sup> or similar in it.
if (val:find("<", nil, true) or data.splitchar) and not term_contains_top_level_html(val) and
-- don't parse inline modifiers if is_head and the value begins with a ~ (link modifier syntax)
(not data.is_head or not val:find("^~")) then
local param_mods = param_mods
if data.is_head then
param_mods = shallow_copy(param_mods)
param_mods.id = nil
end
if data.include_mods or data.exclude_mods then
if not data.is_head then
-- already copied when data.is_head
param_mods = shallow_copy(param_mods)
end
if data.include_mods then
local optional_mods = data.is_head and optional_headword_param_mods or optional_param_mods
for _, mod in ipairs(data.include_mods) do
if type(mod) == "table" then
if #mod ~= 2 then
error(("Internal error: Modifier spec %s in `include_mods` should be of length 2"):format(
dump(mod)))
end
local modkey, modvalue = unpack(mod)
param_mods[modkey] = modvalue
elseif not optional_mods[mod] then
error(("Internal error: Unrecognized modifier spec %s in `include_mods`"):format(
dump(mod)))
else
param_mods[mod] = optional_mods[mod]
end
end
end
if data.exclude_mods then
for _, mod in ipairs(data.exclude_mods) do
if not param_mods[mod] then
error(("Internal error: Modifier spec %s in `exclude_mods` not found among existing modifiers"
):format(dump(mod)))
else
param_mods[mod] = nil
end
end
end
end
return parse_inline_modifiers(val, {
paramname = paramname,
param_mods = param_mods,
generate_obj = generate_obj,
splitchar = data.splitchar,
preserve_splitchar = data.preserve_splitchar,
delimiter_key = data.delimiter_key,
escape_fun = data.escape_fun,
unescape_fun = data.unescape_fun,
pre_normalize_modifiers = data.pre_normalize_modifiers,
})
else
local retval = generate_obj(val)
if data.splitchar then
retval = {retval}
end
return retval
end
end
--[==[
Parse a list of inflection forms that may have inline modifiers attached. `data` is an object with the following fields:
* `forms`: The list of raw values to parse. Required.
* `paramname`: The name of the first parameter from which the value was taken; used in error messages. If this is a
two-element list, the first element is the first parameter and the second element is the prefix of the remaining
parameters. Parameter names that are numbers are handled correctly, as are those with \1 in it marking where the
parameter index goes. Required.
* `qualifiers`: If specified, a possibly gappy list of left qualifiers to add to the parsed terms (for compatibility
purposes).
* `splitchar`: As in `parse_term_with_modifiers()`. The resulting per-term lists will be flattened.
* `frob`, `include_mods`, `exclude_mods`, `is_head`, `preserve_splitchar`, `parse_lang_prefix`, `delimiter_key`,
`escape_fun`, `unescape_fun`, `pre_normalize_modifiers`: As in `parse_term_with_modifiers()`.
Returns a list of objects, suitable for storing as one of the lists in `headdata.inflections` (once a label is added),
where `headdata` is the structure passed to [[Module:headword]].
]==]
function export.parse_term_list_with_modifiers(data)
local paramname, forms = data.paramname, data.forms
local qualifiers = data.qualifiers
local first, restpref
if type(paramname) == "table" then
first = paramname[1]
restpref = paramname[2]
else
first = paramname
restpref = paramname
end
local terms = {}
data = shallow_copy(data)
for i, val in ipairs(forms) do
data.paramname = i == 1 and first or type(restpref) == "number" and restpref + i - 1 or
restpref:find("\1", nil, true) and restpref:gsub("\1", tostring(i)) or restpref .. i
data.val = val
local parsed = export.parse_term_with_modifiers(data)
if qualifiers and qualifiers[i] then
if data.splitchar then
for _, term in ipairs(parsed) do
term.q = {qualifiers[i]}
end
else
parsed.q = {qualifiers[i]}
end
end
if data.splitchar then
extend(terms, parsed)
else
terms[i] = parsed
end
end
return terms
end
--[==[
Construct a link to [[Appendix:Glossary]] for `entry`. If `text` is specified, it is the display text; otherwise,
`entry` is used.
]==]
function export.glossary_link(entry, text)
text = text or entry
return "[[Apendise:Glosaryo#" .. entry .. "|" .. text .. "]]" --TLCHANGE Appendix:Glossary
end
function export.replace_glossary_links_in_label(label)
if label:find("<<", nil, true) then
label = label:gsub("<<(.-)|(.-)>>", export.glossary_link):gsub("<<(.-)>>", export.glossary_link)
end
return label
end
--[==[
Insert a fixed inflection (a label not associated with any inflection values) into an `inflections` field. The
`inflections` field will be initialized if needed. `data` is an object with the following fields:
* `headdata`: The headword structure passed to [[Module:headword]]. Required.
* `inflobj`: The object whose `inflections` field the terms are inserted into. Defaults to `headdata`. Only needs
to be set for nested inflections, which are specified for an inflection object rather than the headword data
structure as a whole.
* `label`: The label that the inflections are given; any parts of the label surrounded in `<<...>>` are linked to the
glossary. (If the contents of `<<...>>` contain a `|` in them, they are a two-part link.) Required.
* `originating_term`: The term object from which this label is derived. If specified, decorations will be taken from
this object.
]==]
function export.insert_fixed_inflection(data)
local headdata, origterm, label = data.headdata, data.originating_term, data.label
local inflobj = data.inflobj or headdata
inflobj.inflections = inflobj.inflections or {}
if not origterm then
insert(inflobj.inflections, {
label = export.replace_glossary_links_in_label(label)
})
else
if origterm.id then
error(("It doesn't make sense to pass in an ID '%s' for label '%s' in conjunction with a term value '%s'"
):format(origterm.id, label, origterm.term))
end
origterm = shallow_copy(origterm)
-- Preserve decorations
origterm.term = nil
origterm.label = export.replace_glossary_links_in_label(label)
insert(inflobj.inflections, origterm)
end
end
--[==[
Insert previously-parsed terms into an `inflections` field. The `inflections` field will be initialized if needed.
`data` is an object with the following fields:
* `headdata`: The headword structure passed to [[Module:headword]]. Required.
* `inflobj`: The object whose `inflections` field the terms are inserted into. Defaults to `headdata`. Only needs
to be set for nested inflections, which are specified for an inflection object rather than the headword data
structure as a whole.
* `terms`: The list of parsed terms. If {nil} or omitted, nothing happens unless `request` is set.
* `label`: The label that the inflections are given; any parts of the label surrounded in `<<...>>` are linked to the
glossary. (If the contents of `<<...>>` contain a `|` in them, they are a two-part link.) Required.
* `no_label`: If the term is {"-"} and there are no other terms, insert a fixed label with this value. Defaults to
{"no "} plus the label.
* `usually_no_label`: If the term is {"-"} and there are other terms, insert a fixed label with this value. Defaults to
{"usually no "} plus the label.
* `cats`: List of categories to insert when terms are given that are not {"-"}. Each category is a string naming a full
category to insert (including the appropriate language name prefixed).
* `no_cats`: List of categories to insert when a term is given as {"-"}.
* `usually_no_cats`: List of categories to insert when a term is given as {"-"} and additional terms are specified as
well (representing, e.g. for the inflection {"plural"}, a term which usually has no plural but does under some
circumstances). If omitted, both the categories in `cats` and `no_cats` are inserted.
* `accel`: If specified, a full accelerator object to add to the inflections.
* `request`: If specified and no terms are given, insert a label with a request for inflections to be given.
* `enable_auto_translit`: If specified and terms are given, display automatic transliteration of the terms.
The return value indicates whether the inflection exists and how many terms are in it. It is an object with the
following fields:
* `exists`: {"yes"} if one or more terms were specified; {"no"} if the value was given as {"-"}; {"usually no"} if
the first value was given as {"-"} but additional terms were supplied; otherwise {nil}, indicating that the status
is unspecified.
* `numterms`: Number of terms in the inflection. Will be 0 unless `exists` has the value {"yes"} or {"usually no"}.
* `request`: True if no terms were specified but a term request was inserted into the inflection (because
`data.request` was specified). Otherwise {nil}.
]==]
function export.insert_inflection(data)
local headdata, terms, label = data.headdata, data.terms, data.label
local inflobj = data.inflobj or headdata
local retval = {}
local accel = data.accel
if data.accel_form then
if accel then
error("Internal error: can't specify both data.accel and data.accel_form")
end
if headdata.heads then
local lemmas = {}
local lemma_translits = {}
for i, headobj in ipairs(headdata.heads) do
lemmas[i] = headobj.term
if lemmas[i] == "+" then
error("Internal error: If you use data.accel_form, you should have resolved all occurrences of + in heads appropriately")
end
lemma_translits[i] = headobj.tr
end
accel = {
lemma = lemmas,
lemma_translit = lemma_translits,
form = data.accel_form,
}
else
accel = {
form = data.accel_form,
}
end
end
local function insert_cats(cats)
for _, cat in ipairs(cats) do
insert(headdata.categories, cat)
end
end
if terms and terms[1] then
terms = shallow_copy(terms)
if terms[1].term == "-" then
if terms[2] then
export.insert_fixed_inflection {
headdata = headdata,
inflobj = inflobj,
originating_term = terms[1],
label = data.usually_no_label or "usually no " .. label,
}
remove(terms, 1)
retval.numterms = #terms
retval.exists = "usually no"
if data.usually_no_cats then
insert_cats(data.usually_no_cats)
else
if data.no_cats then
insert_cats(data.no_cats)
end
if data.cats then
insert_cats(data.cats)
end
end
else
export.insert_fixed_inflection {
headdata = headdata,
inflobj = inflobj,
originating_term = terms[1],
label = data.no_label or "no " .. label,
}
retval.numterms = 0
retval.exists = "no"
if data.no_cats then
insert_cats(data.no_cats)
end
return retval
end
else
retval.numterms = #terms
retval.exists = "yes"
if data.cats then
insert_cats(data.cats)
end
end
if data.check_missing then
error("Internal error: check_missing support removed; use checkredlinks=true in [[Module:headword]]")
end
terms.label = export.replace_glossary_links_in_label(label)
if accel then
terms.accel = accel
end
terms.enable_auto_translit = data.enable_auto_translit
inflobj.inflections = inflobj.inflections or {}
insert(inflobj.inflections, terms)
elseif data.request then
inflobj.inflections = inflobj.inflections or {}
insert(inflobj.inflections, {
label = export.replace_glossary_links_in_label(label),
request = true,
})
retval.numterms = 0
-- retval.exists = nil
retval.request = true
else
retval.numterms = 0
-- retval.exists = nil
end
return retval
end
--[==[
Parse raw arguments from `forms` for inline modifiers, and insert the resulting terms (which should not require
significant additional processing) into `headdata.inflections`. `data` is an object with the following fields:
* `forms`: The list of raw values to parse. If {nil} or omitted, nothing happens.
* `headdata`: The headword structure passed to [[Module:headword]]. Required.
* `paramname`: As in `parse_term_list_with_modifiers()`. Required.
* `label`: As in `insert_inflection()`. Required.
* `qualifiers`, `frob`, `include_mods`, `exclude_mods`, `is_head`, `splitchar`, `preserve_splitchar`, `delimiter_key`,
`escape_fun`, `unescape_fun`, `pre_normalize_modifiers`: As in `parse_term_list_with_modifiers()`.
* `accel`: As in `insert_inflection()`.
Return value is as in `insert_inflection()`.
]==]
function export.parse_and_insert_inflection(data)
local forms = data.forms
if forms and forms[1] then
data = shallow_copy(data)
data.forms = forms
data.terms = export.parse_term_list_with_modifiers(data)
return export.insert_inflection(data)
end
return {
numterms = 0
}
end
--[==[
Canonicalize a single term or term-like object or a list of either into a list of term-like objects. `abterms` is the
term or list to canonicalize, and `field` is the name of the field holding the term (defaulting to {"term"}). This
does the minimal work necessary, meaning that the return value may partly or completely share memory with the value
passed in. As a special case, if `abterms` is {nil}, {nil} is returned. If `origin_val` is specified, add a field
`origin` containing the value of `origin_val` to each resulting term-like object (in this case, the object will be
copied a necessary to avoid side-effecting the passed-in objects).
]==]
function export.canonicalize_termobj_list(abterms, field, origin_val)
if abterms == nil then
return nil
end
field = field or "term"
if type(abterms) == "string" then
return {{[field] = abterms, origin = origin_val}}
elseif not abterms[1] then
if origin_val ~= nil then
abterms = shallow_copy(abterms)
abterms.origin = origin_val
end
return {abterms}
else
-- Check if already in full list term and return directly if so (unless `origin_val` is given, in which case we
-- need to shallow-copy both the list and each term in it).
local must_convert = false
for _, term in ipairs(abterms) do
if type(term) == "string" then
must_convert = true
break
end
end
if not must_convert then
if origin_val ~= nil then
abterms = shallow_copy(abterms)
for i, abterm in ipairs(abterms) do
abterms[i] = shallow_copy(abterm)
abterms[i].origin = origin_val
end
end
return abterms
end
end
local retval = {}
for _, term in ipairs(abterms) do
if type(term) == "string" then
insert(retval, {[field] = term, origin = origin_val})
else
if origin_val ~= nil then
term = shallow_copy(term)
term.origin = origin_val
end
insert(retval, term)
end
end
return retval
end
--[==[
Combine two sets of decorations. If either is {nil}, just return the other, and if both are {nil}, return {nil}.
]==]
function export.combine_decorations(decs1, decs2)
if not decs1 and not decs2 then
return nil
end
if not decs1 then
return decs2
end
if not decs2 then
return decs1
end
local combined = shallow_copy(decs1)
for _, dec in ipairs(decs2) do
insert_if_not(combined, dec)
end
return combined
end
function export.combine_qualifiers_or_labels(...)
-- FIXME: Added 2026-09-17. Remove after a month.
error("Use combine_decorations instead")
end
--[==[
Combine the decorations (qualifiers, labels, references) and ID's of two term objects. `destobj` is the "destination
term object" into which the combined properties are written, and `srcobj` is the "source object" into which the
properties are merged. `destobj` is side-effected (but the lists inside of `destobj` are not); if this is undesirable,
make sure to shallow-copy `destobj` first. If both objects have values for a given decoration, the values of `destobj`
come first. If both objects have a value for `id`, the values must match or an error is thrown; otherwise, the resulting
value of `id` comes from whichever one is defined.
'''NOTE:''' This may not be the correct behavior when deduplicating a list of term objects. See
`insert_termobj_combining_duplicates` for a different approach.
]==]
function export.combine_termobj_decorations(destobj, srcobj)
destobj.q = export.combine_decorations(destobj.q, srcobj.q)
destobj.qq = export.combine_decorations(destobj.qq, srcobj.qq)
destobj.l = export.combine_decorations(destobj.l, srcobj.l)
destobj.ll = export.combine_decorations(destobj.ll, srcobj.ll)
destobj.refs = export.combine_decorations(destobj.refs, srcobj.refs)
if destobj.id and srcobj.id and destobj.id ~= srcobj.id then
-- FIXME: We probably want to pass in an error function
error(("Can't specify two different ID's %s and %s when combining objects"):format(srcobj.id, destobj.id))
end
destobj.id = destobj.id or srcobj.id
return destobj
end
function export.combine_termobj_qualifiers_labels(...)
-- FIXME: Added 2026-09-17. Remove after a month.
error("Use combine_termobj_decorations instead")
end
function export.termobj_has_decorations(obj)
return obj.q and obj.q[1] or obj.qq and obj.qq[1] or obj.l and obj.l[1] or obj.ll and obj.ll[1] or
obj.refs and obj.refs[1]
end
function export.termobj_has_qualifiers_or_labels(...)
-- FIXME: Added 2026-09-17. Remove after a month.
error("Use termobj_has_decorations instead")
end
local function one_decoration_equal(prop1, prop2)
local prop1_is_nil = not prop1 or not prop1[1]
local prop2_is_nil = not prop2 or not prop2[1]
if prop1_is_nil and prop2_is_nil then
return true
end
if prop1_is_nil or prop2_is_nil then
return false
end
return deep_equals(prop1, prop2)
end
function export.termobj_decorations_equal(obj1, obj2)
return one_decoration_equal(obj1.q, obj2.q) and
one_decoration_equal(obj1.qq, obj2.qq) and
one_decoration_equal(obj1.l, obj2.l) and
one_decoration_equal(obj1.ll, obj2.ll) and
one_decoration_equal(obj1.refs, obj2.refs) and
obj1.id == obj2.id
end
function export.termobj_ancillary_properties_equal(...)
-- FIXME: Added 2026-09-17. Remove after a month.
error("Use termobj_decorations_equal instead")
end
function export.convert_termobj_to_formobj(termobj)
local formobj = {
form = termobj.term,
translit = termobj.tr,
}
local footnotes
local function mods_to_footnote(mod_prefix, mod_vals)
if mod_vals and mod_vals[1] then
footnotes = footnotes or {}
for _, val in ipairs(mod_vals) do
insert(footnotes, "[" .. mod_prefix .. ":" .. val .. "]")
end
end
end
mods_to_footnote("q", termobj.q)
mods_to_footnote("qq", termobj.qq)
mods_to_footnote("l", termobj.l)
mods_to_footnote("ll", termobj.ll)
mods_to_footnote("ref", termobj.refs)
mods_to_footnote("id", termobj.id and {termobj.id} or nil)
formobj.footnotes = footnotes
return formobj
end
local recognized_multi_mods = {
q = "q",
qq = "qq",
l = "l",
ll = "ll",
ref = "refs",
}
local recognized_single_mods = {
id = "id",
}
function export.add_footnote_to_termobj(termobj, footnote)
local stripped_footnote = footnote:match("^%[(.*)%]$")
if not stripped_footnote then
error("Internal error: Footnote should be surrounded by brackets at this stage: " .. footnote)
end
local prefix, rest = stripped_footnote:match("^([a-z]+):(.+)$")
local field, is_multi
if prefix then
if recognized_multi_mods[prefix] then
field = recognized_multi_mods[prefix]
is_multi = true
elseif recognized_single_mods[prefix] then
field = recognized_single_mods[prefix]
is_multi = false
end
end
if not field then
rest = stripped_footnote
field = "l"
is_multi = true
end
if is_multi then
if not termobj[field] then
termobj[field] = {}
end
insert(termobj[field], rest)
else
if termobj[field] and termobj[field] ~= rest then
error(("Can't set two values for '%s': '%s' and '%s'"):format(field, termobj[field], rest))
end
termobj[field] = rest
end
end
function export.convert_formobj_to_termobj(formobj)
local termobj = {
term = formobj.form,
tr = formobj.translit,
}
if formobj.footnotes then
for _, footnote in ipairs(formobj.footnotes) do
export.add_footnote_to_termobj(termobj, footnote)
end
end
return termobj
end
local function extract_termobj_field_modifiers(fieldval)
return fieldval:match("^([*+]?)(.*)$")
end
function export.remove_termobj_field_modifiers(termobj)
local function remove_field_modifiers(field)
if termobj[field] and termobj[field][1] then
local any_field_modifiers = false
for _, val in ipairs(termobj[field]) do
local field_mods, _ = extract_termobj_field_modifiers(val)
if field_mods ~= "" then
any_field_modifiers = true
break
end
end
local new_field = {}
if any_field_modifiers then
for _, val in ipairs(termobj[field]) do
local _, field_without_mods = extract_termobj_field_modifiers(val)
insert_if_not(new_field, field_without_mods)
end
termobj[field] = new_field
end
end
end
remove_field_modifiers("q")
remove_field_modifiers("qq")
remove_field_modifiers("l")
remove_field_modifiers("ll")
remove_field_modifiers("refs")
end
function export.insert_termobj_combining_duplicates(destobjs, termobj)
for _, destobj in ipairs(destobjs) do
if destobj.term == termobj.term and destobj.tr == termobj.tr then
-- Form already present; maybe combine footnotes.
local function combine_field_values(field)
if termobj[field] and termobj[field][1] then
-- Check to see if there are existing values with *; if so, remove them.
if destobj[field] and destobj[field][1] then
local any_values_with_asterisk = false
for _, val in ipairs(destobj[field]) do
local field_mods, _ = extract_termobj_field_modifiers(val)
if field_mods:find("%*") then
any_values_with_asterisk = true
break
end
end
if any_values_with_asterisk then
local filtered_values = {}
for _, val in ipairs(destobj[field]) do
local field_mods, _ = extract_termobj_field_modifiers(val)
if not field_mods:find("%*") then
insert(filtered_values, val)
end
end
if filtered_values[1] then
destobj[field] = filtered_values
else
destobj[field] = nil
end
end
end
local any_footnotes_with_plus = false
for _, val in ipairs(termobj[field]) do
local field_mods, _ = extract_termobj_field_modifiers(val)
if field_mods:find("%+") then
any_footnotes_with_plus = true
break
end
end
if any_footnotes_with_plus then
if not destobj[field] then
destobj[field] = {}
else
destobj[field] = shallow_copy(destobj[field])
end
for _, val in ipairs(termobj[field]) do
local already_seen = false
local field_mods, field_without_mods = extract_termobj_field_modifiers(val)
if field_mods:find("%+") then
for _, existing_val in ipairs(destobj[field]) do
local _, existing_field_without_mods =
extract_termobj_field_modifiers(existing_val)
if existing_field_without_mods == field_without_mods then
already_seen = true
break
end
end
if not already_seen then
insert(destobj[field], val)
end
end
end
end
end
end
combine_field_values("q")
combine_field_values("qq")
combine_field_values("l")
combine_field_values("ll")
combine_field_values("refs")
if destobj.id and termobj.id and destobj.id ~= termobj.id then
-- FIXME: We probably want to pass in an error function
error(("Can't specify two different ID's %s and %s when combining objects"):format(termobj.id, destobj.id))
end
destobj.id = destobj.id or termobj.id
return
end
end
insert(destobjs, termobj)
end
export.allowed_special_indicators = {
["first"] = true,
["first-second"] = true,
["first-last"] = true,
["second"] = true,
["last"] = true,
["each"] = true,
["+"] = true, -- requests the default behavior with preposition handling
}
--[==[
Check for special indicators (values such as {"+first"} or {"+first-last"} that are used in a `pl`, `f`, etc. argument
and indicate how to inflect a multiword term). If `form` is such an indicator, the return value is `form` minus
the initial `+` sign; otherwise, if form begins with a `+` sign, an error is thrown; otherwise the return value is nil.
]==]
function export.get_special_indicator(form, noerror)
if form:find("^%+") then
form = form:gsub("^%+", "")
if not export.allowed_special_indicators[form] then
if noerror then
return nil
end
local indicators = {}
for indic, _ in pairs(export.allowed_special_indicators) do
insert(indicators, "+" .. indic)
end
sort(indicators)
error("Special inflection indicator beginning with '+' can only be " ..
mw.text.listToText(indicators) .. ": +" .. form)
end
return form
end
return nil
end
local function add_endings(bases, endings)
local retval = {}
if type(bases) ~= "table" then
bases = {bases}
end
if type(endings) ~= "table" then
endings = {endings}
end
for _, base in ipairs(bases) do
for _, ending in ipairs(endings) do
insert(retval, base .. ending)
end
end
return retval
end
--[==[
Inflect a possibly multiword or hyphenated term `form` using the function `inflect`, which is a function of one argument
that is called on a single word to inflect and should return either the inflected word or a list of inflected words.
`special` indicates how to inflect the multiword term and should be e.g. {"first"} to inflect only the first word,
{"first-last"} to inflect the first and last words, {"each"} to inflect each word, etc. See `allowed_special_indicators`
above for the possibilities. If `special` is `+`, or is omitted and the term is multiword (i.e. containing a space
character), and `prepositions` is supplied, the function checks for multiword or hyphenated terms containing the
prepositions in `prepositions`, e.g. Italian [[senso di marcia]] or [[medaglia d'oro]] or Portuguese
[[tartaruga-do-mar]]. If such a term is found, only the first word is inflected. Otherwise, the default is
{"first-last"}. `prepositions` is a list of Lua patterns matching prepositions. The patterns will automatically have the
separator character (space or hyphen) added to the left side but not the right side, so they should contain a space
character (which will automatically be converted to the appropriate separator) on the right side unless the preposition
is joined on the right side with an apostrophe. Examples of preposition patterns for Italian are {"di "}, {"sull'"} and
{"d?all[oae] "} (which matches {"dallo "}, {"dalle "}, {"alla "}, etc.).
The return value is always either a list of inflected multiword or hyphenated terms, or nil if `special` is omitted
and `form` is not multiword. (If `special` is specified and `form` is not multiword or hyphenated, an error results.)
]==]
function export.handle_multiword(form, special, inflect, prepositions, sep)
sep = sep or form:find(" ") and " " or "%-"
local raw_sep = sep == " " and " " or "-"
-- Used to add regex version of separator in the replacement portion of ugsub() or :gsub()
local sep_replacement = sep == " " and " " or "%%-"
-- Given a Lua pattern, replace space with the appropriate separator.
local function hack_re(re)
if sep == " " then
return re
end
return (re:gsub(" ", sep_replacement))
end
if special == "first" then
local first, rest = form:match(hack_re("^(.-)( .*)$"))
if not first then
error("Special indicator 'first' can only be used with a multiword term: " .. form)
end
return add_endings(inflect(first), rest)
elseif special == "second" then
local first, second, rest = form:match(hack_re("^([^ ]+ )([^ ]+)( .*)$"))
if not first then
error("Special indicator 'second' can only be used with a term with three or more words: " .. form)
end
return add_endings(add_endings({first}, inflect(second)), rest)
elseif special == "first-second" then
local first, space, second, rest = form:match(hack_re("^([^ ]+)( )([^ ]+)( .*)$"))
if not first then
error("Special indicator 'first-second' can only be used with a term with three or more words: " .. form)
end
return add_endings(add_endings(add_endings(inflect(first), space), inflect(second)), rest)
elseif special == "each" then
local terms = split(form, sep)
if #terms < 2 then
error("Special indicator 'each' can only be used with a multiword term: " .. form)
end
for i, term in ipairs(terms) do
terms[i] = inflect(term)
if i > 1 then
terms[i] = add_endings(raw_sep, terms[i])
end
end
local result = ""
for _, term in ipairs(terms) do
result = add_endings(result, term)
end
return result
elseif special == "first-last" then
local first, middle, last = form:match(hack_re("^(.-)( .* )(.-)$"))
if not first then
first, middle, last = form:match(hack_re("^(.-)( )(.*)$"))
end
if not first then
error("Special indicator 'first-last' can only be used with a multiword term: " .. form)
end
return add_endings(add_endings(inflect(first), middle), inflect(last))
elseif special == "last" then
local rest, last = form:match(hack_re("^(.* )(.-)$"))
if not rest then
error("Special indicator 'last' can only be used with a multiword term: " .. form)
end
return add_endings(rest, inflect(last))
elseif special and special ~= "+" then
error("Unrecognized special=" .. special)
end
-- Only do default behavior if special indicator '+' explicitly given or separator is space; otherwise we will
-- break existing behavior with hyphenated words.
if (special == "+" or sep == " ") and form:find(sep) then
if prepositions then
-- check for prepositions in the middle of the word; do it this way so we can handle
-- more than one word before the preposition (and usually inflect each word)
for _, prep in ipairs(prepositions) do
local first, space_prep_rest = umatch(form, hack_re("^(.-)( " .. prep .. ".*)$"))
if first then
return add_endings(inflect(first), space_prep_rest)
end
end
end
-- multiword or hyphenated expressions default to first-last; we need to pass in the separator to avoid
-- problems with multiword terms containing hyphens in the individual words
return export.handle_multiword(form, "first-last", inflect, prepositions, sep)
end
return nil
end
local function link_hyphen_split_component(word, data)
if data.link_hyphen_split_component then
return data.link_hyphen_split_component(word)
else
return "[[" .. word .. "]]"
end
end
-- Default function to split a word on apostrophes. Don't split apostrophes at the beginning or end of a word (e.g.
-- [['ndrangheta]] or [[po']]). Handle multiple apostrophes correctly, e.g. [[l'altr'ieri]] -> [[l']][altr']][[ieri]].
function export.default_split_apostrophe(word, data)
local apostrophe_parts = split(word, "'", true, true)
local linked_apostrophe_parts = {}
local apostrophes_at_beginning = ""
local i = 1
-- Apostrophes at beginning get attached to the first word after (which will always exist but may
-- be blank if the word consists only of apostrophes).
while i < #apostrophe_parts do -- <, not <=, in case the word consists only of apostrophes
local apostrophe_part = apostrophe_parts[i]
i = i + 1
if apostrophe_part == "" then
apostrophes_at_beginning = apostrophes_at_beginning .. "'"
else
break
end
end
apostrophe_parts[i] = apostrophes_at_beginning .. apostrophe_parts[i]
-- Now, do the remaining parts. A blank part indicates more than one apostrophe in a row; we join
-- all of them to the preceding word.
while i <= #apostrophe_parts do
local apostrophe_part = apostrophe_parts[i]
if apostrophe_part == "" then
linked_apostrophe_parts[#linked_apostrophe_parts] =
linked_apostrophe_parts[#linked_apostrophe_parts] .. "'"
elseif i == #apostrophe_parts then
insert(linked_apostrophe_parts, apostrophe_part)
else
insert(linked_apostrophe_parts, apostrophe_part .. "'")
end
i = i + 1
end
for j, tolink in ipairs(linked_apostrophe_parts) do
linked_apostrophe_parts[j] = link_hyphen_split_component(tolink, data)
end
return concat(linked_apostrophe_parts)
end
--[=[
Auto-add links to a word that should not have spaces but may have hyphens and/or apostrophes. We split off final
punctuation, then split on hyphens if `data.split_hyphen` is given, and also split on apostrophes if
`data.split_apostrophe` is given. We only split on hyphens if they are in the middle of the word, not at the beginning
or end (hyphens at the beginning or end indicate suffixes or prefixes, respectively). `include_hyphen_prefixes`, if
given, is a set of prefixes (not including the final hyphen) where we should include the final hyphen in the prefix.
Hence, e.g. if "anti" is in the set, a Portuguese word like [[anti-herói]] "anti-hero" will be split [[anti-]][[herói]]
(whereas a word like [[código-fonte]] "source code" will be split as [[código]]-[[fonte]]).
If `data.split_apostrophe` is specified, we split on apostrophes unless `data.no_split_apostrophe_words` is given and
the word is in the specified set, such as French [[c'est]] and [[quelqu'un]]. If `data.split_apostrophe` is true, the
default algorithm applies, which splits on all apostrophes except those at the beginning and end of a word (as in
Italian [['ndrangheta]] or [[po']]), and includes the apostrophe in the link to its left (so we auto-split French
[[l'eau]] as [[l']][[eau]] and [[l'altr'ieri]] as [[l']][altr']][[ieri]]). If `data.split_apostrophe` is specified
but not `true`, it should be a function of one argument that does custom apostrophe-splitting. The argument is the word
to split, and the return value should be the split and linked word.
]=]
local function add_single_word_links(space_word, data, term_has_spaces)
local space_word_no_punct, punct
local punct_pattern = data.punctuation
if punct_pattern and is_callable(punct_pattern) then
space_word_no_punct, punct = punct_pattern(space_word)
else
if punct_pattern == nil then
punct_pattern = "[,;:?!]"
end
space_word_no_punct, punct = umatch(space_word, "^(.*)(" .. punct_pattern .. ")$")
end
space_word_no_punct = space_word_no_punct or space_word
punct = punct or ""
local words
if space_word_no_punct:sub(1, 1) == "-" or space_word_no_punct:sub(-1) == "-" then
-- don't split prefixes and suffixes
words = {space_word_no_punct}
else
local splitter
if term_has_spaces then
splitter = data.split_hyphen_when_space
else
splitter = data.split_hyphen_when_no_space
end
if is_callable(splitter) then
words = splitter(space_word_no_punct)
if type(words) == "string" then
return words .. punct
end
end
end
if not words then
local split_hyphen
if term_has_spaces then
split_hyphen = data.split_hyphen_when_space
else
split_hyphen = data.split_hyphen_when_no_space
if split_hyphen == nil then -- default to true; use `false` to avoid this
split_hyphen = true
end
end
if split_hyphen then
words = split(space_word_no_punct, "-", true, true)
else
words = {space_word_no_punct}
end
end
local linked_words = {}
for j, word in ipairs(words) do
if j < #words and data.include_hyphen_prefixes and data.include_hyphen_prefixes[word] then
word = "[[" .. word .. "-]]"
elseif j > 1 and data.include_hyphen_suffixes and data.include_hyphen_suffixes[word] then
word = "[[-" .. word .. "]]"
else
-- Don't split on apostrophes if the word is in `no_split_apostrophe_words`.
if (not data.no_split_apostrophe_words or not data.no_split_apostrophe_words[word]) and
data.split_apostrophe and word:find("'", nil, true) then
if data.split_apostrophe == true then
word = export.default_split_apostrophe(word, data)
else -- custom apostrophe splitter/linker
word = data.split_apostrophe(word)
end
elseif word ~= "" then -- avoid -[[]]- (e.g. f--k)
word = link_hyphen_split_component(word, data)
end
if j < #words then
word = word .. "-"
end
end
insert(linked_words, word)
end
return concat(linked_words) .. punct
end
--[=[
Auto-add links to a multiword term. `data` contains fields customizing how to do this. By default we proceed as follows:
(1) If the term already has embedded links in it, they are left unchanged.
(2) Otherwise, if there are spaces present, we split on spaces and link each word separately.
(3) If a given space-separated component ends in punctuation (defaulting to [,;:?!]), it is separated off, the remainder
of the algorithm run, and the punctuation pasted back on.
(4) If there are hyphens in a given space-separated component, we may link each hyphenated term separately depending
on the settings in `data`. Normally the hyphens are not included in the linked terms, but this can be overridden
for specific prefixes and/or suffixes. By default, if there are spaces in the multiword term, we do not link
hyphenated components (because of cases like "boire du petit-lait" where "petit-lait" should be linked as a whole),
but do so otherwise (e.g. for "avant-avant-hier"); this can overridden for cases like "croyez-le ou non".
Cases where only some of the hyphens should be split can always be handled by explicitly specifying the head (e.g.
"Nord-Pas-de-Calais" given as head=[[Nord]]-[[Pas-de-Calais]]).
(5) If there are apostrophes in a given component, we may link each apostrophe-separated term separately depending
on the settings in `data`, including the apostrophe in the link to its left (so we split "de l'eau" as
"[[de]] [[l']][[eau]]").
The settings in `data` are as follows:
`split_hyphen_when_no_space`: Whether to split on hyphens when the term has no spaces. Defaults to true if set to `nil`.
This can be a function of one argument, to implement a custom splitting algorithm for hyphen-separated terms. If
this returns [FIXME: FINISH ME ...]
If `data.split_apostrophe` is specified, we split on apostrophes unless `data.no_split_apostrophe_words` is given and
the word is in the specified set, such as French [[c'est]] and [[quelqu'un]]. If `data.split_apostrophe` is true, the
default algorithm applies, which splits on all apostrophes except those at the beginning and end of a word (as in
Italian [['ndrangheta]] or [[po']]), and includes the apostrophe in the link to its left (so we auto-split French
[[l'eau]] as [[l']][[eau]] and [[l'altr'ieri]] as [[l']][altr']][[ieri]]). If `data.split_apostrophe` is specified
but not `true`, it should be a function of one argument that does custom apostrophe-splitting. The argument is the word
to split, and the return value should be the split and linked word.
We don't always split on hyphens because of cases like "boire du petit-lait" where "petit-lait" should be linked as a
whole, but provide the option to do it for cases like "croyez-le ou non". If there's no space, however, then it makes
sense to split on hyphens by `no_split_apostrophe_words` and `include_hyphen_prefixes` allow for special-case handling
of particular words and are as described in the comment above add_single_word_links().
]=]
function export.add_links_to_multiword_term(term, data)
if term:match("[%[%]]") then
return term
end
local words = split(term, " ", true, true)
local term_has_spaces = #words > 1
local linked_words = {}
for _, word in ipairs(words) do
insert(linked_words, add_single_word_links(word, data, term_has_spaces))
end
local retval = concat(linked_words, " ")
-- If we ended up with a single link consisting of the entire term,
-- remove the link.
return retval:match("^%[%[([^%[%]]*)%]%]$") or retval
end
local function canonicalize_begin_end_spec(spec)
local from, to = spec:match("^(.-):(.*)$")
if not from then
from = spec
to = ""
end
return from, to
end
--[==[
Given a `linked_term` that is the output of add_links_to_multiword_term(), apply modifications as given in
`modifier_spec` to change the link destination of subterms (normally single-word non-lemma forms; sometimes
collections of adjacent words). This is usually used to link non-lemma forms to their corresponding lemma, but can
also be used to replace a span of adjacent separately-linked words to a single multiword lemma. The format of
`modifier_spec` is one or more semicolon-separated subterm specs, where each such spec is of the form
SUBTERM:DEST, where SUBTERM is one or more words in the `linked_term` but without brackets in them, and DEST is the
corresponding link destination to link the subterm to. Any occurrence of ~ in DEST is replaced with SUBTERM.
Alternatively, a single modifier spec can be of the form BEGIN[FROM:TO], which is equivalent to writing
BEGINFROM:BEGINTO (see example below).
For example, given the source phrase [[il bue che dice cornuto all'asino]] "the pot calling the kettle black"
(literally "the ox that calls the donkey horned/cuckolded"), the result of calling add_links_to_multiword_term()
is [[il]] [[bue]] [[che]] [[dice]] [[cornuto]] [[all']][[asino]]. With a modifier_spec of 'dice:dire', the result
is [[il]] [[bue]] [[che]] [[dire|dice]] [[cornuto]] [[all']][[asino]]. Here, based on the modifier spec, the
non-lemma form [[dice]] is replaced with the two-part link [[dire|dice]].
Another example: given the source phrase [[chi semina vento raccoglie tempesta]] "sow the wind, reap the whirlwind"
(literally (he) who sows wind gathers [the] tempest"). The result of calling add_links_to_multiword_term() is
[[chi]] [[semina]] [[vento]] [[raccoglie]] [[tempesta]], and with a modifier_spec of 'semina:~re; raccoglie:~re',
the result is [[chi]] [[seminare|semina]] [[vento]] [[raccogliere|raccoglie]] [[tempesta]]. Here we use the ~
notation to stand for the non-lemma form in the destination link.
A more complex example is [[se non hai altri moccoli puoi andare a letto al buio]], which becomes
[[se]] [[non]] [[hai]] [[altri]] [[moccoli]] [[puoi]] [[andare]] [[a]] [[letto]] [[al]] [[buio]] after calling
add_links_to_multiword_term(). With the following modifier_spec:
'hai:avere; altr[i:o]; moccol[i:o]; puoi: potere; andare a letto:~; al buio:~', the result of applying the spec is
[[se]] [[non]] [[avere|hai]] [[altro|altri]] [[moccolo|moccoli]] [[potere|puoi]] [[andare a letto]] [[al buio]].
Here, we rely on the alternative notation mentioned above for e.g. 'altr[i:o]', which is equivalent to 'altri:altro',
and link multiword subterms using e.g. 'andare a letto:~'. (The code knows how to handle multiword subexpressions
properly, and if the link text and destination are the same, only a single-part link is formed.)
]==]
function export.apply_link_modifiers(linked_term, modifier_spec, lang)
local split_modspecs = split(modifier_spec, "%s*;%s*")
for j, modspec in ipairs(split_modspecs) do
local id
if modspec:find("<") then
local rest
rest, id = modspec:match("^(.*)<id:(.-)>$")
if rest then
modspec = rest
end
end
local subterm, dest, otherlang
local begin_spec, rest, end_spec = modspec:match("^%[(.-)%]([^:]*)%[(.-)%]$")
if begin_spec then
local begin_from, begin_to = canonicalize_begin_end_spec(begin_spec)
local end_from, end_to = canonicalize_begin_end_spec(end_spec)
subterm = begin_from .. rest .. end_from
dest = begin_to .. rest .. end_to
end
if not subterm then
rest, end_spec = modspec:match("^([^:]*)%[(.-)%]$")
if rest then
local end_from, end_to = canonicalize_begin_end_spec(end_spec)
subterm = rest .. end_from
dest = rest .. end_to
end
end
if not subterm then
begin_spec, rest = modspec:match("^%[(.-)%]([^:]*)$")
if begin_spec then
local begin_from, begin_to = canonicalize_begin_end_spec(begin_spec)
subterm = begin_from .. rest
dest = begin_to .. rest
end
end
if not subterm then
subterm, dest = modspec:match("^(.-)%s*:%s*(.*)$")
if subterm and subterm ~= "^" and subterm ~= "$" then
local langdest
-- Parse off an initial language code (e.g. 'en:Higgs', 'la:minūtia' or 'grc:σκατός'). Also handle
-- Wikipedia prefixes ('w:Abatemarco' or 'w:it:Colle Val d'Elsa').
otherlang, langdest = dest:match("^([A-Za-z0-9._-]+):([^ ].*)$")
if otherlang == "w" then
local foreign_wikipedia, foreign_term = langdest:match("^([A-Za-z0-9._-]+):([^ ].*)$")
if foreign_wikipedia then
otherlang = otherlang .. ":" .. foreign_wikipedia
langdest = foreign_term
end
dest = ("%s:%s"):format(otherlang, langdest)
otherlang = nil
elseif otherlang then
otherlang = get_lang_by_code(otherlang, true, "allow etym")
dest = langdest
end
end
end
if not subterm then
if modspec == "?" or modspec == "!" then
subterm = "$"
dest = modspec
elseif modspec == "..." or modspec == "...?" then
subterm = "$"
dest = " " .. modspec
elseif modspec:find("^[A-Z]$") then
-- X, Y, etc. by themselves are unlinked, to help with snowclones
subterm = modspec
dest = "_"
else
subterm = modspec
dest = "~"
end
end
if subterm == "^" then
linked_term = dest:gsub("_", " ") .. linked_term
elseif subterm == "$" then
linked_term = linked_term .. dest:gsub("_", " ")
else
if subterm:find("[", nil, true) then
error(("Subterm '%s' in modifier spec '%s' cannot have brackets in it"):format(
escape_wikicode(subterm), escape_wikicode(modspec)))
end
local escaped_subterm = pattern_escape(subterm)
local subterm_re = "%[%[" .. escaped_subterm:gsub("(%%?[ ',%-])", "%%]*%1%%[*") .. "%]%]"
local expanded_dest
if dest:find("~", nil, true) then
expanded_dest = dest:gsub("~", replacement_escape(subterm))
else
expanded_dest = dest
end
if otherlang then
expanded_dest = expanded_dest .. "#" .. otherlang:getCanonicalName()
end
local subterm_replacement
if expanded_dest == "_" then
subterm_replacement = subterm
if id then
error("Can't supply <id:...> with an unlinked subterm")
end
if otherlang then
error("Can't supply prefixed language with an unlinked subterm")
end
elseif id or otherlang then
if id and expanded_dest:find("[", nil, true) then
error("Can't supply <id:...> with destination with embedded brackets")
end
subterm_replacement = require(links_module).language_link {
lang = otherlang or lang,
term = expanded_dest,
alt = subterm,
id = id,
}
elseif expanded_dest:find("[", nil, true) then
-- Use the destination directly if it has brackets in it (e.g. to put brackets around parts of a word).
subterm_replacement = expanded_dest
elseif expanded_dest == subterm then
subterm_replacement = "[[" .. subterm .. "]]"
else
subterm_replacement = "[[" .. expanded_dest .. "|" .. subterm .. "]]"
end
local escaped_subterm_replacement = replacement_escape(subterm_replacement)
local replaced_linked_term = ugsub(linked_term, subterm_re, escaped_subterm_replacement)
if replaced_linked_term == linked_term then
mw.log(("Attempted to replace %s with %s in %s"):format(subterm_re, escaped_subterm_replacement, linked_term))
error(("Subterm '%s' could not be located in %slinked expression %s, or replacement same as subterm"):format(
subterm, j > 1 and "intermediate " or "", escape_wikicode(linked_term)))
else
linked_term = replaced_linked_term
end
end
end
return linked_term
end
local inflection_to_cats = {
plural = {
filter_plpos = function(plpos)
-- plurals also occur with determiners, adjectives etc. and we don't want to generate categories like
-- 'countable determiners', 'countable adjectives', etc. Note that the passed-in `plpos` has `proper nouns`
-- converted to `nouns`.
return plpos == "nouns"
end,
cats = {"countable {plpos}"},
no_cats = {"uncountable {plpos}"},
},
comparative = {
cats = {"comparable {plpos}"},
no_cats = {"uncomparable {plpos}"},
},
["female equivalent"] = {
cats = {"{plpos} with other-gender equivalents"},
},
["male equivalent"] = {
cats = {"{plpos} with other-gender equivalents"},
},
}
--[=[
Validate the items in `items` against the list or set of valid items in `valid_items`. If `field` is given, fetch the
item to check from that-named field of each object in `items`; otherwise use the items in `items` directly. If an error
occurs, `item_type` specifies the type of item to mention in the error message, which will also list the allowed items
(either taken directly from `valid_items` if a list, or from the sorted keys if a set).
]=]
local function validate_items(data)
local items, field, valid_items, item_type =
data.items, data.field, data.valid_items, data.item_type
local valid_set
if valid_items[1] then
valid_set = list_to_set(valid_items)
else
valid_set = valid_items
end
for _, item in ipairs(items) do
if field then
item = item[field]
end
if not valid_set[item] then
local valid_list
if valid_items[1] then
valid_list = valid_items
else
valid_list = {}
for valid_item, _ in pairs(valid_items) do
insert(valid_list, valid_item)
end
table.sort(valid_list)
end
error(("Invalid %s: %s; expected one of %s"):format(item_type, item, mw.text.listToText(valid_list)))
end
end
end
local Headdata = {}
function Headdata:get_canonicalized_plpos()
return (self.pos_category:gsub("proper noun", "noun"))
end
--[==[
Canonicalize a category. The category string will have the full language name (i.e. the name of the L2 language under
which an entry is inserted, which may a parent language if the language in question is an etymology-only language)
prepended to it, and any occurrences of `{plpos}` in the string replaced with the actual plural part of speech (with
some canonicalization; specifically, `proper nouns` is converted to `nouns` when replacing `{plpos}`). To specify a
full category and not have the language name prepended to it, precede it with {"Category:"}, which will be removed.
]==]
function Headdata:canonicalize_category(category)
if category:find("{plpos}") then
local plpos = self:get_canonicalized_plpos()
category = category:gsub("{plpos}", plpos)
end
if category:find("^Category:") then
return (category:gsub("^Category:", ""))
else
return self.langfullname .. " " .. category
end
end
--[==[
Canonicalize a list of categories according to the process described in `Headdata:canonicalize_category`. This simply
loops over each category in `categories` and calls `Headdata:canonicalize_category` on each one.
]==]
function Headdata:canonicalize_categories(categories)
if not categories then
return categories
end
local canon_cats = {}
for _, cat in ipairs(categories) do
insert(canon_cats, self:canonicalize_category(cat))
end
return canon_cats
end
--[==[
Insert a category into the `categories` list in the headword `data` structure. `category` is normally a string naming
the category, which will have the full language name prepended to it and any occurrences of `{plpos}` in the string
replaced with the actual plural part of speech (with some canonicalization; specifically, `proper nouns` is converted to
`nouns` when replacing `{plpos}`). To specify a full category and not have the language name prepended to it, precede it
with {"Category:"}.
]==]
function Headdata:insert_category(category)
insert(self.categories, self:canonicalize_category(category))
end
--[==[
Validate the genders in `genders` (a list of gender spec objects, as produced by {type = "genders"} in
[[Module:parameters]] and accepted by [[Module:gender and number]]), checking that all specified genders are in the list
given in `valid_genders`. Optional `props` controls how the validation happens. In particular, unless `props.no_augment`
is given, then for any gender beginning with `m`, if a corresponding gender beginning with `f` occurs, analogous genders
beginning with `mf`, `mfbysense` and `mfequiv` are also allowed. For example, if `m-d` (masculine dual) and `f-d`
(feminine dual) both occur, genders `mf-d`, `mfbysense-d` and `mfequiv-d` are also allowed. If a disallowed gender is
given, an error occurs, giving the disallowed gender along with the list of all allowed genders.
]==]
function Headdata:validate_genders(genders, valid_genders, props)
if not genders then
return
end
props = props or {}
local gender_type, no_augment = props.gender_type, props.no_augment
gender_type = gender_type or "headword"
local valid_gender_set = list_to_set(valid_genders)
local augmented_gender_set
if no_augment then
augmented_gender_set = valid_gender_set
else
augmented_gender_set = {}
for g, _ in pairs(valid_gender_set) do
augmented_gender_set[g] = true
if g:find("^m") and not g:find("^mf") and valid_gender_set[g:gsub("^m", "f")] then
augmented_gender_set[g:gsub("^m", "mf")] = true
augmented_gender_set[g:gsub("^m", "mfbysense")] = true
augmented_gender_set[g:gsub("^m", "mfequiv")] = true
end
end
end
validate_items {
items = genders,
field = "spec",
valid_items = augmented_gender_set,
item_type = ("%s gender"):format(gender_type),
}
end
--[==[
Parse an inflection specified in `field`, the name of a parameter holding an inflection. If the parameter is numeric,
the field should be given as a number (as with the `params` structure passed to [[Module:parameters]]), not a string
containing the representation of a number. The field can specify multiple comma-separated terms, and each term can have
associated inline modifiers that will be parsed (unless there is top-level HTML in the parameter, i.e. HTML not
contained inside an inline modifier, e.g. as may be generated by using {{tl|l}} or similar template inside a parameter).
This is a wrapper around the top-level `parse_term_with_modifiers()` function. `props` is an optional structure
containing additional properties, including all additional properties documented for the top-level
`parse_term_with_modifiers()` function.
If the parameter in `field` is unspecified, the return value of this function will be an empty list, not {nil}, so it
is always safe to iterate over the return value.
By default, the allowed modifiers are the same as for `parse_term_with_modifiers()`, except that (normally) the
`<tr:...>` modifier will be allowed if `include_tr` was specified in the original call to `process_headword()`; likewise
for the `<ts:...>` modifier if `include_ts` was specified and the `<sc:...>` modifier if `include_sc` was specified. If
If you pass in your own `include_mods` list of additional allowed modifiers, it will (normally) automatically be
augmented with {"tr"}, {"ts"} and/or {"sc"} if `include_tr`, `include_ts` and/or `include_sc` was specified when calling
`process_headword()`. To disable automatic augmentation of these modifiers (whether or not you specify an `include_mods`
property), specify {no_augment_include_mods = true} in `props`.
]==]
function Headdata:parse_inflection(field, props)
local val = self.process_props.args[field]
if not val then
return {}
end
props = props and shallow_copy(props) or {}
local include_mods = props.include_mods
local data = self.process_props.data
if not props.no_augment_include_mods and (data.include_tr or data.include_ts or data.include_sc) then
include_mods = include_mods and shallow_copy(include_mods) or {}
if data.include_tr then
insert_if_not(include_mods, "tr")
end
if data.include_ts then
insert_if_not(include_mods, "ts")
end
if data.include_sc then
insert_if_not(include_mods, "sc")
end
end
props.val = val
props.paramname = field
props.splitchar = props.splitchar or ","
props.include_mods = include_mods
return export.parse_term_with_modifiers(props) or {}
end
--[==[
Insert previously-parsed terms into the `inflections` of the headword `data` structure. This is a wrapper around
the top-level `insert_inflection()` function. `terms` is the list of parsed terms. (If {nil}, nothing happens unless
`request` is set in `props`.) `label` is the the label that the inflections are given; any parts of the label surrounded
in `<<...>>` are linked to the glossary. (If the contents of `<<...>>` contain a `|` in them, they are a two-part link.)
`props` is an optional structure containing additional properties, including all additional properties documented for
the top-level `insert_inflection()` function.
Unless `no_auto_cats` is given in `props`, certain labels automatically trigger the insertion of additional
categories in specific circumstances. This is controlled by the `inflection_to_cats` structure in
[[Module:headword utilities]]. For example, if the part of speech is {"nouns"} or {"proper nouns"} and the label (after
removing any links and `<<...>>` glossary specs) is {"plural"}, an additional category
<code><var>lang</var> countable nouns</code> will be added if a plural value is given (i.e. the value is not {"-"}). If
the value is {"-"} (which indicates that there is no plural and triggers the insertion of the fixed inflection label
{"no plural"}), <code><var>lang</var> uncountable nouns</code> will be inserted instead, and if both {"-"} and a value
are given (which triggers the insertion of the {"usually no plural"} fixed inflection label), both categories are added.
Similar categories are inserted when a comparative is given (with a label {"comparative"}), and if the label is
{"female equivalent"} or {"male equivalent"} and the value is not {"-"}, a category such as
<code><var>lang</var> nouns with other-gender equivalents</code> is inserted.
]==]
function Headdata:insert_inflection(terms, label, props)
props = props and shallow_copy(props) or {}
if not props.no_auto_cats then
local bare_label = label
if bare_label:find("[[", nil, true) then
bare_label = require(links_module).remove_links(bare_label)
end
if bare_label:find("<<", nil, true) then
bare_label = bare_label:gsub("<<.-|(.-)>>", "%1"):gsub("<<(.-)>>", "%1")
end
local cats = inflection_to_cats[bare_label]
if cats then
if not cats.filter_plpos or cats.filter_plpos(self:get_canonicalized_plpos()) then
if props.cats == nil then
props.cats = self:canonicalize_categories(cats.cats)
end
if props.usually_no_cats == nil then
props.usually_no_cats = self:canonicalize_categories(cats.usually_no_cats)
end
if props.no_cats == nil then
props.no_cats = self:canonicalize_categories(cats.no_cats)
end
end
end
end
props.headdata = self
props.terms = terms
props.label = label
return export.insert_inflection(props)
end
--[==[
Insert a "fixed" inflection (a label without associated values) into the `inflections` table of the headword `data`
structure, labeled according to `label` (which can have glossary links in it specified using `<<...>>`, exactly as for
`:insert_inflection()`). An example label (from {{tl|mn-noun}} in [[Module:mn-headword]]) is {"hidden-g declension"},
specifying that the noun belongs to the hidden-''g'' declension. This is a direct wrapper around the top-level function
`insert_fixed_inflection()`; see that function for more details on optional `props`.
]==]
function Headdata:insert_fixed_inflection(label, props)
props = props and shallow_copy(props) or {}
props.headdata = self
props.label = label
export.insert_fixed_inflection(props)
end
--[==[
Parse the inflection(s) specified in `field` and insert them into the `inflections` table of the headword `data`
structure, labeled according to `label`. This is equivalent to calling {terms = data:parse_inflection(field, props)}
followed by {return data:insert_inflection(terms, label, props)} and behaves the same as the combination of those two
functions. See their documentation for more details.
]==]
function Headdata:parse_and_insert_inflection(field, label, props)
local terms = self:parse_inflection(field, props)
return self:insert_inflection(terms, label, props)
end
--[==[
Generate an inflection that may be specified explicitly or defaulted (which involves looping over the specified or
defaulted heads and determining the script of each one, since the formation of the default depends on the script).
`data` is the data object passed into the POS handler. `terms` is the list of terms to process. Those where the term
itself is not `+` will be returned unchanged, while those where the term is `+` will be handled by generating the
appropriate inflections from the headwords using `make_inflection` (which is passed three arguments, `head`, `tr` and
`sccode`, i.e. the script code of `head`) and should return two values, term and translit, either of which can be
nil. A nil head will be ignored, and otherwise the decorations specified on the `+` term will be combined with the
decorations specified on the head. The return value is a list of inflections where no requests for the default
inflection remain.
]==]
function Headdata:resolve_special(terms, handle_special, props)
props = props or {}
local infls = {}
local is_special = props.is_special or function(_data, infl) return infl.term == "+" end
for _, termobj in ipairs(terms) do
if not is_special(self, termobj) then
insert(infls, termobj)
else
for _, headobj in ipairs(self.heads) do
local head = headobj.term or self.pagename
local head_no_links
if props.with_links then
head = head:find("%[") and head or require(headword_module).add_multiword_links(head, not headobj.term)
head_no_links = require(links_module).remove_links(head)
else
head = require(links_module).remove_links(head)
head_no_links = head
end
local newterms = handle_special {
head = head,
tr = headobj.tr,
infl = termobj,
sc = self.lang:findBestScript(head_no_links),
}
if newterms then
newterms = export.canonicalize_termobj_list(newterms, "term", "resolve_special")
for _, newterm in ipairs(newterms) do
if not props.no_combine_handle_special_retval_with_origin then
export.combine_termobj_decorations(newterm, termobj)
end
if not props.no_combine_handle_special_retval_with_head then
export.combine_termobj_decorations(newterm, headobj)
end
insert(infls, newterm)
end
end
end
end
end
return infls
end
--[==[
Add the current page to a tracking page named `Wiktionary:Tracking/``lang``-headword/``page```, where ``lang`` is the
language code of the current language. For example, if the current language is `mak` and `page` is {"redundant-lon"},
the current page will get added to the tracking page `Wiktionary:Tracking/mak-headword/redundant-lon`. All pages added
to that tracking page can be seen by going to [[Special:WhatLinksHere/Wiktionary:Tracking/mak-headword/redundant-lon]].
This is typically used to track issues occurring in user-specified parameters that do not rise to the level of errors
(e.g. redundant parameters, deprecated usages or other dispreferred values).
]==]
function Headdata:track(page)
return require(debug_track_module)(self.langcode .. "-headword/" .. page)
end
local boolean_param = {type = "boolean"}
--[==[
Process an arbitrary headword in an arbitrary language, handling generic and language-specific arguments and calling
`full_headword()` in [[Module:headword]]. This is intended for use in implementing headword modules (e.g.
[[Module:uz-headword]] for Uzbek, [[Module:mn-headword]] for Uzbek, [[Module:gsw-headword]] for Alemannic German, etc.)
and provides a general implementation of such modules. On input, `data` is an object with the following fields:
* `lang`: The language object of the language being handled. '''Required.''' Use the special value {false} to indicate
that the language is specified by the user in {{para|1}}.
* `frame`: The frame object passed into the `show()` function of your module, which implements headword-handling for
all parts of speech in the module, including a generic POS-handling template (e.g. {{tl|uz-head}} or {{tl|mn-head}}),
which allows arbitrary parts of speech to be handled. '''Required.'''
* `pos_functions`: A table listing, for each part of speech requiring special handling, the extra parameters (if any)
that the part of speech accepts, along with how to handle them. See the examples below. '''Required.'''
* `validate_lang`: If {lang = true} is specified, this is a function of one argument (a language object, based on the
language specified in {{para|1}}) that should throw an error if the language object is disallowed. If omitted, all
languages are allowed.
* `numbered_head`: If true, explicit headwords are specified in a numbered param instead of in {{para|head}}. The param
used is usually {{para|1}}, but is {{para|2}} for generic POS templates such as {{tl|mn-head}} or for POS-specific
templates when {lang = true} is specified (e.g. {{tl|arb-noun}}), and is {{para|3}} for generic POS templates when
{lang = true} is spcified (e.g. {{tl|arb-head}}).
* `include_tr`: If true, allow explicit transliterations to be specified. The transliteration(s) for the headword(s)
themselves is/are specified in {{para|tr}} or through the {{cd|<tr:...>}} inline modifier on headwords, and
transliterations of inflections are specified through the {{cd|<tr:...>}} inline modifier. This should generally be
given when a headword for the language may be in a script other than Latin.
* `include_ts`: If true, allow explicit transcriptions to be specified. The transcription(s) for the headword(s)
themselves is/are specified in {{para|ts}} or through the {{cd|<ts:...>}} inline modifier on headwords, and
transcriptions of inflections are specified through the {{cd|<ts:...>}} inline modifier. This should generally only
be given for certain languages where the spelling is radically different from the pronunciation (e.g. in cuneiform
languages such as Hittite and Akkadian, and potentially in Tibetan), and represents a pronunciation-based rendering
(usually not direct IPA).
* `include_sc`: If true, allow an explicit script code to be specified. The overall script code for the headword(s)
themselves can be specified using {{para|sc}}, and per-headword or per-inflection script codes are specified using the
{{cd|<sc:...>}} inline modifier. This should generally be given when a language supports multiple scripts.
* `infls`: An inflections structure specifying extra generic parameters that apply to all parts of speech and how to
handle them. The format is the same as for the `infls` structure in `pos_functions`.
* `augment_params`: A callback function to add extra generic parameters, or modify existing generic parameters in the
`params` structure; but in general, extra generic parameters should be added through the `infls` structure instead.
This callback should not be used to add part-of-speech-specific parameters; those are handled through the appropriate
setting in `pos_functions`. It is passed two single arguments, the `headdata` object and the `params` table to be
augmented. See below for extra fields stored in the `process_props` structure of the `headdata` object. This function
is called after initializing the `params` table and processing the overall `infls` structure, but just before adding
part-of-speech-specific parameters (from `pos_functions`) to `params`. Thus, it can override any generic parameters
but may itself be overridden by a part-of-speech-specific parameter.
* `augment_headdata`: A callback function to modify the `headdata` object passed to `full_headword()` in
[[Module:headword]]. This should not be used to for part-of-speech-specific parameter handling; this is handled
through the appropriate setting in `pos_functions`. It is passed a single argument, the `headdata` object, as for
`augment_params`; but the `process_props` structure and other fields will be more filled out, as this callback is
called later. This can be used, for example, to override the value of a generic setting in `headdata` (e.g.
[[Module:uz-headword]] uses this to mark non-Latin terms as variant forms by setting `headdata.var`, being careful not
to override a value already set by the user). This function is called after initializing the `headdata` table with all
information taken from generic parameters and processing generic parameters specified in the overall `infls`
structure, and just before processing the appropriate part-of-speech-specific `infls` structure in `pos_functions`
(which in turn is followed by any handler function in `pos_functions`). Thus, it can override any value set during
generic parameter processing but may itself be overridden by a part-of-speech-specific parameter or handler.
* `force_cat`: If true, add the headword to the appropriate categories even on non-mainspace pages. This can be used for
testing category handling in sample template calls on userspace test pages or template documentation pages. It should
not be set in production code.
* `enable_auto_translit`: If true, turn on automatic transliteration of inflections at a global level (i.e. applying to
all inflections). This has no effect on headwords, which are automatically transliterated by default if in a non-Latin
script and automatic transliteration is available for the language. You can also set this value for particular
inflections in the `insert_inflection()` function.
The `headdata` headword data structure has an extra field in it called `process_props` that is specific to the
`process_headword()` function, containing various extra properies. As the operation of `process_headword()` proceeds,
this object gets filled out with more fields. For example, once parameter parsing happens, the resulting values are
available in the `args` field of `process_props`. The following fields are found in `process_props` (note that `poscat`,
the canonicalized plural part of speech of the headword being processed, is *not* present here; it's directly on
`headdata`):
* `namespace`: The name of the current namespace; an empty string for the mainspace. This references the namespace of
the actual page and isn't affected by the {{para|pagename}} parameter.
* `indexing_poscat`: The canonicalized part of speech of the headword used to index into `pos_functions`. This is the
same as `poscat` for specific part-of-speech templates such as {{tl|uz-noun}}, but has the value {"head"} for generic
part-of-speech templates such as {{tl|uz-head}}. (Note that `poscat` is directly available on `headdata`.)
* `generic_pos_template`: True if a generic POS templates like {{tl|uz-head}} or {{tl|mn-head}} was used. (This is
signaled by omitting the invocation parameter {{para|1}} to `process_headword`.)
* `lang_in_1`: True if the language code is to be fetched from {{para|1}}.
* `pos_param`: The parameter holding the part of speech, if a generic POS tempalte like {{tl|mn-head}} is being
processed (i.e. `generic_pos_template` is set). In such a case, it will have the value of {1} or {2}, depending on
whether the language code is being fetched from {{para|1}} (see `lang_in_1`). Otherwise it will be {nil}.
* `head_param`: The parameter holding the explicit headword. If `numbered_head` was specified (as for Mongolian headword
templates), this has the value {1}, {2} or {3} depending on whether the language code is being fetched from {{para|1}}
(see `lang_in_1`) and whether a generic POS template like {{tl|mn-head}} is being processed (see
`generic_pos_template`). Otherwise, it has the value {"head"}. Also see the `lang` and `numbered_head` properties in
the `data` structure sent to `process_headword()`.
* `is_suffix`: True if the current term is a suffix. This is set when processing the `suffix`, `nosuffix` and `clitic`
parameters; it is always {false} beforehand (i.e. during `augment_params` and processing of the general `infls`
structure).
* `insert_specs`: This is a table mapping parameter names to the return value of `Headdata:insert_inflection()`, filled
out as parameter values are processed. This lets a given parameter processing function in `infls` gain access to the
result of calling `insert_inflection()` on previous parameters (which indicates the number of items inserted as well
as whether `-` was specified).
The `pos_functions` table contains an entry for each part of speech needing special handling, where the key is the
canonical plural part of speech (e.g. {"adverbs"} or {"proper nouns"}). The value associated with each key is a table
normally containing a field `infls`, listing the extra part-of-speech-specific inflection and other parameters along
with how to handle them. The specs in `infls` are used in three ways:
# to augment the `params` object passed to the `process()` function in [[Module:parameters]], specifying how to parse
the appropriate inflectional parameters;
# to specify how to process any inflectional parameters given and insert them into the `headdata` object passed to
`full_headword()` in [[Module:headword]];
# to generate appropriate documentation for the parameters and other changes made by the headword template (e.g.
inserting categories).
Alternatively, you can separately control the augmentation of the `params` object and the procesing of the resulting
arguments. This is done by specifying two fields in place of `infls`, named `params` and `func`. `params` is a table
containing extra parameters to add to the overall `params` object passed to the `process()` function in
[[Module:parameters]]. `func` is a function of two arguments, normally called `data` (the headword data structure
`headdata`) and `args` (the processed arguments table). However, this alternative method is not normally recommended
because it leads to duplication between the `params and `func` fields and the documentation, which must be manually
specified.
A simple example, as used to handle pronouns for Turoyo, is
{
local valid_genders = {"m", "f", "m-p", "f-p", "p", "?"}
pos_functions["pronouns"] = {
infls = {
{2, type = "genders", validate = valid_genders},
{"f", label = "feminine"},
{"pl", label = "plural"},
},
}
}
The equivalent using `params` and `func` is
{
local valid_genders = {"m", "f", "m-p", "f-p", "p", "?"}
pos_functions["pronouns"] = {
params = {
[2] = {type = "genders"},
f = true,
pl = true,
},
func = function(data, args)
data:validate_genders(args[2], valid_genders)
data.genders = args[2]
data:parse_and_insert_inflection("f", "feminine")
data:parse_and_insert_inflection("pl", "plural")
end
}
}
Note how the version with separate `params and `func` is longer and splits information on the parameters between the
two fields. The `params` structure sets extra user-specifiable parameters {{para|2}} for genders (since the headword is
in {{para|1}}) as well a {{para|f}} and {{para|pl}}, and the `func` handler processes those parameters. Note how this is
done by calling methods on the headword `data` structure. Each such parameter can have multiple comma-separated values,
and each value can have inline modifiers attached to it to specify further properties of the value. The `infls` version
ends up making the same method calls, but does it for you instead of you having to do it yourself.
These methods are implemented through a metatable set on the headword `data` structure, which is removed before calling
`full_headword()` in [[Module:headword]]. The methods access extra information related to headword processing (such as
the `args` table) that is stored in the `process_props` field of the headword `data` strucuture. This field is also
removed prior to calling `full_headword()`.
The methods available on the headword `data` structure are as follows. Each one also has its own documentation.
* {parse_inflection(field, props)}: Parse value(s) specified in `field` (a user-specified parameter in the `args` table)
and return a list of term objects. Optional `props` specifies additional properties controlling the parsing.
* {insert_inflection(terms, label, props)}: Insert the terms in `terms` (a list of term objects as returned by
`parse_inflection()`) into the `inflections` list in the headword `data` structure, giving the inflection the label as
specified in `label`. Optional `props` specifies additional properties controlling the parsing.
* {parse_and_insert_inflection(field, label, props)}: A combination of `parse_inflection()` and `insert_inflection()`,
if no further processing of the parsed values needs to be done before insertion.
* {insert_fixed_inflection(label, props)}: Insert a "fixed" inflection (a label without associated values) into the
`inflections` table. An example (from {{tl|mn-noun}} in [[Module:mn-headword]]) is {"hidden-g declension"}, specifying
that the noun belongs to the hidden-''g'' declension.
* {resolve_special(terms, handle_special, props)}: Resolve "special" indicators as specified by the user in an inflection
parameter. A typical example is {"+"}, requesting a default value. `terms` is the list of parsed term objects and
`handle_special` is a handler function to process special indicators and convert them to their actual values.
* {validate_genders(genders, valid_genders, props)}: Validate that the user-specified genders in `genders` all belong to
the list given in `valid_genders`, throwing an error if not.
* {insert_category(category)}: Insert a category into the `categories` list in the headword `data` structure. `category`
is normally a string naming the category, which will have the language prepended to it and any occurrences of
`{plpos}` in the string replaced with the actual plural part of speech.
]==]
function export.process_headword(data)
local lang, frame, pos_functions, validate_lang, numbered_head, include_tr, include_ts, include_sc, force_cat,
enable_auto_translit, infls, augment_params, augment_headdata =
data.lang, data.frame, data.pos_functions, data.validate_lang, data.numbered_head, data.include_tr,
data.include_ts, data.include_sc, data.force_cat, data.enable_auto_translit, data.infls, data.augment_params,
data.augment_headdata
local iparams = {
[1] = true,
def = true,
}
local iargs = require(parameters_module).process(frame.args, iparams)
local parargs = frame:getParent().args
local langcode
if not lang then
error("Internal error: `data.lang` must be specified; either a language object or `true` for a user-specified language")
end
local lang_in_1
if lang == true then
lang_in_1 = true
langcode = ine(parargs[1])
if langcode then
langcode = mw.text.trim(langcode)
lang = require(languages_module).getByCode(langcode, 1, true)
if validate_lang then
validate_lang(lang)
end
else
error("Language code (see [[WT:Language codes]]) must be specified in 1=")
end
else
langcode = lang:getCode()
if validate_lang then
error("Internal error: `data.validate_lang` must not be specified if a language code is given in `data.lang`")
end
end
local poscat = iargs[1]
local generic_pos_template = not poscat
local pos_param
if generic_pos_template then
pos_param = lang_in_1 and 2 or 1
poscat = ine(parargs[pos_param]) or
mw.title.getCurrentTitle().fullText == ("Template:%s-head"):format(langcode) and "interjection" or
error(("Part of speech must be specified in %s="):format(pos_param))
poscat = require(headword_module).canonicalize_pos(poscat)
end
local head_param = numbered_head and (generic_pos_template and lang_in_1 and 3 or
(generic_pos_template or lang_in_1) and 2 or 1) or "head"
local indexing_poscat = generic_pos_template and "head" or poscat
local namespace = mw.loadData(headword_data_module).page.namespace
-- Partly initialize headdata now for use in generic infls callbacks. Will be further initialized later after
-- processing parameters.
local headdata = {
lang = lang,
langcode = langcode,
langfullcode = lang:getFullCode(),
langname = lang:getCanonicalName(),
langfullname = lang:getFullName(),
process_props = {
namespace = namespace,
data = data,
indexing_poscat = indexing_poscat,
generic_pos_template = generic_pos_template,
lang_in_1 = lang_in_1,
pos_param = pos_param,
head_param = head_param,
is_suffix = false,
insert_specs = {},
},
pos_category = poscat,
orig_poscat = poscat, -- preserve user-specified poscat in case pos_category is changed to 'suffixes'
categories = {},
inflections = {enable_auto_translit = enable_auto_translit},
force_cat_output = force_cat,
no_redundant_head_cat = true,
}
setmetatable(headdata, {__index = Headdata})
local params = {
[head_param] = {template_default = iargs.def},
head2 = {replaced_by = false, instead = ("use comma-separated |%s="):format(head_param)},
id = true,
sort = true,
cat = true,
nolink = boolean_param,
nolinkhead = {type = "boolean", alias_of = "nolink"},
suffix = boolean_param,
nosuffix = boolean_param,
clitic = true,
addlpos = true,
var = {type = "boolean", allow = {"both"}},
json = boolean_param,
pagename = true, -- for testing
}
if include_sc then
params.sc = {type = "script"}
end
if include_tr then
params.tr = true
params.tr2 = {replaced_by = false, instead = "use comma-separated |tr= or <tr:...> inline modifier on head"}
end
if include_ts then
params.ts = true
params.ts2 = {replaced_by = false, instead = "use comma-separated |ts= or <ts:...> inline modifier on head"}
end
if lang_in_1 then
params[1] = {required = true} -- required but ignored as already processed above
end
if generic_pos_template then
params[pos_param] = {required = true} -- required but ignored as already processed above
end
local function resolve_prop(prop, ...)
if type(prop) == "function" then
prop = prop(headdata, ...)
end
return prop
end
local function augment_params_from_infls(infls)
infls = resolve_prop(infls)
for _, infl in ipairs(infls) do
local function interr(txt)
error(("Internal error: %s (coming from infls spec %s)"):format(txt, dump(infl)))
end
local param = infl[1]
if param then
param = resolve_prop(param)
if type(param) ~= "string" and type(param) ~= "number" then
interr(("Parameter name %s must be a string or number"):format(dump(param)))
end
-- We handle defaults as well as validation ourselves.
local typ = resolve_prop(infl.type) or "string"
if typ ~= "genders" and typ ~= "boolean" and typ ~= "string" then
-- FIXME: Handle more types.
interr(('Unrecognized type %s; can only currently handle "genders", "boolean" and "string" (the default)'):format(
dump(typ)))
end
params[param] = {type = typ, required = resolve_prop(infl.required), template_default = resolve_prop(infl.template_default)}
if typ ~= "boolean" and type(param) == "string" then
params[param .. "2"] = {replaced_by = false, instead = ("use comma-separated |%s="):format(param)}
end
end
end
end
if infls then
augment_params_from_infls(infls)
end
if augment_params then
augment_params(headdata, params)
end
if pos_functions[indexing_poscat] then
local pos_infls = pos_functions[indexing_poscat].infls
if pos_infls then
augment_params_from_infls(pos_infls)
end
local pos_params = pos_functions[indexing_poscat].params
if pos_params then
for key, val in pairs(pos_params) do
params[key] = val
end
end
end
local args = require("Module:parameters").process(parargs, params)
local pagename = args.pagename or mw.loadData(headword_data_module).pagename
local sc = args.sc or lang:findBestScript(pagename)
headdata.pagename = pagename
headdata.process_props.args = args
headdata.sc = sc
headdata.id = args.id
headdata.sort = args.sort
-- No redundant script cat unless the user explicitly gave sc=
headdata.no_script_code_cat = not args.sc
headdata.var = args.var
local extra_term_mods = {}
if include_tr then
insert(extra_term_mods, "tr")
end
if include_ts then
insert(extra_term_mods, "ts")
end
if include_sc then
insert(extra_term_mods, "sc")
end
if not extra_term_mods[1] then
extra_term_mods = nil
end
local trs = args.tr and split_on_comma(args.tr) or {}
local num_trs = #trs
local tss = args.ts and split_on_comma(args.ts) or {}
local num_tss = #tss
local heads = args[head_param] and export.parse_term_with_modifiers {
val = args[head_param],
paramname = head_param,
splitchar = ",",
is_head = true,
include_mods = extra_term_mods,
} or {}
local num_heads = #heads
if num_heads > 0 and num_trs > 0 and num_heads ~= num_trs then
error(("%s head%s specified explicitly but %s translit%s; they must match; use '+' to stand for the default head (the pagename) or default automatic translit and '-' to stand for no translit"):format(
num_heads, num_heads > 1 and "s" or "", num_trs, num_trs > 1 and "s" or ""))
end
if num_heads > 0 and num_tss > 0 and num_heads ~= num_tss then
error(("%s head%s specified explicitly but %s transcription%s; they must match; use '+' to stand for the default head (the pagename) and '-' to stand for no transcription"):format(
num_heads, num_heads > 1 and "s" or "", num_tss, num_tss > 1 and "s" or ""))
end
if num_trs > 0 and num_tss > 0 and num_trs ~= num_tss then
error(("%s translit%s specified explicitly but %s transcription%s; they must match; use '+' to stand for default automatic translit and '-' to stand for no translit or transcription"):format(
num_trs, num_trs > 1 and "s" or "", num_tss, num_tss > 1 and "s" or ""))
end
-- Be careful here not to overwrite user_specified_heads if it's empty so we can later check user_specified_heads
-- to see if the user provided any heads.
local max_tr_ts = math.max(num_trs, num_tss)
if num_heads == 0 and max_tr_ts > 0 then
heads = {}
for i = 1, max_tr_ts do
heads[i] = {term = "+"}
end
end
if not heads[1] then
heads = {{term = "+"}}
end
for i, headobj in ipairs(heads) do
if headobj.tr and trs[i] then
if headobj.tr ~= trs[i] then
error(("Saw two different translits '%s' and '%s' for head #%s"):format(
headobj.tr, trs[i], i))
end
else
headobj.tr = headobj.tr or trs[i]
end
if headobj.tr == "+" then
headobj.tr = nil
end
if headobj.ts and tss[i] then
if headobj.ts ~= tss[i] then
error(("Saw two different transcriptions '%s' and '%s' for head #%s"):format(
headobj.ts, tss[i], i))
end
else
headobj.ts = headobj.ts or tss[i]
end
if headobj.ts == "-" then
headobj.ts = nil
end
if headobj.term == "+" then
headobj.term = args.nolink and pagename or nil
if headobj.term and namespace == "Reconstruction" then
headobj.term = "*" .. headobj.term
end
end
end
headdata.heads = heads
local function pagename_is_suffix()
if sc:getCode() == "Latn" then
-- shortcut Latin terms to avoid unnecessarily loading [[Module:affix]]
return pagename:find("^%-") and not pagename:find("%-$")
else
local affix_type, _, _, _ = require(affix_module).parse_term_for_affixes(pagename, lang, sc)
return affix_type == "suffix"
end
end
local clitic_label
if args.clitic then
clitic_label = require(yesno_module)(args.clitic, args.clitic)
end
if clitic_label == true then
clitic_label = "clitic"
end
if clitic_label then
headdata:insert_category("clitics")
headdata:insert_fixed_inflection(clitic_label)
elseif args.suffix or (
not args.nosuffix and pagename_is_suffix() and poscat ~= "suffixes" and poscat ~= "suffix forms"
) then
headdata.process_props.is_suffix = true
local function handle_suffix_pos(pos, is_first)
local form_type = pos:match("^(.*) forms$")
local actual_poscat
if form_type then
headdata:insert_category(("%s suffix forms"):format(form_type))
headdata:insert_fixed_inflection(form_type .. " suffix form")
else
local singular_pos = require(en_utilities_module).singularize(pos)
headdata:insert_category(("%s-forming suffixes"):format(singular_pos))
headdata:insert_fixed_inflection(singular_pos .. "-forming suffix")
end
local postype = require(headword_module).pos_lemma_or_nonlemma(pos)
if not postype then
error(("Unrecognized canonicalized part of speech '%s' in addlpos=, cannot determine whether lemma or non-lemma form"):format(
pos
))
end
actual_poscat = postype == "lemma" and "suffixes" or "suffix forms"
if is_first then
headdata.pos_category = actual_poscat
elseif headdata.pos_category ~= actual_poscat then
error(("Cannot mix suffixes and suffix forms using addlpos=; '%s' is a %s while overall POS '%s' is a %s; use separate POS headers for the two"):
format(pos, actual_poscat, poscat, headdata.pos_category))
end
end
handle_suffix_pos(poscat, true)
if args.addlpos then
for _, addlpos in ipairs(split(args.addlpos, "%s*,%s*")) do
addlpos = require(headword_module).canonicalize_pos(addlpos)
handle_suffix_pos(addlpos, false)
end
end
end
if args.cat then
for _, cat in ipairs(split_on_comma(args.cat)) do
headdata:insert_category(cat)
end
end
local function augment_headdata_from_infls(infls)
infls = resolve_prop(infls)
for _, infl in ipairs(infls) do
local function interr(txt)
error(("Internal error: %s (coming from infls spec %s)"):format(txt, dump(infl)))
end
local function process_labelobjs(labelobjs, originating_term, handle_labelobj)
if labelobjs == nil then
return
end
if type(labelobjs) ~= "string" and type(labelobjs) ~= "table" then
interr(("Wrong type '%s' for label object(s) %s, expected string or table"):format(
type(labelobjs), dump(labelobjs)
))
end
if type(labelobjs) == "string" or type(labelobjs) == "table" and not labelobjs[1] then
labelobjs = {labelobjs}
end
for _, labelobj in ipairs(labelobjs) do
local label, termobj
if type(labelobj) == "string" then
label = labelobj
termobj = originating_term
elseif type(labelobj) ~= "table" then
interr(("Wrong type '%s' for label object %s, expected string or table"):format(
type(labelobj), dump(labelobj)
))
label = labelobj.term
if type(label) ~= "string" then
interr(("Wrong type '%s' for label %s from label object %s, expected string"):format(
type(label), dump(label), dump(labelobj)
))
end
termobj = labelobj
end
handle_labelobj(label, termobj)
end
end
local param = infl[1]
if param then
local vals
-- Fetch the param and make sure it's a string or number.
param = resolve_prop(param)
if type(param) ~= "string" and type(param) ~= "number" then
interr(("Parameter name %s must be a string or number"):format(dump(param)))
end
-- Fetch the type and validate.
local typ = resolve_prop(infl.type)
if typ == nil then
typ = "string"
end
if typ ~= "genders" and typ ~= "boolean" and typ ~= "string" then
-- FIXME: Handle more types.
interr(('Unrecognized type %s; can only currently handle "genders", "boolean" and "string" (the default)'):format(
dump(typ)))
end
-- Fetch the value(s).
if typ == "genders" or typ == "boolean" then
vals = args[param]
elseif typ == "string" then
local parse_inflection_props = resolve_prop(infl.parse_inflection_props)
local include_mods = resolve_prop(infl.include_mods)
local no_augment_include_mods = resolve_prop(infl.no_augment_include_mods)
if include_mods ~= nil or no_augment_include_mods ~= nil then
if parse_inflection_props == nil then
parse_inflection_props = {}
else
parse_inflection_props = shallow_copy(parse_inflection_props)
end
if include_mods ~= nil then
parse_inflection_props.include_mods = include_mods
end
if no_augment_include_mods ~= nil then
parse_inflection_props.no_augment_include_mods = no_augment_include_mods
end
end
vals = headdata:parse_inflection(param, parse_inflection_props)
-- Convert an empty list to nil for consistent checking below.
if not vals[1] then
vals = nil
end
else
interr(("Unrecognized type '%s"):format(typ))
end
-- If value(s) nil, fetch the default.
if vals == nil and infl.default ~= nil then
local default = resolve_prop(infl.default)
if typ == "genders" then
vals = export.canonicalize_termobj_list(default, "spec", "default")
elseif typ == "boolean" then
vals = default
elseif typ == "string" then
vals = export.canonicalize_termobj_list(default, "term", "default")
else
interr(("Unrecognized type '%s"):format(typ))
end
end
-- Resolve "special" values (special signals a string values, such as requesting the default with "+").
if vals ~= nil and infl.resolve_special then
if typ ~= "string" then
interr(("Cannot specify resolve_special= for type %s"):format(dump(typ)))
end
local resolve_special_props = resolve_prop(infl.resolve_special_props, vals)
if infl.is_special ~= nil then
if resolve_special_props == nil then
resolve_special_props = {}
else
resolve_special_props = shallow_copy(resolve_special_props)
end
resolve_special_props.is_special = infl.is_special
end
vals = headdata:resolve_special(vals, infl.resolve_special, resolve_special_props)
end
-- Validate the value(s).
if vals ~= nil and infl.validate ~= nil then
if typ == "boolean" then
interr('Cannot specify validate= when type is "boolean"')
elseif type(infl.validate) == "function" then
infl.validate(headdata, vals)
elseif typ == "genders" then
headdata:validate_genders(vals, infl.validate)
elseif typ == "string" then
validate_items {
items = vals,
field = "term",
valid_items = infl.validate,
item_type = ("values in |%s="):format(param),
}
else
interr(("Unrecognized type '%s"):format(typ))
end
end
-- Run the process_after_parse handler, if it exists.
if vals ~= nil and infl.process_after_parse ~= nil then
local intentionally_nil
vals, intentionally_nil = infl.process_after_parse(headdata, vals)
if vals == nil and not intentionally_nil then
interr("If you return nil from process_after_parse, you must return a second non-nil return " ..
"value to indicate that the nil return value was intentional")
end
end
-- "Implement" the values, if non-falsy (i.e. we don't want to fire on boolean false or empty list).
-- If a fixed label is specified, insert it. Then, depending on the type, attach the values to a label
-- as an inflection, set the `genders` field, or do nothing if boolean (throwing an error if there was
-- no fixed label).
if vals == true or type(vals) == "table" and vals[1] then
if infl.fixed_label and infl.all_fixed_label then
interr("Cannot specify both fixed_label= and all_fixed_label=; specify one or the other")
end
local function check_fixed_label_references_val(label)
if type(label) == "table" and label[1] then
for _, lab in ipairs(label) do
if check_fixed_label_references_val(lab) then
return true
end
end
return false
end
if type(label) == "table" then
if not label.term then
interr(("Fixed label structure %s does not have a value for `.term`"):format(dump(label)))
end
label = label.term
end
if type(label) ~= "string" then
interr(("Wrong type for fixed label %s, should be string"):format(type(label)))
end
return not not label:find("{val}")
end
local fixed_label = infl.fixed_label
local all_fixed_label = infl.all_fixed_label
-- If the value being processed is boolean, there's only one value so treat a fixed_label as an
-- all_fixed_label and output only once; likewise if the caller specified a fixed_label without
-- {val} in it.
if fixed_label and (typ == "boolean" or type(fixed_label) ~= "function" and not
check_fixed_label_references_val(fixed_label)) then
all_fixed_label = fixed_label
fixed_label = nil
end
local inserted_fixed_label
if fixed_label then
if typ == "boolean" then
interr("Boolean fixed_label values should have been converted to all_fixed_label")
end
for _, valobj in ipairs(vals) do
local labelobjs = resolve_prop(fixed_label, valobj)
process_labelobjs(labelobjs, valobj, function(label, termobj)
if label:find("{val}") then
if typ ~= "string" then
interr(('Cannot specify {val} in fixed_label %s when type is "%s"'):format(dump(label), typ))
end
label = label:gsub("{val}", replacement_escape(valobj.term))
end
headdata:insert_fixed_inflection(label, {
originating_term = termobj
})
inserted_fixed_label = true
end)
end
elseif all_fixed_label then
local labelobjs = resolve_prop(all_fixed_label, vals)
process_labelobjs(labelobjs, nil, function(label, termobj)
if label:find("{vals}") then
if typ ~= "string" then
interr(('Cannot specify {vals} in all_fixed_label %s when type is "%s"'):format(dump(label), typ))
end
local formatted_labels = {}
for _, valobj in ipairs(vals) do
insert(formatted_labels, add_decorations(valobj.term, valobj, lang))
end
label = label:gsub("{vals}", replacement_escape(serial_comma_join(formatted_labels)))
end
headdata:insert_fixed_inflection(label, termobj)
inserted_fixed_label = true
end)
end
local inserted_vals
if infl.label ~= nil then
if typ ~= "string" then
interr(("label=%s can only be specified for type 'string', not '%s'"):format(
dump(infl.label), typ
))
end
local label = resolve_prop(infl.label, vals)
if label ~= nil then
local insert_inflection_props = resolve_prop(infl.insert_inflection_props, vals)
local no_auto_cats = resolve_prop(infl.no_auto_cats, vals)
if no_auto_cats ~= nil then
if insert_inflection_props == nil then
insert_inflection_props = {}
else
insert_inflection_props = shallow_copy(insert_inflection_props)
end
insert_inflection_props.no_auto_cats = infl.no_auto_cats
end
local insert_spec = headdata:insert_inflection(vals, label, insert_inflection_props)
headdata.process_props.insert_specs[param] = insert_spec
inserted_vals = true
end
end
if typ == "genders" then
headdata.genders = vals
end
local inserted_cat
if infl.cat then
local allcats = {}
for _, valobj in ipairs(vals) do
local cats = resolve_prop(infl.cat, valobj)
if type(cats) == "string" then
cats = {cats}
end
if cats ~= nil then
for _, cat in ipairs(cats) do
if cat:find("{val}") then
cat = cat:gsub("{val}", replacement_escape(valobj.term))
end
insert_if_not(allcats, cat)
end
end
end
for _, cat in ipairs(allcats) do
headdata:insert_category(cat)
inserted_cat = true
end
end
if typ == "boolean" then
if not inserted_fixed_label and not inserted_cat then
interr(("User set boolean setting for %s= but no fixed label added and no category " ..
"inserted; if you took action in process_after_parse(), make sure to return " ..
"`nil, true`"):format(param))
end
elseif typ == "string" then
if not inserted_vals and not inserted_fixed_label then
interr(("User set value(s) %s for %s= but no inflection inserted and no fixed label " ..
"added; if you took action in process_after_parse(), make sure to return " ..
"`nil, true`"):format(dump(vals), param))
end
end
end
else -- no param specified
if infl.label or infl.all_fixed_label then
interr("Cannot have label= or all_fixed_label= without specifying a param")
end
if infl.fixed_label then
local labelobjs = resolve_prop(infl.fixed_label)
process_labelobjs(labelobjs, nil, function(label, termobj)
if label:find("{val}") then
interr("Cannot specify {val} in a fixed_label= value without specifying a param")
end
headdata:insert_fixed_inflection(label, {
originating_term = termobj
})
end)
end
if infl.cat then
local cats = resolve_prop(infl.cat)
if type(cats) == "string" then
cats = {cats}
end
if cats ~= nil then
for _, cat in ipairs(cats) do
if cat:find("{val}") then
interr("Cannot specify {val} in a cat= value without specifying a param")
end
headdata:insert_category(cat)
end
end
end
end
end
end
if infls then
augment_headdata_from_infls(infls)
end
if augment_headdata then
augment_headdata(headdata, args)
end
if pos_functions[indexing_poscat] then
local pos_infls = pos_functions[indexing_poscat].infls
if pos_infls then
augment_headdata_from_infls(pos_infls)
end
local func = pos_functions[indexing_poscat].func
if func then
func(headdata, args)
end
end
setmetatable(headdata, nil)
if args.json then
return require("Module:JSON").toJSON(headdata)
end
headdata.process_props = nil
return require(headword_module).full_headword(headdata)
end
return export
ou0y7dxffzgvhrvsgvx5tbty4giij9y
Padron:orthography
10
33948
178021
165462
2026-09-21T16:34:05Z
Yivan000
4078
Inilipat ni Yivan000 ang pahinang [[Padron:ortograpiya]] sa [[Padron:orthography]]
165462
wikitext
text/x-wiki
<includeonly><span class="orth-brac">⟨</span><span class="orth-content">{{{1|{{error|Dapat magbigay ng parametro sa padron ng ortograpiya}}}}}</span><span class="orth-brac">⟩</span></includeonly><noinclude>{{dokumentasyon ng padron}}</noinclude>
rsbfu4znoryrut6sb0fr6jkjgu8qglk
Padron:orthography/documentation
10
33949
178023
165463
2026-09-21T16:34:28Z
Yivan000
4078
Inilipat ni Yivan000 ang pahinang [[Padron:ortograpiya/doc]] sa [[Padron:orthography/documentation]] nang walang iniwang redirect
165463
wikitext
text/x-wiki
{{documentation subpage}}
{{shortcut|Template:orth|Template:angbr}}
Ginagamit upang markahan ang teksto sa mga angle panaklong, na ginagamit upang markahan ang mga grapema, i.e. mga letrang ginagamit sa ortograpiya, upang makilala ang mga ito mula sa malaponema o ponetika na notasyon sa International Phonetic Alphabet, o para simpleng gawing malinaw na ang teksto ay tumatalakay sa mga partikular na grapemang.
Halimbawa, habang ang {{IPAchar|/a/}} (ponemiko) ay kumakatawan sa [[ponema]] ''a'' at {{IPAchar|[a]}} (ponetiko) ay kumakatawan sa [[phone]] ''a'', {{orth|a}} ay kumakatawan sa [[grapema]] ''a'', ibig sabihin, alinmang tunog ang, o ang mga tunog ay kinakatawan ng ''a' o'.
Kailangan lang ng isang parametro, na kung saan ay ang teksto na ipapakita sa loob ng mga anggulong panaklong.
==TemplateData==
{{TemplateData header}}
<templatedata>
{
"params": {
"1": {
"label": "text",
"description": "Tekstong ipapakita sa loob ng mga anggulong panaklong",
"example": "a",
"type": "string",
"required": true
}
},
"description": "Gamitin ang padron na ito para markahan ang mga grapema, hal. mga titik o kumbinasyon nito sa isang ortograpiya, sa mga anggulong panaklong."
}
</templatedata>
<includeonly>
[[Category:Mga padron ng pormat ng teksto]]
</includeonly>
4uyb9h6pj0tnjlw48s9mu0cqnsi9g4i
Kategorya:Afrikāns na pangatnig
14
38853
178016
2026-09-21T16:28:27Z
Yivan000
4078
Nilikha ang pahina na may '{{auto cat}}'
178016
wikitext
text/x-wiki
{{auto cat}}
eomzlm5v4j7ond1phrju7cnue91g5qx
Padron:RQ:Man'yōshū
10
38854
178018
2026-09-21T16:30:03Z
Yivan000
4078
Inilipat ni Yivan000 ang pahinang [[Padron:RQ:Man'yōshū]] sa [[Padron:RQ:ojp:Man'yōshū]]
178018
wikitext
text/x-wiki
#REDIRECT [[Padron:RQ:ojp:Man'yōshū]]
571av7xbamy6flcc37jisogo0ebc3bh
Padron:ortograpiya
10
38855
178022
2026-09-21T16:34:05Z
Yivan000
4078
Inilipat ni Yivan000 ang pahinang [[Padron:ortograpiya]] sa [[Padron:orthography]]
178022
wikitext
text/x-wiki
#REDIRECT [[Padron:orthography]]
i8xkr4zzus9m1dv7yjb45ehlk0diwg0
Padron:wgping
10
38856
178025
2026-09-21T16:38:19Z
Yivan000
4078
Inilipat ni Yivan000 ang pahinang [[Padron:wgping]] sa [[Padron:workgroup ping]]
178025
wikitext
text/x-wiki
#REDIRECT [[Padron:workgroup ping]]
2qzdns82ss7zyl24iib65s75fffppsy
Padron:Policy
10
38857
178029
2026-09-21T16:58:33Z
Yivan000
4078
Nilipat ni Yivan000 ang pahinang [[Padron:Policy]] sa [[Padron:policy]] mula sa redirect
178029
wikitext
text/x-wiki
#REDIRECT [[Padron:policy]]
7h0nv17fix74mox2qo4s98ecg4lh4sg
Pinagbuhatan
0
38858
178032
2026-09-22T04:45:08Z
Yivan000
4078
Inilipat ni Yivan000 ang pahinang [[Pinagbuhatan]] sa [[pinagbuhatan]]
178032
wikitext
text/x-wiki
#REDIRECT [[pinagbuhatan]]
5rabgkdfqw8d0lc0d5h544ywvuf0doz
178033
178032
2026-09-22T04:46:25Z
Yivan000
4078
Removed redirect to [[pinagbuhatan]]
178033
wikitext
text/x-wiki
=={{=tl=}}==
===Pagbigkas===
{{tl-pr}}
===Pangngalang pantangi===
{{tl-proper noun|b=+}}
# {{place|tl|barangay|city/Pasig|r/Metro Manila|c/Philippines}}
8sg5dmsoc4yzec3u5fycahuva86q5qm