Module:form of/templates: Difference between revisions

No edit summary
No edit summary
 
Line 1: Line 1:
local export = {}
local export = {}


local debug_track_module = "Module:debug/track"
local form_of_module = "Module:form of"
local form_of_module = "Module:form of"
local functions_module = "Module:fun"
local functions_module = "Module:fun"
Line 17: Line 18:
local pairs = pairs
local pairs = pairs
local require = require
local require = require
local boolean_param = {type = "boolean"}


-- FIXME: Finish [[Module:format utilities]].
-- FIXME: Finish [[Module:format utilities]].
Line 24: Line 27:
--[==[
--[==[
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.]==]
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 debug_track(...)
debug_track = require(debug_track_module)
return debug_track(...)
end


local function decode_entities(...)
local function decode_entities(...)
Line 135: Line 142:
[[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.
]==]
]==]
-- Add tracking category for PAGE when called from TEMPLATE. The tracking category linked to is
-- [[Wiktionary:Tracking/form of/TEMPLATE/PAGE]]. If TEMPLATE is omitted, the tracking category is of the form
-- [[Wiktionary:Tracking/form of/PAGE]].
local function track(page, template)
debug_track("form of/" .. (template and template .. "/" or "") .. page)
end




Line 141: Line 155:
-- Named params not controlling link display
-- Named params not controlling link display
["cat"] = {list = true, sublist = "comma without whitespace", flatten = true},
["cat"] = {list = true, sublist = "comma without whitespace", flatten = true},
["notext"] = {type = "boolean"},
["notext"] = boolean_param,
["sort"] = true,
["sort"] = true,
["enclitic"] = true,
["enclitic"] = true,
-- FIXME! The following should only be available when withcap=1 in invocation args or when withencap=1 and the
-- 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.
-- language is "en". Before doing that, need to remove all uses of nocap= in other circumstances.
["nocap"] = {type = "boolean"},
["nocap"] = boolean_param,
["addl"] = true, -- additional text to display at the end, before the closing </span>
["addl"] = true, -- additional text to display at the end, before the closing </span>
["pagename"] = true, -- for testing, etc.
["pagename"] = true, -- for testing, etc.
Line 182: Line 196:
end
end


-- Modify PARAMS in-place by adding parameters that control the link to the
-- main entry. TERM_PARAM is the number of the param specifying the main
-- entry itself; TERM_PARAM + 1 will be the display text, and TERM_PARAM + 2
-- will be the gloss, unless NO_NUMBERED_GLOSS is given.
local function add_link_params(parent_args, params, term_param, no_numbered_gloss)
params[term_param + 1] = {alias_of = "alt"}
if not no_numbered_gloss then
params[term_param + 2] = {alias_of = "t"}
end
-- Numbered params controlling link display
params[term_param] = true
end


-- Need to do what [[Module:parameters]] does to string arguments from parent_args as we're running this
-- Need to do what [[Module:parameters]] does to string arguments from parent_args as we're running this
Line 225: Line 226:
end
end


--[=[
Modify `params` in-place by adding parameters that control the link to the main entry and any base lemmas. `term_param`
is the number of the param specifying the main entry itself; `term_param` + 1 will be the display text, and `term_param`
+ 2 will be the gloss, unless `no_numbered_gloss` is given. The base lemma parameters are determined by attempting to
load language-specific data for the language of the page; this comes from |lang= if `compat` is given, else from |1=.
]=]
local function add_link_and_base_lemma_params(iargs, parent_args, params, term_param, compat, no_numbered_gloss)
local function add_link_and_base_lemma_params(iargs, parent_args, params, term_param, compat, no_numbered_gloss)
local base_lemma_params
local base_lemma_params
if not iargs.nolink and not iargs.linktext then
if not iargs.nolink and not iargs.linktext then
add_link_params(parent_args, params, term_param, no_numbered_gloss)
-- Numbered params controlling link display
if iargs.with_multiple_parts then
params[term_param] = {list = true, allow_holes = true}
else
params[term_param + 1] = {alias_of = "alt"}
if not no_numbered_gloss then
params[term_param + 2] = {alias_of = "t"}
end
params[term_param] = true
end
base_lemma_params = add_base_lemma_params(parent_args, iargs, params, compat)
base_lemma_params = add_base_lemma_params(parent_args, iargs, params, compat)
end
end
Line 239: Line 255:
if iargs.withdot then
if iargs.withdot then
params.dot = true
params.dot = true
params.nodot = {type = "boolean"}
params.nodot = boolean_param
end
end


Line 247: Line 263:


