Module:form of/templates: Difference between revisions
No edit summary |
No edit summary |
||
| (One intermediate revision by the same user not shown) | |||
| Line 1: | Line 1: | ||
local export = {} | |||
local form_of_module = "Module:form of" | |||
local functions_module = "Module:fun" | |||
local headword_data_module = "Module:headword/data" | |||
local languages_module = "Module:languages" | |||
local load_module = "Module:load" | |||
local parameters_module = "Module:parameters" | |||
local parameter_utilities_module = "Module:parameter utilities" | |||
local parse_interface_module = "Module:parse interface" | |||
local string_utilities_module = "Module:string utilities" | |||
local table_module = "Module:table" | |||
local utilities_module = "Module:utilities" | |||
local insert = table.insert | local insert = table.insert | ||
local | local ipairs = ipairs | ||
local | local pairs = pairs | ||
local | local require = require | ||
local | |||
local | -- FIXME: Finish [[Module:format utilities]]. | ||
local | -- local allowed_conj_set = require(format_utilities_module).allowed_conj_set_for_join_segments | ||
local | local allowed_conj_set = {["and"] = true, ["or"] = true, ["and/or"] = true} | ||
--[==[ | |||
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 format_categories(...) | |||
format_categories = require(utilities_module).format_categories | |||
return format_categories(...) | |||
end | |||
local function format_form_of(...) | |||
format_form_of = require(form_of_module).format_form_of | |||
return format_form_of(...) | |||
end | |||
local function get_lang(...) | |||
get_lang = require(languages_module).getByCode | |||
return get_lang(...) | |||
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 load_data(...) | |||
load_data = require(load_module).load_data | |||
return load_data(...) | |||
end | |||
local function parse_inline_modifiers(...) | |||
parse_inline_modifiers = require(parse_interface_module).parse_inline_modifiers | |||
return parse_inline_modifiers(...) | |||
end | |||
local function pattern_escape(...) | |||
pattern_escape = require(string_utilities_module).pattern_escape | |||
return pattern_escape(...) | |||
end | |||
local | local function process_params(...) | ||
process_params = require(parameters_module).process | |||
return process_params(...) | |||
end | |||
local function safe_load_data(...) | |||
safe_load_data = require(load_module).safe_load_data | |||
return safe_load_data(...) | |||
end | |||
local function split(...) | |||
split = require(string_utilities_module).split | |||
return split(...) | |||
end | |||
local function split_tag_set(...) | |||
split_tag_set = require(form_of_module).split_tag_set | |||
return split_tag_set(...) | |||
end | |||
local function tagged_inflections(...) | |||
tagged_inflections = require(form_of_module).tagged_inflections | |||
return tagged_inflections(...) | |||
end | |||
local function trim(...) | |||
trim = require(string_utilities_module).trim | |||
return trim(...) | |||
end | |||
local function ucfirst(...) | |||
ucfirst = require(string_utilities_module).ucfirst | |||
return ucfirst(...) | |||
end | |||
--[==[ | |||
Loaders for objects, which load data (or some other object) into some variable, which can then be accessed as "foo or get_foo()", where the function get_foo sets the object to "foo" and then returns it. This ensures they are only loaded when needed, and avoids the need to check for the existence of the object each time, since once "foo" has been set, "get_foo" will not be called again.]==] | |||
local force_cat | |||
local function get_force_cat() | |||
force_cat, get_force_cat = require(form_of_module).force_cat, nil | |||
return force_cat | |||
end | |||
local m_form_of_pos | |||
local function get_m_form_of_pos() | |||
m_form_of_pos, get_m_form_of_pos = load_data(headword_data_module).pos_aliases, nil | |||
return m_form_of_pos | |||
end | |||
local module_prefix | |||
local function get_module_prefix() | |||
module_prefix, get_module_prefix = require(form_of_module).form_of_lang_data_module_prefix, nil | |||
return module_prefix | |||
end | |||
--[==[ intro: | --[==[ intro: | ||
| Line 15: | Line 135: | ||
[[Module:form of]], which contains the underlying implementing code and is meant to be called from other modules. | [[Module:form of]], which contains the underlying implementing code and is meant to be called from other modules. | ||
]==] | ]==] | ||
| Line 28: | Line 140: | ||
return { | return { | ||
-- Named params not controlling link display | -- Named params not controlling link display | ||
["cat"] = {list = true}, | ["cat"] = {list = true, sublist = "comma without whitespace", flatten = true}, | ||
["notext"] = {type = "boolean"}, | ["notext"] = {type = "boolean"}, | ||
["sort"] = | ["sort"] = true, | ||
["enclitic"] = | ["enclitic"] = true, | ||
-- FIXME! The following should only be available when withcap=1 in invocation args. Before doing that, need to | -- FIXME! The following should only be available when withcap=1 in invocation args or when withencap=1 and the | ||
-- language is "en". Before doing that, need to remove all uses of nocap= in other circumstances. | |||
["nocap"] = {type = "boolean"}, | ["nocap"] = {type = "boolean"}, | ||
["addl"] = true, -- additional text to display at the end, before the closing </span> | |||
["pagename"] = true, -- for testing, etc. | |||
[" | |||
["pagename"] = | |||
} | } | ||
end | end | ||
-- Split TAGSPECS (inflection tag specifications) on SPLIT_REGEX, which | -- Split TAGSPECS (inflection tag specifications) on SPLIT_REGEX, which | ||
| Line 132: | Line 160: | ||
local inflection_tags = {} | local inflection_tags = {} | ||
for _, tagspec in ipairs(tagspecs) do | for _, tagspec in ipairs(tagspecs) do | ||
for tag in | for tag in gsplit(tagspec, split_regex) do | ||
insert(inflection_tags, tag) | insert(inflection_tags, tag) | ||
end | end | ||
| Line 140: | Line 168: | ||
local function parse_terms_with_inline_modifiers(paramname, val, param_mods, lang) | |||
local function parse_terms_with_inline_modifiers(paramname, val, lang) | |||
local function generate_obj(term) | local function generate_obj(term) | ||
return {lang = lang, term = term} | return {lang = lang, term = decode_entities(term)} | ||
end | end | ||
return parse_inline_modifiers(val, { | |||
paramname = paramname, | |||
param_mods = param_mods, | |||
generate_obj = generate_obj, | |||
splitchar = ",", | |||
outer_container = {}, | |||
}) | |||
end | end | ||
-- Modify PARAMS in-place by adding parameters that control the link to the | -- Modify PARAMS in-place by adding parameters that control the link to the | ||
| Line 215: | Line 188: | ||
-- will be the gloss, unless NO_NUMBERED_GLOSS is given. | -- will be the gloss, unless NO_NUMBERED_GLOSS is given. | ||
local function add_link_params(parent_args, params, term_param, no_numbered_gloss) | local function add_link_params(parent_args, params, term_param, no_numbered_gloss) | ||
params[term_param + 1] = {alias_of = "alt"} | params[term_param + 1] = {alias_of = "alt"} | ||
if not no_numbered_gloss then | if not no_numbered_gloss then | ||
| Line 230: | Line 193: | ||
end | end | ||
-- Numbered params controlling link display | -- Numbered params controlling link display | ||
params[term_param] = | params[term_param] = true | ||
end | |||
-- Need to do what [[Module:parameters]] does to string arguments from parent_args as we're running this | |||
-- before calling [[Module:parameters]] on parent_args. | |||
local function ine(arg) | |||
if not arg then | |||
return nil | |||
end | |||
arg = trim(arg) | |||
return arg ~= "" and arg or nil | |||
end | |||
-- | local function add_base_lemma_params(parent_args, iargs, params, compat) | ||
-- Check the language-specific data for additional base lemma params. But if there's no language-specific data, | |||
local | -- attempt any parent varieties as well (i.e. superordinate varieties). | ||
params[param] = | local lang = get_lang(ine(parent_args[compat and "lang" or 1]) or ine(iargs.lang) or "und", nil, true) | ||
while lang do | |||
local langdata = safe_load_data((module_prefix or get_module_prefix()) .. lang:getCode()) | |||
if langdata then | |||
local base_lemma_params = langdata.base_lemma_params | |||
if base_lemma_params then | |||
for _, param in ipairs(base_lemma_params) do | |||
params[param.param] = true | |||
end | |||
return base_lemma_params | |||
end | |||
end | |||
lang = lang:getParent() | |||
end | end | ||
end | end | ||
local function add_link_and_base_lemma_params(iargs, parent_args, params, term_param, compat, no_numbered_gloss) | |||
local base_lemma_params | |||
if not iargs.nolink and not iargs.linktext then | |||
add_link_params(parent_args, params, term_param, no_numbered_gloss) | |||
base_lemma_params = add_base_lemma_params(parent_args, iargs, params, compat) | |||
end | |||
return base_lemma_params | |||
end | |||
local function | local function handle_withdot_withcap(iargs, params) | ||
local ignored_tracked_params = {} | |||
if iargs.withdot then | |||
params.dot = true | |||
params.nodot = {type = "boolean"} | |||
end | end | ||
if iargs.withcap and iargs.withencap then | |||
error("Internal error: Can specify only one of withcap= and withencap=") | |||
end | end | ||
if not iargs.withcap then | |||
params.cap = {type = "boolean"} | |||
ignored_tracked_params.nocap = iargs.withencap and "non-english" or "always" | |||
end | end | ||
return ignored_tracked_params | |||
end | end | ||
--[=[ | --[=[ | ||
Construct and return the full definition line for a form-of-type template invocation. `data` is an object with the | |||
argument specifying the | following fields: | ||
of args[1]), | * `template`: Approximate template name, for debug tracking; | ||
* `iargs`: processed invocation arguments; | |||
* `parent_args`: raw parent args from `frame:getParent().args`; | |||
* `params`: partially constructed params structure of the sort passed to `process()` in [[Module:parameters]], but | |||
without any link params; | |||
* `ignored_tracked_params`: params that are ignored but should be tracked, to be eventually removed; | |||
* `term_param`: the parent argument specifying the main entry; | |||
* `compat`: true if the language code is found in args.lang instead of args[1]; | |||
* `base_lemma_params`: if non-nil, a list of base lemma param objects of the sort stored in the language-specific data; | |||
* `do_form_of`: a function of one argument, `lemma_data`, that returns the actual definition-line text and any | |||
language-specific categories. See below. | |||
This function does several things: | |||
# If link parameters are called for (neither `iargs.nolink` nor `iargs.linktext` are given), augment the `params` | |||
structure with separate link parameters. | |||
# Modify the parent args as appropriate if invocation arguments def= or ignore= are given. | |||
# Parse the parent args, both for separate parameter properties and inline modifiers on the term parameter (which may | |||
consist of multiple comma-separated terms). | |||
# Compute categories to add to the page, including language-specific categories and any categories requested by the | |||
invocation or parent args. | |||
# Parse enclitic and extra base lemma parameters. | |||
# Construct the actual text using `do_form_of`. | |||
# Add a terminating period/dot as appropriate, along with the formatted categories. | |||
`do_form_of` takes one argument, `lemma_data`, which looks like this: | |||
{ | { | ||
lang = LANG, | lang = LANG, | ||
args = {ARG = VALUE, ARG = VALUE, ...}, | |||
lemmas = {LEMMA_OBJ, LEMMA_OBJ, ...}, | lemmas = {LEMMA_OBJ, LEMMA_OBJ, ...}, | ||
enclitics = {ENCLITIC_OBJ, ENCLITIC_OBJ, ...}, | enclitics = {ENCLITIC_OBJ, ENCLITIC_OBJ, ...}, | ||
base_lemmas = {BASE_LEMMA_OBJ, BASE_LEMMA_OBJ, ...}, | base_lemmas = {BASE_LEMMA_OBJ, BASE_LEMMA_OBJ, ...}, | ||
categories = {"CATEGORY", "CATEGORY", ...}, | categories = {"CATEGORY", "CATEGORY", ...}, | ||
posttext = "POSTTEXT" or nil, | |||
} | } | ||
| Line 298: | Line 296: | ||
* LANG is the language code; | * LANG is the language code; | ||
* ARGS is the parsed arguments, based on what the user specified; | |||
* LEMMAS is a sequence of objects specifying the main entries/lemmas, as passed to full_link in [[Module:links]]; | * LEMMAS is a sequence of objects specifying the main entries/lemmas, as passed to full_link in [[Module:links]]; | ||
however, if the invocation argument linktext= is given, it will be a string consisting of that text, and if the | however, if the invocation argument linktext= is given, it will be a string consisting of that text, and if the | ||
| Line 307: | Line 306: | ||
base lemma parameter (i.e. the relationship between the intermediate and base lemmas) and LEMMA_OBJ is of the same | base lemma parameter (i.e. the relationship between the intermediate and base lemmas) and LEMMA_OBJ is of the same | ||
format of ENCLITIC_OBJ, i.e. an object suitable to be passed to full_link in [[Module:links]]; PARAM_OBJ is of the | format of ENCLITIC_OBJ, i.e. an object suitable to be passed to full_link in [[Module:links]]; PARAM_OBJ is of the | ||
format { param = "PARAM", tags = {"TAG", "TAG", ...} } where PARAM is the name of the parameter to {{inflection of}} | format { param = "PARAM", tags = {"TAG", "TAG", ...} } where PARAM is the name of the parameter to | ||
{{inflection of}} etc. that holds the base lemma(s) of the specified relationship and the tags describe the | |||
relationship, such as {"comd"} or {"past", "part"}; | |||
* CATEGORIES is the categories to add the page to (consisting of any categories specified in the invocation or | * CATEGORIES is the categories to add the page to (consisting of any categories specified in the invocation or | ||
parent args and any tracking categories, but not any additional lang-specific categories that may be added by | parent args and any tracking categories, but not any additional lang-specific categories that may be added by | ||
{{inflection of}} or similar templates). | {{inflection of}} or similar templates); | ||
* POSTTEXT is text to display at the end of the form-of text, before the final </span> (or at the end of the first | |||
line, before the colon, in a multiline {{infl of}} call). | |||
`do_form_of` should return two arguments: | |||
(1) The actual definition-line text, marked up appropriately with <span>...</span> but without any terminating | |||
period/dot. | |||
(2) Any extra categories to add the page to (other than those that can be derived from parameters specified to the | |||
invocation or parent arguments, which will automatically be added to the page). | |||
]=] | ]=] | ||
local function | local function construct_form_of_text(data) | ||
local template, iargs, parent_args, params, no_numbered_gloss, do_form_of = | |||
data.template, data.iargs, data.parent_args, data.params, data.no_numbered_gloss, data.do_form_of | |||
local term_param = iargs.term_param | |||
local compat = iargs.lang or parent_args.lang | |||
term_param = term_param or compat and 1 or 2 | |||
-- Numbered params | |||
params[compat and "lang" or 1] = { | |||
required = not iargs.lang, | |||
type = "language", | |||
default = iargs.lang or "und" | |||
} | |||
local base_lemma_params = add_link_and_base_lemma_params(iargs, parent_args, params, term_param, compat, | |||
no_numbered_gloss) | |||
local ignored_tracked_params = handle_withdot_withcap(iargs, params) | |||
--[=[ | |||
Process parent arguments. This is similar to the following: | |||
require("Module:parameters").process(parent_args, params) | |||
but in addition it does the following: | |||
(1) Supplies default values for unspecified parent arguments as specified in | |||
DEFAULTS, which consist of specs of the form "ARG=VALUE". These are | |||
added to the parent arguments prior to processing, so boolean and number | |||
parameters will process the value appropriately. | |||
(2) Removes parent arguments specified in IGNORESPECS, which consist either | |||
of bare argument names to remove, or list-argument names to remove of the | |||
form "ARG:list". | |||
(3) Tracks the use of any parent arguments specified in TRACKED_PARAMS, which | |||
is a set-type table where the keys are arguments as they exist after | |||
processing (hence numeric arguments should be numbers, not strings) | |||
and the values should be boolean true. | |||
]=]-- | |||
local defaults = iargs.def | |||
local ignorespecs = iargs.ignore | |||
if defaults[1] or ignorespecs[1] then | |||
local new_parent_args = {} | |||
for _, default in ipairs(defaults) do | |||
local defparam, defval = default:match("^(.-)=(.*)$") | |||
if not defparam then | |||
error("Bad default spec " .. default) | |||
end | |||
new_parent_args[defparam] = defval | |||
end | |||
local params_to_ignore = {} | |||
local numbered_list_params_to_ignore = {} | |||
local named_list_params_to_ignore = {} | |||
for _, ignorespec in ipairs(ignorespecs) do | |||
for ignore in gsplit(ignorespec, ",") do | |||
local param = ignore:match("^(.*):list$") | |||
if param then | |||
if param:match("^%d+$") then | |||
insert(numbered_list_params_to_ignore, tonumber(param)) | |||
else | |||
insert(named_list_params_to_ignore, "^" .. pattern_escape(param) .. "%d*$") | |||
end | |||
else | |||
if ignore:match("^%d+$") then | |||
ignore = tonumber(ignore) | |||
end | |||
params_to_ignore[ignore] = true | |||
end | |||
end | |||
end | |||
for k, v in pairs(parent_args) do | |||
if not params_to_ignore[k] then | |||
local ignore_me = false | |||
if type(k) == "number" then | |||
for _, lparam in ipairs(numbered_list_params_to_ignore) do | |||
if k >= lparam then | |||
ignore_me = true | |||
break | |||
end | |||
end | |||
else | |||
for _, lparam in ipairs(named_list_params_to_ignore) do | |||
if k:match(lparam) then | |||
ignore_me = true | |||
break | |||
end | |||
end | |||
end | |||
if not ignore_me then | |||
new_parent_args[k] = v | |||
end | |||
end | |||
end | |||
parent_args = new_parent_args | |||
end | |||
local m_param_utils, param_mods | |||
local function init_param_mods() | |||
if not m_param_utils then | |||
m_param_utils = require(parameter_utilities_module) | |||
param_mods = m_param_utils.construct_param_mods { | |||
{group = {"link", "q", "l", "ref"}}, | |||
{param = "conj", set = allowed_conj_set, overall = true}, | |||
} | |||
end | |||
end | |||
local terms, args | |||
if iargs.nolink or iargs.linktext then | |||
args = process_params(parent_args, params) | |||
else | |||
init_param_mods() | |||
terms, args = m_param_utils.parse_term_with_inline_modifiers_and_separate_params { | |||
params = params, | |||
param_mods = param_mods, | |||
raw_args = parent_args, | |||
termarg = term_param, | |||
track_module = "form-of" .. (template and "/" .. template or ""), | |||
lang = compat and "lang" or 1, | |||
sc = "sc", | |||
-- Don't do this, doesn't seem to make sense. | |||
-- parse_lang_prefix = true, | |||
make_separate_g_into_list = true, | |||
process_args_before_parsing = function(args) | |||
-- For compatibility with the previous code, we accept a comma-separated list of genders in each of g=, | |||
-- g2=, etc. in addition to separate genders in g=/g2=/etc. | |||
if args.g and args.g[1] then | |||
local genders = {} | |||
for _, g in ipairs(args.g) do | |||
extend(genders, split(g, ",")) | |||
end | |||
args.g = genders | |||
end | |||
end, | |||
splitchar = ",", | |||
subitem_param_handling = "last", | |||
} | |||
end | |||
local lang = args[compat and "lang" or 1] | local lang = args[compat and "lang" or 1] | ||
| Line 323: | Line 467: | ||
local categories = {} | local categories = {} | ||
if not args | if not args.nocat then | ||
for _, cat in ipairs(iargs | for _, cat in ipairs(iargs.cat) do | ||
insert(categories, lang:getFullName() .. " " .. cat) | insert(categories, lang:getFullName() .. " " .. cat) | ||
end | end | ||
end | end | ||
for _, cat in ipairs(args | for _, cat in ipairs(args.cat) do | ||
insert(categories, lang:getFullName() .. " " .. cat) | insert(categories, lang:getFullName() .. " " .. cat) | ||
end | end | ||
| Line 335: | Line 479: | ||
local function add_term_tracking_categories(term) | local function add_term_tracking_categories(term) | ||
-- add tracking category if term is same as page title | |||
if term and mw.title.getCurrentTitle().text == (lang:makeEntryName(term)) then | |||
insert(categories, "Forms linking to themselves") | |||
end | |||
-- maybe add tracking category if primary entry doesn't exist (this is an | -- maybe add tracking category if primary entry doesn't exist (this is an | ||
-- expensive call so we don't do it by default) | -- expensive call so we don't do it by default) | ||
if iargs | if iargs.noprimaryentrycat and term and mw.title.getCurrentTitle().nsText == "" | ||
and not mw.title.new(term) | and not mw.title.new(term):getContent() then | ||
insert(categories, lang:getFullName() .. " " .. iargs | insert(categories, lang:getFullName() .. " " .. iargs.noprimaryentrycat) | ||
end | end | ||
end | end | ||
| Line 345: | Line 493: | ||
local lemmas | local lemmas | ||
if iargs | if iargs.nolink then | ||
lemmas = nil | lemmas = nil | ||
elseif iargs | elseif iargs.linktext then | ||
lemmas = iargs | lemmas = iargs.linktext | ||
else | else | ||
if not terms.terms[1] then | |||
if not | |||
if mw.title.getCurrentTitle().nsText == "Template" then | if mw.title.getCurrentTitle().nsText == "Template" then | ||
term = "term" | terms.terms[1] = { | ||
lang = lang, | |||
term = "term" | |||
} | |||
else | else | ||
error("No linked-to term specified | error("No linked-to term specified") | ||
end | end | ||
end | end | ||
for _, termobj in ipairs(terms.terms) do | |||
if termobj.term then | |||
add_term_tracking_categories(termobj.term) | |||
add_term_tracking_categories( | |||
end | end | ||
-- NOTE: Formerly, template arg sc= overrode inline modifier <sc:...>, which seems backwards, so I've | |||
-- changed it. Hopefully nothing depended on the old behavior. | |||
end | end | ||
lemmas = terms.terms | |||
end | end | ||
local enclitics | local enclitics, enclitic_conj | ||
if args.enclitic then | if args.enclitic then | ||
init_param_mods() | |||
local enclitics_obj = parse_terms_with_inline_modifiers("enclitic", args.enclitic, param_mods, lang) | |||
enclitics = enclitics_obj.terms | |||
enclitic_conj = enclitics_obj.conj | |||
end | end | ||
local base_lemmas = {} | local base_lemmas = {} | ||
| Line 404: | Line 532: | ||
local param = base_lemma_param_obj.param | local param = base_lemma_param_obj.param | ||
if args[param] then | if args[param] then | ||
init_param_mods() | |||
local base_lemmas_obj = parse_terms_with_inline_modifiers(param, args[param], param_mods, lang) | |||
insert(base_lemmas, { | insert(base_lemmas, { | ||
paramobj = base_lemma_param_obj, | paramobj = base_lemma_param_obj, | ||
lemmas = | lemmas = base_lemmas_obj.terms, | ||
conj = base_lemmas_obj.conj, | |||
}) | }) | ||
end | end | ||
| Line 412: | Line 543: | ||
end | end | ||
local posttext = iargs.posttext | |||
local addl = args.addl | |||
if addl then | |||
posttext = posttext or "" | |||
if addl:find("^[;:]") then | |||
posttext = posttext .. addl | |||
elseif addl:find("^_") then | |||
posttext = posttext .. " " .. addl:sub(2) | |||
else | |||
posttext = posttext .. ", " .. addl | |||
end | |||
end | |||
local lemma_data = { | |||
lang = lang, | lang = lang, | ||
args = args, | |||
lemmas = lemmas, | lemmas = lemmas, | ||
conj = terms and terms.conj or iargs.conj, | |||
enclitics = enclitics, | enclitics = enclitics, | ||
enclitic_conj = enclitic_conj, | |||
base_lemmas = base_lemmas, | base_lemmas = base_lemmas, | ||
categories = categories, | categories = categories, | ||
posttext = posttext, | |||
} | } | ||
local form_of_text, lang_cats = do_form_of(lemma_data) | local form_of_text, lang_cats = do_form_of(lemma_data) | ||
extend(lemma_data.categories, lang_cats) | |||
local text = form_of_text .. ( | local text = form_of_text .. ( | ||
args | args.nodot and "" or args.dot or iargs.withdot and "." or "" | ||
) | ) | ||
if #lemma_data.categories == 0 then | if #lemma_data.categories == 0 then | ||
return text | return text | ||
end | end | ||
return text . | return text .. format_categories(lemma_data.categories, lemma_data.lang, args.sort, | ||
-- If lemma_is_sort_key is given, supply the first lemma term as the sort base if possible. If sort= is given, | -- If lemma_is_sort_key is given, supply the first lemma term as the sort base if possible. If sort= is given, | ||
-- it will override the base; otherwise, the base will be converted appropriately to a sort key using the | -- it will override the base; otherwise, the base will be converted appropriately to a sort key using the | ||
| Line 455: | Line 582: | ||
iargs.lemma_is_sort_key and type(lemma_data.lemmas) == "table" and lemma_data.lemmas[1].term, | iargs.lemma_is_sort_key and type(lemma_data.lemmas) == "table" and lemma_data.lemmas[1].term, | ||
-- Supply the first lemma's script for sort key computation. | -- Supply the first lemma's script for sort key computation. | ||
force_cat or get_force_cat(), type(lemma_data.lemmas) == "table" and lemma_data.lemmas[1].sc) | |||
end | end | ||
| Line 463: | Line 590: | ||
return { | return { | ||
["term_param"] = {type = "number"}, | ["term_param"] = {type = "number"}, | ||
["lang"] = | ["lang"] = true, -- To be used as the default code in params. | ||
["sc"] = {type = "script"}, | ["sc"] = {type = "script"}, | ||
["cat"] = {list = true}, | ["cat"] = {list = true, sublist = "comma without whitespace", flatten = true}, | ||
["ignore"] = {list = true}, | ["ignore"] = {list = true}, | ||
["def"] = {list = true}, | ["def"] = {list = true}, | ||
["conj"] = {set = allowed_conj_set, default = "and"}, | |||
["withcap"] = {type = "boolean"}, | ["withcap"] = {type = "boolean"}, | ||
["withencap"] = {type = "boolean"}, | |||
["withdot"] = {type = "boolean"}, | ["withdot"] = {type = "boolean"}, | ||
["nolink"] = {type = "boolean"}, | ["nolink"] = {type = "boolean"}, | ||
["linktext"] = | ["linktext"] = true, | ||
["posttext"] = | ["posttext"] = true, | ||
["noprimaryentrycat"] = | ["noprimaryentrycat"] = true, | ||
["lemma_is_sort_key"] = | ["lemma_is_sort_key"] = true, | ||
} | } | ||
end | |||
local function should_ucfirst_text(args, iargs, lang) | |||
return args.cap or (iargs.withcap or iargs.withencap and lang:getCode() == "en") and not args.nocap | |||
end | end | ||
| Line 499: | Line 633: | ||
: Categories to place the page into. The language name will automatically be prepended. Note that there is also a | : Categories to place the page into. The language name will automatically be prepended. Note that there is also a | ||
template param {{para|cat}} to specify categories at the template level. Use of {{para|nocat}} disables categorization | template param {{para|cat}} to specify categories at the template level. Use of {{para|nocat}} disables categorization | ||
of categories specified using invocation param {{para|cat}}, but not using template param {{para|cat}}. | of categories specified using invocation param {{para|cat}}, but not using template param {{para|cat}}. A single param | ||
can specify multiple comma-separated categories if no space follows the comma. | |||
; {{para|ignore}}, {{para|ignore2}}, ...: | ; {{para|ignore}}, {{para|ignore2}}, ...: | ||
: One or more template params to silently accept and ignore. Useful e.g. when the template takes additional parameters | : One or more template params to silently accept and ignore. Useful e.g. when the template takes additional parameters | ||
| Line 509: | Line 644: | ||
; {{para|withcap}} | ; {{para|withcap}} | ||
: Capitalize the first character of the text preceding the link, unless template param {{para|nocap}} is given. | : Capitalize the first character of the text preceding the link, unless template param {{para|nocap}} is given. | ||
; {{para|withencap}} | |||
: Capitalize the first character of the text preceding the link if the language is English and template param | |||
{{para|nocap}} is not given. | |||
; {{para|withdot}} | ; {{para|withdot}} | ||
: Add a final period after the link, unless template param {{para|nodot}} is given to suppress the period, or | : Add a final period after the link, unless template param {{para|nodot}} is given to suppress the period, or | ||
| Line 535: | Line 673: | ||
local iparams = get_common_invocation_params() | local iparams = get_common_invocation_params() | ||
iparams[1] = {required = true} | iparams[1] = {required = true} | ||
local iargs = | local iargs = process_params(frame.args, iparams) | ||
local parent_args = frame:getParent().args | local parent_args = frame:getParent().args | ||
local params = get_common_template_params() | local params = get_common_template_params() | ||
if next(iargs.cat) then | |||
params.nocat = {type = "boolean"} | |||
end | end | ||
return construct_form_of_text { | |||
template = "form-of-t", | |||
iargs = iargs, | |||
parent_args = parent_args, | |||
params = params, | |||
do_form_of = function(lemma_data) | |||
local args = lemma_data.args | |||
local text | |||
if args.notext then | |||
text = "" | |||
else | |||
text = iargs[1] | |||
if should_ucfirst_text(args, iargs, lemma_data.lang) then | |||
text = ucfirst(text) | |||
end | |||
end | |||
return format_form_of { | |||
text = text, lemmas = lemma_data.lemmas, conj = lemma_data.conj, enclitics = lemma_data.enclitics, | |||
base_lemmas = lemma_data.base_lemmas, lemma_face = "term", posttext = lemma_data.posttext | |||
}, {} | |||
return | |||
base_lemmas = lemma_data.base_lemmas, lemma_face = "term", posttext = | |||
end | end | ||
} | |||
end | end | ||
| Line 596: | Line 711: | ||
This is a wrapper around construct_form_of_text() and takes the following arguments: processed invocation arguments | This is a wrapper around construct_form_of_text() and takes the following arguments: processed invocation arguments | ||
IARGS, processed parent arguments ARGS, TERM_PARAM (the parent argument specifying the main entry), COMPAT (true if the | IARGS, processed parent arguments ARGS, TERM_PARAM (the parent argument specifying the main entry), COMPAT (true if the | ||
language code is found in args | language code is found in args.lang instead of args[1]), and TAGS, the list of (non-canonicalized) inflection tags. | ||
It returns that actual definition-line text including terminating period/full-stop, formatted categories, etc. and | It returns that actual definition-line text including terminating period/full-stop, formatted categories, etc. and | ||
should be directly returned as the template function's return value | should be directly returned as the template function's return value. | ||
]=] | ]=] | ||
local function construct_tagged_form_of_text(iargs, | local function construct_tagged_form_of_text(data) | ||
return construct_form_of_text | local template, iargs, parent_args, params, no_numbered_gloss, tags = | ||
function(lemma_data) | data.template, data.iargs, data.parent_args, data.params, data.no_numbered_gloss, data.tags | ||
-- Named params not controlling link display | |||
-- Always included because lang-specific categories may be added | |||
params.nocat = {type = "boolean"} | |||
params.p = true | |||
params.POS = {alias_of = "p"} | |||
return construct_form_of_text { | |||
template = template, | |||
iargs = iargs, | |||
parent_args = parent_args, | |||
params = params, | |||
no_numbered_gloss = no_numbered_gloss, | |||
do_form_of = function(lemma_data) | |||
local args = lemma_data.args | |||
if is_callable(tags) then | |||
tags = tags(args) | |||
end | |||
-- NOTE: tagged_inflections returns two values, so we do too. | -- NOTE: tagged_inflections returns two values, so we do too. | ||
return | return tagged_inflections { | ||
lang = lemma_data.lang, | lang = lemma_data.lang, | ||
tags = tags, | tags = tags, | ||
lemmas = lemma_data.lemmas, | lemmas = lemma_data.lemmas, | ||
conj = lemma_data.conj, | |||
enclitics = lemma_data.enclitics, | enclitics = lemma_data.enclitics, | ||
enclitic_conj = lemma_data.enclitic_conj, | |||
base_lemmas = lemma_data.base_lemmas, | base_lemmas = lemma_data.base_lemmas, | ||
lemma_face = "term", | lemma_face = "term", | ||
POS = args | POS = args.p, | ||
pagename = args | pagename = args.pagename, | ||
-- Set no_format_categories because we do it ourselves in construct_form_of_text(). | -- Set no_format_categories because we do it ourselves in construct_form_of_text(). | ||
no_format_categories = true, | no_format_categories = true, | ||
nocat = args | nocat = args.nocat, | ||
notext = args | notext = args.notext, | ||
capfirst = args | capfirst = should_ucfirst_text(args, iargs, lemma_data.lang), | ||
posttext = | posttext = lemma_data.posttext, | ||
} | } | ||
end | end | ||
} | |||
end | end | ||
| Line 649: | Line 782: | ||
; {{para|def}}, {{para|def2}}, ... | ; {{para|def}}, {{para|def2}}, ... | ||
; {{para|withcap}} | ; {{para|withcap}} | ||
; {{para|withencap}} | |||
; {{para|withdot}} | ; {{para|withdot}} | ||
; {{para|nolink}} | ; {{para|nolink}} | ||
| Line 660: | Line 794: | ||
local iparams = get_common_invocation_params() | local iparams = get_common_invocation_params() | ||
iparams[1] = {list = true, required = true} | iparams[1] = {list = true, required = true} | ||
iparams | iparams.split_tags = true | ||
local iargs = | local iargs = process_params(frame.args, iparams) | ||
local parent_args = frame:getParent().args | local parent_args = frame:getParent().args | ||
local params = get_common_template_params() | |||
return construct_tagged_form_of_text { | |||
template = "tagged-form-of-t", | |||
iargs = iargs, | |||
parent_args = parent_args, | |||
params = params, | |||
tags = split_inflection_tags(iargs[1], iargs.split_tags), | |||
} | } | ||
end | end | ||
| Line 718: | Line 818: | ||
: { {{TEMPLATE|LANG|MAIN_ENTRY_LINK|MAIN_ENTRY_DISPLAY_TEXT|TAG|TAG|...}}} | : { {{TEMPLATE|LANG|MAIN_ENTRY_LINK|MAIN_ENTRY_DISPLAY_TEXT|TAG|TAG|...}}} | ||
instead of | instead of | ||
: { {{TEMPLATE|LANG|MAIN_ENTRY_LINK|MAIN_ENTRY_DISPLAY_TEXT|GLOSS}}} | : { {{TEMPLATE|LANG|MAIN_ENTRY_LINK|MAIN_ENTRY_DISPLAY_TEXT|GLOSS}}} | ||
| Line 743: | Line 843: | ||
; {{para|def}}, {{para|def2}}, ... | ; {{para|def}}, {{para|def2}}, ... | ||
; {{para|withcap}} | ; {{para|withcap}} | ||
; {{para|withencap}} | |||
; {{para|withdot}} | ; {{para|withdot}} | ||
; {{para|nolink}} | ; {{para|nolink}} | ||
| Line 753: | Line 854: | ||
function export.inflection_of_t(frame) | function export.inflection_of_t(frame) | ||
local iparams = get_common_invocation_params() | local iparams = get_common_invocation_params() | ||
iparams | iparams.preinfl = {list = true} | ||
iparams | iparams.postinfl = {list = true} | ||
iparams | iparams.split_tags = true | ||
local iargs = | local iargs = process_params(frame.args, iparams) | ||
local parent_args = frame:getParent().args | local parent_args = frame:getParent().args | ||
local params = get_common_template_params() | |||
local compat = iargs.lang or parent_args.lang | |||
local tagsind = (iargs.term_param or compat and 1 or 2) + 2 | |||
local compat = iargs | |||
params[tagsind] = {list = true, | params[tagsind] = {list = true, | ||
-- at least one inflection tag is required unless preinfl or postinfl tags are given | -- at least one inflection tag is required unless preinfl or postinfl tags are given | ||
required = #iargs | required = #iargs.preinfl == 0 and #iargs.postinfl == 0} | ||
return construct_tagged_form_of_text { | |||
template = "inflection-of-t", | |||
iargs = iargs, | |||
parent_args = parent_args, | |||
params = params, | |||
no_numbered_gloss = true, | |||
tags = function(args) | |||
local infls | |||
if not next(iargs.preinfl) and not next(iargs.postinfl) then | |||
-- If no preinfl or postinfl tags, just use the user-specified tags directly. | |||
infls = args[tagsind] | |||
else | |||
-- Otherwise, we need to prepend the preinfl tags and postpend the postinfl tags. If there's only one tag set | |||
-- (no semicolon), it's easier. Since this is common, we optimize for it. | |||
infls = {} | |||
local saw_semicolon = false | |||
for _, infl in ipairs(args[tagsind]) do | |||
params | if infl == ";" then | ||
saw_semicolon = true | |||
break | |||
end | |||
end | |||
local split_preinfl = split_inflection_tags(iargs.preinfl, iargs.split_tags) | |||
local split_postinfl = split_inflection_tags(iargs.postinfl, iargs.split_tags) | |||
if not saw_semicolon then | |||
extend(infls, split_preinfl) | |||
extend(infls, args[tagsind]) | |||
extend(infls, split_postinfl) | |||
else | |||
local groups = split_tag_set(args[tagsind]) | |||
for _, group in ipairs(groups) do | |||
if #infls > 0 then | |||
insert(infls, ";") | |||
end | |||
extend(infls, split_preinfl) | |||
extend(infls, group) | |||
extend(infls, split_postinfl) | |||
end | |||
end | end | ||
end | end | ||
end | return infls | ||
end, | |||
} | |||
end | end | ||
| Line 853: | Line 921: | ||
function export.normalize_pos(frame) | function export.normalize_pos(frame) | ||
local iparams = { | local iparams = { | ||
[1] = | [1] = true, | ||
["default"] = | ["default"] = true, | ||
} | } | ||
local iargs = | local iargs = process_params(frame.args, iparams) | ||
if not iargs[1] and not iargs | if not iargs[1] and not iargs.default then | ||
error("Either 1= or default= must be given in the invocation args") | error("Either 1= or default= must be given in the invocation args") | ||
end | end | ||
if not iargs[1] then | if not iargs[1] then | ||
return iargs | return iargs.default | ||
end | end | ||
return | return (m_form_of_pos or get_m_form_of_pos())[iargs[1]] or iargs[1] | ||
end | end | ||
return export | return export | ||