Module:affix/templates: Difference between revisions
No edit summary |
No edit summary |
||
| (9 intermediate revisions by the same user not shown) | |||
| Line 3: | Line 3: | ||
local m_affix = require("Module:affix") | local m_affix = require("Module:affix") | ||
local m_utilities = require("Module:utilities") | local m_utilities = require("Module:utilities") | ||
local en_utilities_module = "Module:en-utilities" | |||
local parameter_utilities_module = "Module:parameter utilities" | local parameter_utilities_module = "Module:parameter utilities" | ||
local pseudo_loan_module = "Module:affix/pseudo-loan" | local pseudo_loan_module = "Module:affix/pseudo-loan" | ||
local insert = table.insert | |||
local boolean_param = {type = "boolean"} | |||
local function is_property_key(k) | local function is_property_key(k) | ||
| Line 11: | Line 15: | ||
end | end | ||
local recognized_affix_types = { | |||
prefix = "prefix", | |||
pre = "prefix", | |||
suffix = "suffix", | |||
suf = "suffix", | |||
interfix = "interfix", | |||
inter = "interfix", | |||
infix = "infix", | |||
["in"] = "infix", | |||
circumfix = "circumfix", | |||
circum = "circumfix", | |||
["non-affix"] = "non-affix", | |||
naf = "non-affix", | |||
root = "non-affix", | |||
} | |||
local function pre_normalize_affix_type(data) | |||
local modtext = data.modtext | |||
modtext = modtext:match("^<(.*)>$") | |||
if not modtext then | |||
error(("Internal error: Passed-in modifier isn't surrounded by angle brackets: %s"):format(data.modtext)) | |||
end | |||
if recognized_affix_types[modtext] then | |||
modtext = "type:" .. modtext | |||
end | |||
return "<" .. modtext .. ">" | |||
end | |||
-- Parse raw arguments. A single parameter `data` is passed in, with the following fields: | -- Parse raw arguments. A single parameter `data` is passed in, with the following fields: | ||
| Line 23: | Line 55: | ||
-- * `require_index_for_pos`: There is no separate |pos= parameter distinct from |pos1=, |pos2=, etc. Instead, | -- * `require_index_for_pos`: There is no separate |pos= parameter distinct from |pos1=, |pos2=, etc. Instead, | ||
-- specifying |pos= results in an error. | -- specifying |pos= results in an error. | ||
-- * `dont_require_index`: Allow |foo= to be specified as a synonym for |foo1= (except for |lit=, which remains | |||
-- distinct). | |||
-- * `allow_type`: Allow |type1=, |type2=, etc. or inline <type:...> for the affix type, and allow a separate |type= | |||
-- parameter for the etymology type (FIXME: this may be confusing; consider changing the etymology type to |etype=). | |||
-- * `allow_semicolon_separator`: Allow semicolon as a separator, displaying as " or ". This requires changes in the | |||
-- display of the output, to not always put a + between the items. | |||
-- | -- | ||
-- Note that all language parameters are allowed to be etymology-only languages. | -- Note that all language parameters are allowed to be etymology-only languages. | ||
| Line 44: | Line 82: | ||
[term_index] = {list = true, allow_holes = true}, | [term_index] = {list = true, allow_holes = true}, | ||
["sort"] = {}, | ["sort"] = {}, | ||
["nocap"] = | ["nocap"] = boolean_param, -- always allow this even if not used, for use with {{surf}}, which adds it | ||
} | } | ||
| Line 58: | Line 96: | ||
local m_param_utils = require(parameter_utilities_module) | local m_param_utils = require(parameter_utilities_module) | ||
local | local param_mod_source = {} | ||
-- We want to require an index for all params (or use separate_no_index, which also requires an index for the | if not data.dont_require_index then | ||
insert(param_mod_source, | |||
-- We want to require an index for all params (or use separate_no_index, which also requires an index for the | |||
{group = {"link", "ref", "lang", "q", "l"}} | -- param corresponding to the first item). | ||
{default = true, require_index = true} | |||
) | |||
{param = "pos", separate_no_index = | end | ||
insert(param_mod_source, {group = {"link", "ref", "lang", "q", "l", "infl"}}) | |||
-- Override lit= to be separate from lit1=. | |||
insert(param_mod_source, {param = "lit", separate_no_index = true}) | |||
if not data.dont_require_index and not data.require_index_for_pos then | |||
-- Override pos= to be separate from pos1=. | |||
insert(param_mod_source, {param = "pos", separate_no_index = true}) | |||
end | |||
if data.allow_type then | |||
insert(param_mod_source, {param = "type", separate_no_index = true}) | |||
end | |||
local param_mods = m_param_utils.construct_param_mods(param_mod_source) | |||
if data.extra_params then | if data.extra_params then | ||
data.extra_params(params) | data.extra_params(params) | ||
end | end | ||
local items, args = m_param_utils. | local items, args = m_param_utils.parse_list_with_inline_modifiers_and_separate_params { | ||
params = params, | params = params, | ||
param_mods = param_mods, | param_mods = param_mods, | ||
| Line 78: | Line 127: | ||
parse_lang_prefix = true, | parse_lang_prefix = true, | ||
track_module = "homophones", | track_module = "homophones", | ||
disallow_custom_separators = | -- the inclusion of ‎ is what [[Module:affix]] has always done | ||
default_separator = data.allow_semicolon_separator and " +‎ " or nil, | |||
special_separators = data.allow_semicolon_separator and {[";"] = " or "} or nil, | |||
disallow_custom_separators = not data.allow_semicolon_separator, | |||
-- For compatibility, we need to not skip completely unspecified items. It is common, for example, to do | -- For compatibility, we need to not skip completely unspecified items. It is common, for example, to do | ||
-- {{suffix|lang||foo}} to generate "+ -foo". | -- {{suffix|lang||foo}} to generate "+ -foo". | ||
dont_skip_items = true, | dont_skip_items = true, | ||
-- Allow e.g. <infix> to be specified in place of <type:infix>. | |||
pre_normalize_modifiers = pre_normalize_affix_type, | |||
-- Don't pass in `lang` or `sc`, as they will be used as defaults to initialize the items, which we don't want | -- Don't pass in `lang` or `sc`, as they will be used as defaults to initialize the items, which we don't want | ||
-- (particularly for `lang`), as the code in [[Module:affix]] uses the presence of `lang` as an indicator that | -- (particularly for `lang`), as the code in [[Module:affix]] uses the presence of `lang` as an indicator that | ||
| Line 107: | Line 161: | ||
if not saw_item_property then | if not saw_item_property then | ||
items[i] = nil | items[i] = nil | ||
elseif item.type then | |||
-- Validate and canonicalize affix types. | |||
if not recognized_affix_types[item.type] then | |||
local valid_types = {} | |||
for k in pairs(recognized_affix_types) do | |||
insert(valid_types, ("'%s'"):format(k)) | |||
end | |||
table.sort(recognized_affix_types) | |||
error(("Unrecognized affix type '%s' in item %s; valid values are %s"):format( | |||
item.type, item.itemno, table.concat(valid_types, ", "))) | |||
else | |||
item.type = recognized_affix_types[item.type] | |||
end | |||
end | end | ||
end | |||
if args.type and args.type.default and not m_affix.etymology_types[args.type.default] then | |||
error("Unrecognized etymology type: '" .. args.type.default .. "'") | |||
end | end | ||
| Line 120: | Line 191: | ||
data.lit = args.lit and args.lit.default | data.lit = args.lit and args.lit.default | ||
data.sort_key = args.sort | data.sort_key = args.sort | ||
data.type = args.type | data.type = args.type and args.type.default | ||
data.nocap = args.nocap | data.nocap = args.nocap | ||
data.notext = args.notext | data.notext = args.notext | ||
| Line 129: | Line 200: | ||
data.q = args.q.default | data.q = args.q.default | ||
data.qq = args.qq.default | data.qq = args.qq.default | ||
data.infl = args.infl.default | |||
return data | return data | ||
end | end | ||
| Line 135: | Line 207: | ||
function export.affix(frame) | function export.affix(frame) | ||
local function extra_params(params) | local function extra_params(params) | ||
params.notext = boolean_param | |||
params.notext = | params.nocat = boolean_param | ||
params.nocat = | params.force_cat = boolean_param | ||
params.force_cat = | |||
end | end | ||
| Line 144: | Line 215: | ||
raw_args = frame:getParent().args, | raw_args = frame:getParent().args, | ||
extra_params = extra_params, | extra_params = extra_params, | ||
allow_type = true, | |||
allow_semicolon_separator = true, | |||
} | } | ||
-- There must be at least one part to display. If there are gaps, a term | -- There must be at least one part to display. If there are gaps, a term | ||
-- request will be shown. | -- request will be shown. | ||
if not next(parts) and not args.type then | if not next(parts) and not args.type.default then | ||
if mw.title.getCurrentTitle().nsText == "Template" then | if mw.title.getCurrentTitle().nsText == "Template" then | ||
parts = { {term = "prefix-"}, {term = "base"}, {term = "-suffix"} } | parts = { {term = "prefix-"}, {term = "base"}, {term = "-suffix"} } | ||
| Line 165: | Line 234: | ||
function export.compound(frame) | function export.compound(frame) | ||
local function extra_params(params) | local function extra_params(params) | ||
params.notext = boolean_param | |||
params.notext = | params.nocat = boolean_param | ||
params.nocat = | params.force_cat = boolean_param | ||
params.force_cat = | |||
end | end | ||
| Line 174: | Line 242: | ||
raw_args = frame:getParent().args, | raw_args = frame:getParent().args, | ||
extra_params = extra_params, | extra_params = extra_params, | ||
allow_type = true, | |||
allow_semicolon_separator = true, | |||
} | } | ||
-- There must be at least one part to display. If there are gaps, a term | -- There must be at least one part to display. If there are gaps, a term | ||
-- request will be shown. | -- request will be shown. | ||
if not next(parts) and not args.type then | if not next(parts) and not args.type.default then | ||
if mw.title.getCurrentTitle().nsText == "Template" then | if mw.title.getCurrentTitle().nsText == "Template" then | ||
parts = { {term = "first"}, {term = "second"} } | parts = { {term = "first"}, {separator = " +‎ ", term = "second"} } | ||
else | else | ||
error("You must provide at least one part of a compound.") | error("You must provide at least one part of a compound.") | ||
| Line 193: | Line 259: | ||
end | end | ||
-- FIXME: Temporary for check in compound_like() below for old-style {{contraction}} parameters. Remove eventually. | |||
local function ine(arg) | |||
if arg == "" then | |||
return nil | |||
else | |||
return arg | |||
end | |||
end | |||
function export.compound_like(frame) | function export.compound_like(frame) | ||
| Line 201: | Line 276: | ||
["oftext"] = {}, | ["oftext"] = {}, | ||
["cat"] = {}, | ["cat"] = {}, | ||
["noaffixcat"] = boolean_param, | |||
["dont_require_index"] = boolean_param, | |||
} | } | ||
local iargs = require("Module:parameters").process(frame.args, iparams) | local iargs = require("Module:parameters").process(frame.args, iparams) | ||
local parent_args = frame:getParent().args | |||
-- Error to catch most uses of old-style parameters for {{contraction}}. (FIXME: Remove eventually.) | |||
local term_param = iargs.lang and 1 or 2 | |||
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 | |||
local function extra_params(params) | local function extra_params(params) | ||
params.notext = | params.notext = boolean_param | ||
params.nocat = | params.nocat = boolean_param | ||
params.force_cat = | params.force_cat = boolean_param | ||
end | end | ||
local args, parts, lang, sc = parse_args { | local args, parts, lang, sc = parse_args { | ||
raw_args = | raw_args = parent_args, | ||
extra_params = extra_params, | extra_params = extra_params, | ||
ilang = iargs.lang, | ilang = iargs.lang, | ||
dont_require_index = iargs.dont_require_index, | |||
-- FIXME, why are we doing this? Formerly we had 'params.pos = nil' whose intention was to disable the overall | -- FIXME, why are we doing this? Formerly we had 'params.pos = nil' whose intention was to disable the overall | ||
-- pos= while preserving posN=, which is equivalent to the following using the new syntax. But why is this | -- pos= while preserving posN=, which is equivalent to the following using the new syntax. But why is this | ||
-- necessary? | -- necessary? | ||
require_index_for_pos = true, | require_index_for_pos = not iargs.dont_require_index, | ||
allow_semicolon_separator = true, | |||
} | } | ||
| Line 227: | Line 322: | ||
local oftext = not notext and (iargs.oftext or text and "of") | local oftext = not notext and (iargs.oftext or text and "of") | ||
local cat = not nocat and iargs.cat | local cat = not nocat and iargs.cat | ||
local noaffixcat = nocat or iargs.noaffixcat | |||
if not next(parts) then | if not next(parts) then | ||
if mw.title.getCurrentTitle().nsText == "Template" then | if mw.title.getCurrentTitle().nsText == "Template" then | ||
parts = { {term = "first"}, {term = "second"} } | parts = { {term = "first"}, {separator = " +‎ ", term = "second"} } | ||
end | end | ||
end | end | ||
return m_affix.show_compound_like(augment_affix_data({ parts = parts, text = text, oftext = oftext, cat = cat }, | return m_affix.show_compound_like(augment_affix_data({ parts = parts, text = text, oftext = oftext, cat = cat, noaffixcat = noaffixcat }, | ||
args, lang, sc)) | args, lang, sc)) | ||
end | end | ||
| Line 282: | Line 378: | ||
local function extra_params(params) | local function extra_params(params) | ||
params.notext = boolean_param | |||
params.notext = | params.nocat = boolean_param | ||
params.nocat = | params.force_cat = boolean_param | ||
params.force_cat = | |||
end | end | ||
| Line 291: | Line 386: | ||
raw_args = parent_args, | raw_args = parent_args, | ||
extra_params = extra_params, | extra_params = extra_params, | ||
allow_type = true, | |||
allow_semicolon_separator = true, | |||
} | } | ||
-- There must be at least one part to display. If there are gaps, a term | -- There must be at least one part to display. If there are gaps, a term | ||
| Line 301: | Line 394: | ||
if not next(parts) then | if not next(parts) then | ||
if mw.title.getCurrentTitle().nsText == "Template" then | if mw.title.getCurrentTitle().nsText == "Template" then | ||
parts = { {term = "first"}, {term = "second"} } | parts = { {term = "first"}, {separator = " +‎ ", term = "second"} } | ||
else | else | ||
error("You must provide at least one part.") | error("You must provide at least one part.") | ||
| Line 332: | Line 425: | ||
function export.circumfix(frame) | function export.circumfix(frame) | ||
local function extra_params(params) | local function extra_params(params) | ||
params.nocat = | params.nocat = boolean_param | ||
params.force_cat = | params.force_cat = boolean_param | ||
end | end | ||
| Line 363: | Line 456: | ||
function export.confix(frame) | function export.confix(frame) | ||
local function extra_params(params) | local function extra_params(params) | ||
params.nocat = | params.nocat = boolean_param | ||
params.force_cat = | params.force_cat = boolean_param | ||
end | end | ||
| Line 393: | Line 486: | ||
function export.pseudo_loan(frame) | function export.pseudo_loan(frame) | ||
local function extra_params(params) | local function extra_params(params) | ||
params.notext = | params.notext = boolean_param | ||
params.nocat = | params.nocat = boolean_param | ||
params.force_cat = | params.force_cat = boolean_param | ||
end | end | ||
| Line 406: | Line 499: | ||
-- necessary? | -- necessary? | ||
require_index_for_pos = true, | require_index_for_pos = true, | ||
allow_semicolon_separator = true, | |||
} | } | ||
| Line 415: | Line 509: | ||
function export.infix(frame) | function export.infix(frame) | ||
local function extra_params(params) | local function extra_params(params) | ||
params.nocat = | params.nocat = boolean_param | ||
params.force_cat = | params.force_cat = boolean_param | ||
end | end | ||
| Line 444: | Line 538: | ||
function export.prefix(frame) | function export.prefix(frame) | ||
local function extra_params(params) | local function extra_params(params) | ||
params.nocat = | params.nocat = boolean_param | ||
params.force_cat = | params.force_cat = boolean_param | ||
end | end | ||
| Line 480: | Line 574: | ||
function export.suffix(frame) | function export.suffix(frame) | ||
local function extra_params(params) | local function extra_params(params) | ||
params.nocat = | params.nocat = boolean_param | ||
params.force_cat = | params.force_cat = boolean_param | ||
end | end | ||
| Line 523: | Line 617: | ||
} | } | ||
local derivtype = iargs.derivtype | local derivtype = iargs.derivtype | ||
params[1] = {required = "true", type = "language", default = "und"} | |||
params[2] = {} | |||
local args = require("Module:parameters").process(frame:getParent().args, params) | local args = require("Module:parameters").process(frame:getParent().args, params) | ||
local lang | local lang = args[1] | ||
local term = args[2] or args.head | |||
local id = args.id | local id = args.id | ||
local sc = args.sc | local sc = args.sc | ||
local pos = require( | local pos = require(en_utilities_module).pluralize(args.pos or "term") | ||
if not term then | if not term then | ||
local SUBPAGE = mw. | local SUBPAGE = mw.loadData("Module:headword/data").pagename | ||
if lang:hasType("reconstructed") or mw.title.getCurrentTitle().nsText == "Reconstruction" then | if lang:hasType("reconstructed") or mw.title.getCurrentTitle().nsText == "Reconstruction" then | ||
term = "*" .. SUBPAGE | term = "*" .. SUBPAGE | ||
| Line 560: | Line 637: | ||
term = SUBPAGE | term = SUBPAGE | ||
end | end | ||
end | end | ||
| Line 577: | Line 647: | ||
elseif derivtype == "compound" then | elseif derivtype == "compound" then | ||
category = langname .. " compound " .. pos .. " with " .. term | category = langname .. " compound " .. pos .. " with " .. term | ||
elseif derivtype == "classifier" then | |||
category = langname .. " " .. pos .. " classified by " .. term | |||
else | else | ||
category = langname .. " " .. pos .. " " .. derivtype .. "ed with " .. term .. (id and " (" .. id .. ")" or "") | category = langname .. " " .. pos .. " " .. derivtype .. "ed with " .. term .. (id and " (" .. id .. ")" or "") | ||