if not iargs.withcap then
if not iargs.withcap then
params.cap = {type = "boolean"}
params.cap = boolean_param
ignored_tracked_params.nocap = iargs.withencap and "non-english" or "always"
ignored_tracked_params.nocap = iargs.withencap and "non-english" or "always"
end
end
Line 336: Line 352:
default = iargs.lang or "und"
default = iargs.lang or "und"
}
}
-- Error to catch most uses of old-style parameters for {{contraction of}}. (FIXME: Remove eventually.)
if iargs.with_multiple_parts then
if ine(parent_args[term_param + 2]) and not ine(parent_args[term_param + 1]) and not ine(parent_args.tr2) and not ine(parent_args.ts2)
and not ine(parent_args.t2) and not ine(parent_args.gloss2) and not ine(parent_args.g2)
and not ine(parent_args.alt2) then
error(("You specified a term in %s= and not one in %s=. You probably meant to use t= to specify a gloss instead. "
.. "If you intended to specify two terms, put the second term in %s=."):format(term_param + 2, term_param + 1,
term_param + 1))
end
if not ine(parent_args[term_param + 1]) and not ine(parent_args.alt2) and not ine(parent_args.tr2) and not ine(parent_args.ts2)
and ine(parent_args.g2) then
error(("You specified a gender in g2= but no term in %s=. You were probably trying to specify two genders for "
.. "a single term. To do that, put both genders in g=, comma-separated."):format(term_param + 1))
end
end


local base_lemma_params = add_link_and_base_lemma_params(iargs, parent_args, params, term_param, compat,
local base_lemma_params = add_link_and_base_lemma_params(iargs, parent_args, params, term_param, compat,
Line 345: Line 377:
require("Module:parameters").process(parent_args, params)
require("Module:parameters").process(parent_args, params)
but in addition it does the following:
but in addition it does the following:
(1) Supplies default values for unspecified parent arguments as specified in
(1) Supplies default values for unspecified parent arguments as specified in DEFAULTS, which consist of specs of the
DEFAULTS, which consist of specs of the form "ARG=VALUE". These are
form "ARG=VALUE". These are added to the parent arguments prior to processing, so boolean and number parameters
added to the parent arguments prior to processing, so boolean and number
will process the value appropriately.
parameters will process the value appropriately.
(2) Removes parent arguments specified in IGNORESPECS, which consist either of bare argument names to remove, or
(2) Removes parent arguments specified in IGNORESPECS, which consist either
list-argument names to remove of the form "ARG:list".
of bare argument names to remove, or list-argument names to remove of the
(3) Tracks the use of any parent arguments specified in TRACKED_PARAMS, which is a set where the keys are arguments
form "ARG:list".
as they exist after processing (hence numeric arguments should be numbers, not strings) and the values should be
(3) Tracks the use of any parent arguments specified in TRACKED_PARAMS, which
boolean true.
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 defaults = iargs.def
Line 417: Line 446:
end
end


local m_param_utils, param_mods
local param_mods_with_conj, param_mods_without_conj


local function init_param_mods()
local function get_param_mods(with_conj)
if not m_param_utils then
if with_conj then
m_param_utils = require(parameter_utilities_module)
if not param_mods_with_conj then
param_mods = m_param_utils.construct_param_mods {
param_mods_with_conj = require(parameter_utilities_module).construct_param_mods {
{group = {"link", "q", "l", "ref"}},
{group = {"link", "q", "l", "ref"}},
{param = "conj", set = allowed_conj_set, overall = true},
{param = "conj", set = allowed_conj_set, overall = true},
}
}
end
return param_mods_with_conj
else
if not param_mods_without_conj then
param_mods_without_conj = require(parameter_utilities_module).construct_param_mods {
{group = {"link", "q", "l", "ref"}},
-- Override lit= to have a separate overall value
{param = "lit", separate_no_index = true},
}
end
return param_mods_without_conj
end
end
end
end
Line 433: Line 473:
args = process_params(parent_args, params)
args = process_params(parent_args, params)
else
else
init_param_mods()
local m_param_utils = require(parameter_utilities_module)
terms, args = m_param_utils.parse_term_with_inline_modifiers_and_separate_params {
if iargs.with_multiple_parts then
params = params,
terms, args = m_param_utils.parse_list_with_inline_modifiers_and_separate_params {
param_mods = param_mods,
params = params,
raw_args = parent_args,
param_mods = get_param_mods(false),
termarg = term_param,
raw_args = parent_args,
track_module = "form-of" .. (template and "/" .. template or ""),
termarg = term_param,
lang = compat and "lang" or 1,
track_module = "form of" .. (template and "/" .. template or ""),
sc = "sc",
lang = compat and "lang" or 1,
-- Don't do this, doesn't seem to make sense.
sc = "sc.default",
-- parse_lang_prefix = true,
parse_lang_prefix = true,
make_separate_g_into_list = true,
default_separator = " +&lrm; ",
process_args_before_parsing = function(args)
special_separators = {[";"] = " or "},
-- 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.
else
if args.g and args.g[1] then
terms, args = m_param_utils.parse_term_with_inline_modifiers_and_separate_params {
local genders = {}
params = params,
for _, g in ipairs(args.g) do
param_mods = get_param_mods("with conj"),
extend(genders, split(g, ","))
raw_args = parent_args,
end
termarg = term_param,
args.g = genders
track_module = "form of" .. (template and "/" .. template or ""),
end
lang = compat and "lang" or 1,
end,
sc = "sc",
splitchar = ",",
parse_lang_prefix = true,
subitem_param_handling = "last",
make_separate_g_into_list = true,
}
splitchar = ",",
subitem_param_handling = "last",
}
end
end
end


local lang = args[compat and "lang" or 1]
local lang = args[compat and "lang" or 1]
-- Tracking for certain user-specified params. This is generally used for
-- parameters that we accept but ignore, so that we can eventually remove
-- all uses of these params and stop accepting them.
if ignored_tracked_params then
for ignored_tracked_param, condition in pairs(ignored_tracked_params) do
if parent_args[ignored_tracked_param] and (condition ~= "non-english" or lang:getCode() ~= "en") then
track("arg/" .. ignored_tracked_param, template)
track("arg/" .. ignored_tracked_param)
end
end
end


-- Determine categories for the page, including tracking categories
-- Determine categories for the page, including tracking categories
Line 480: Line 535:
local function add_term_tracking_categories(term)
local function add_term_tracking_categories(term)
-- add tracking category if term is same as page title
-- add tracking category if term is same as page title
if term and mw.title.getCurrentTitle().text == (lang:makeEntryName(term)) then
if term and mw.loadData("Module:headword/data").pagename == lang:stripDiacritics(term) then
insert(categories, "Forms linking to themselves")
insert(categories, "Forms linking to themselves")
end
end
Line 498: Line 553:
lemmas = iargs.linktext
lemmas = iargs.linktext
else
else
if not terms.terms[1] then
if iargs.with_multiple_parts then
lemmas = terms
else
lemmas = terms.terms
end
if not lemmas[1] then
if mw.title.getCurrentTitle().nsText == "Template" then
if mw.title.getCurrentTitle().nsText == "Template" then
terms.terms[1] = {
lemmas[1] = {
lang = lang,
lang = lang,
term = "term"
term = "term"
Line 508: Line 568:
end
end
end
end
for _, termobj in ipairs(terms.terms) do
for _, termobj in ipairs(lemmas) do
if termobj.term then
if termobj.term then
add_term_tracking_categories(termobj.term)
add_term_tracking_categories(termobj.term)
Line 516: Line 576:
-- changed it. Hopefully nothing depended on the old behavior.
-- changed it. Hopefully nothing depended on the old behavior.
end
end
lemmas = terms.terms
end
end


local enclitics, enclitic_conj
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, get_param_mods("with conj"),
local enclitics_obj = parse_terms_with_inline_modifiers("enclitic", args.enclitic, param_mods, lang)
lang)
enclitics = enclitics_obj.terms
enclitics = enclitics_obj.terms
enclitic_conj = enclitics_obj.conj
enclitic_conj = enclitics_obj.conj
Line 532: Line 590:
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],
local base_lemmas_obj = parse_terms_with_inline_modifiers(param, args[param], param_mods, lang)
get_param_mods("with conj"), lang)
insert(base_lemmas, {
insert(base_lemmas, {
paramobj = base_lemma_param_obj,
paramobj = base_lemma_param_obj,
Line 556: Line 614:
end
end


local conj
if iargs.with_multiple_parts then
conj = false -- signals to use 'separator' field
else
conj = terms and terms.conj or iargs.conj
end
local lemma_data = {
local lemma_data = {
lang = lang,
lang = lang,
args = args,
args = args,
lemmas = lemmas,
lemmas = lemmas,
conj = terms and terms.conj or iargs.conj,
conj = conj,
enclitics = enclitics,
enclitics = enclitics,
enclitic_conj = enclitic_conj,
enclitic_conj = enclitic_conj,
Line 566: Line 630:
categories = categories,
categories = categories,
posttext = posttext,
posttext = posttext,
lit = iargs.with_multiple_parts and args.lit.default or nil,
}
}


Line 573: Line 638:
args.nodot and "" or args.dot or iargs.withdot and "." or ""
args.nodot and "" or args.dot or iargs.withdot and "." or ""
)
)
if #lemma_data.categories == 0 then
if not lemma_data.categories[1] then
return text
return text
end
end
Line 586: Line 651:




-- Invocation parameters shared between form_of_t(), tagged_form_of_t() and inflection_of_t().
-- Invocation parameters shared between form_of_t(), tagged_form_of_t() and inflection_of_t(). `calling_func` is the
local function get_common_invocation_params()
-- invoking function ("form_of_t", "tagged_form_of_t" or "inflection_of_t"), for handling parameters shared by two but
return {
-- not all three invoking functions.
local function get_common_invocation_params(calling_func)
local iparams = {
["term_param"] = {type = "number"},
["term_param"] = {type = "number"},
["lang"] = true, -- To be used as the default code in params.
["lang"] = true, -- To be used as the default code in params.
Line 596: Line 663:
["def"] = {list = true},
["def"] = {list = true},
["conj"] = {set = allowed_conj_set, default = "and"},
["conj"] = {set = allowed_conj_set, default = "and"},
["withcap"] = {type = "boolean"},
["withcap"] = boolean_param,
["withencap"] = {type = "boolean"},
["withencap"] = boolean_param,
["withdot"] = {type = "boolean"},
["withdot"] = boolean_param,
["nolink"] = {type = "boolean"},
["nolink"] = boolean_param,
["linktext"] = true,
["linktext"] = true,
["posttext"] = true,
["posttext"] = true,
Line 605: Line 672:
["lemma_is_sort_key"] = true,
["lemma_is_sort_key"] = true,
}
}
if calling_func ~= "inflection_of_t" then
iparams.with_multiple_parts = boolean_param
end
return iparams
end
end




local function should_ucfirst_text(args, iargs, lang)
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
local code = lang:getCode()
return args.cap or (iargs.withcap or iargs.withencap and code == "en" or code == "mul") and not args.nocap
end
end


Line 624: Line 696:
: Numbered param holding the term linked to. Other numbered params come after. Defaults to 1 if invocation or template
: Numbered param holding the term linked to. Other numbered params come after. Defaults to 1 if invocation or template
   param {{para|lang}} is present, otherwise 2.
   param {{para|lang}} is present, otherwise 2.
; {{para|with_multiple_parts|1}}
: If specified, higher numbered parameters above the numbered param in {{para|term_param}} specify additional parts out
  of which the term was constructed, for use by templates like {{tl|contraction of}}. (If not specified, the parameter
  at <code><var>term_param</var> + 1</code> is the display form, same as {{para|alt}}, and the parameter at
  at <code><var>term_param</var> + 2</code> is the gloss, same as {{para|t}}.)
; {{para|lang}}
; {{para|lang}}
: Default language code for language-specific templates. If specified, no language code needs to be specified, and if
: Default language code for language-specific templates. If specified, no language code needs to be specified, and if
Line 642: Line 719:
: One or more default values to supply for template args. For example, specifying {{para|def|2=tr=-}} causes the default
: One or more default values to supply for template args. For example, specifying {{para|def|2=tr=-}} causes the default
   for template param {{para|tr}} to be `-`. Actual template params override these defaults.
   for template param {{para|tr}} to be `-`. Actual template params override these defaults.
; {{para|withcap}}
; {{para|withcap|1}}
: 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}}
; {{para|withencap|1}}
: Capitalize the first character of the text preceding the link if the language is English and template param
: Capitalize the first character of the text preceding the link if the language is English and template param
   {{para|nocap}} is not given.
   {{para|nocap}} is not given.
; {{para|withdot}}
; {{para|withdot|1}}
: 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
   {{para|dot}} is given to specify an alternative punctuation character.
   {{para|dot}} is given to specify an alternative punctuation character.
; {{para|nolink}}
; {{para|nolink|1}}
: Suppress the display of the link. If specified, none of the template params that control the link
: Suppress the display of the link. If specified, none of the template params that control the link
   ({{para|<var>term_param</var>}}, {{para|<var>term_param</var> + 1}}, {{para|<var>term_param</var> + 2}}, {{para|t}},
   ({{para|<var>term_param</var>}}, {{para|<var>term_param</var> + 1}}, {{para|<var>term_param</var> + 2}}, {{para|t}},
Line 667: Line 744:
: Category to add the page to if the primary entry linked to doesn't exist. The language name will automatically be
: Category to add the page to if the primary entry linked to doesn't exist. The language name will automatically be
   prepended.
   prepended.
; {{para|lemma_is_sort_key}}
; {{para|lemma_is_sort_key|1}}
: If the user didn't specify a sort key, use the lemma as the sort key (instead of the page itself).
: If the user didn't specify a sort key, use the lemma as the sort key (instead of the page itself).
]==]
]==]
function export.form_of_t(frame)
function export.form_of_t(frame)
local iparams = get_common_invocation_params()
local iparams = get_common_invocation_params("form_of_t")
iparams[1] = {required = true}
iparams[1] = {required = true}
local iargs = process_params(frame.args, iparams)
local iargs = process_params(frame.args, iparams)
Line 679: Line 756:


if next(iargs.cat) then
if next(iargs.cat) then
params.nocat = {type = "boolean"}
params.nocat = boolean_param
end
end


Line 698: Line 775:
end
end
end
end
-- This returns two values, which we pass up to the caller.
return format_form_of {
return format_form_of {
text = text, lemmas = lemma_data.lemmas, conj = lemma_data.conj, enclitics = lemma_data.enclitics,
lang = lemma_data.lang, text = text, lemmas = lemma_data.lemmas, conj = lemma_data.conj,
base_lemmas = lemma_data.base_lemmas, lemma_face = "term", posttext = lemma_data.posttext
enclitics = lemma_data.enclitics, base_lemmas = lemma_data.base_lemmas, lemma_face = "term",
}, {}
lit = lemma_data.lit, posttext = lemma_data.posttext
}
end
end
}
}
Line 721: Line 800:
-- Named params not controlling link display
-- Named params not controlling link display
-- Always included because lang-specific categories may be added
-- Always included because lang-specific categories may be added
params.nocat = {type = "boolean"}
params.nocat = boolean_param
params.p = true
params.p = true
params.POS = {alias_of = "p"}
params.POS = {alias_of = "p"}
Line 776: Line 855:
   argument, simplifying template code.
   argument, simplifying template code.
; {{para|term_param}}
; {{para|term_param}}
; {{para|with_multiple_parts|1}}
; {{para|lang}}
; {{para|lang}}
; {{para|sc}}
; {{para|sc}}
Line 781: Line 861:
; {{para|ignore}}, {{para|ignore2}}, ...
; {{para|ignore}}, {{para|ignore2}}, ...
; {{para|def}}, {{para|def2}}, ...
; {{para|def}}, {{para|def2}}, ...
; {{para|withcap}}
; {{para|withcap|1}}
; {{para|withencap}}
; {{para|withencap|1}}
; {{para|withdot}}
; {{para|withdot|1}}
; {{para|nolink}}
; {{para|nolink|1}}
; {{para|linktext}}
; {{para|linktext}}
; {{para|posttext}}
; {{para|posttext}}
; {{para|noprimaryentrycat}}
; {{para|noprimaryentrycat}}
; {{para|lemma_is_sort_key}}
; {{para|lemma_is_sort_key|1}}
: All of these are the same as in {form_of_t()}.
: All of these are the same as in {form_of_t()}.
]==]
]==]
function export.tagged_form_of_t(frame)
function export.tagged_form_of_t(frame)
local iparams = get_common_invocation_params()
local iparams = get_common_invocation_params("tagged_form_of_t")
iparams[1] = {list = true, required = true}
iparams[1] = {list = true, required = true}
iparams.split_tags = true
iparams.split_tags = true
Line 842: Line 922:
; {{para|ignore}}, {{para|ignore2}}, ...
; {{para|ignore}}, {{para|ignore2}}, ...
; {{para|def}}, {{para|def2}}, ...
; {{para|def}}, {{para|def2}}, ...
; {{para|withcap}}
; {{para|withcap|1}}
; {{para|withencap}}
; {{para|withencap|1}}
; {{para|withdot}}
; {{para|withdot|1}}
; {{para|nolink}}
; {{para|nolink|1}}
; {{para|linktext}}
; {{para|linktext}}
; {{para|posttext}}
; {{para|posttext}}
; {{para|noprimaryentrycat}}
; {{para|noprimaryentrycat}}
; {{para|lemma_is_sort_key}}
; {{para|lemma_is_sort_key|1}}
: All of these are the same as in {form_of_t()}.
: All of these are the same as in {form_of_t()}.
]==]
]==]
function export.inflection_of_t(frame)
function export.inflection_of_t(frame)
local iparams = get_common_invocation_params()
local iparams = get_common_invocation_params("inflection_of_t")
iparams.preinfl = {list = true}
iparams.preinfl = {list = true}
iparams.postinfl = {list = true}
iparams.postinfl = {list = true}