This module is used to show headword lines, along with any annotations like genders, transliterations and inflections. It's used by the template {{head}}
, via the submodule Module:headword/templates.
This is the primary external entry point. NOTE: The values passed in below will be destructively modified. You are warned.
function export.full_headword(lang, sc, heads, translits, genders, inflections, categories, sort_key)
This is used to display an entire headword line, such as will be displayed by {{head}}
or various language-specific headword templates (e.g. {{ru-adj}}
for Russian adjectives, {{de-noun}}
for German nouns, etc.). Arguments are as follows (WARNING: they will be destructively modified):
lang
is required and is a language object corresponding to a given language. Use e.g. require("Module:languages").getByCode("ru")
to retrieve the object corresponding to Russian.sc
is a script object corresponding to a given script. Most of the time you can pass in nil
.heads
is a table listing the heads of the headword, each of which is a string. An empty string means to use a default head based on the page name. It is also possible to pass in a single string for a single headword, or nil
, which is equivalent to passing in a single empty string (i.e. only one head, based on the page name).translits
is a table listing the transliterations corresponding to each headword in heads
. The Nth numbered entry should be either a string specifying the transliteration of headword N, or nil
for no transliteration (for some languages, this means to generate an automatic transliteration, and "-" will have to be passed in to suppress the transliteration entirely). It is also possible to pass in a single string (equivalent to a one-element list) or nil
(equivalent to a no-element list). Note that, if there are multiple headwords, the table in translits
might have entries in the middle of the list that are nil
. A list of this sort cannot be created with table.insert()
, as attempting to insert nil
this way does nothing. Instead, the correct numbered entries will have to be directly assigned to.genders
is a table listing the gender/number strings for the headwords. This can be nil
for no genders/numbers. The individual gender/number strings are as in Module:gender and number. See format_genders
below for an example of this argument (it has the same format as the data.genders
argument to that function).inflections
is a table listing the inflections to be displayed in the headword entry. The format of this table is somewhat complex and is described below under format_inflections
(it has the same format as the data.inflections
argument to that function).categories
is a table listing the categories to which the page containing the headword belongs. The first category should be a part-of-speech category (e.g. "Russian adjectives"
).sort_key
is a string specifying a sort key for the categories listed in categories
, or nil
to use a default sort key based on the page name. This is used to ensure that the page is listed in the correct order in the categories to which it belongs. See format_categories()
in Module:utilities for more information.full_headword(
require("Module:languages").getByCode("en"), -- language code
nil, -- no script
{"book"}, -- headwords
nil, -- no translit
nil, -- no gender
{
{label = "plural", "books"} -- inflections
},
{"English nouns"} -- categories
)
might give (depending on the page it's run on):
<strong class="Latn headword" lang="en">book</strong> ‎(''plural'' <b class="Latn" lang="en">]</b>)]]
which displays as:
full_headword(
require("Module:languages").getByCode("de"),
nil,
{"Hund"},
nil,
{"m"},
{
{label = "genitive", "Hundes", "Hunds"},
{label = "plural", "] </b>''or (nonstandard)''<b> ]"},
{label = "diminutive",
{term = "Hündchen", genders = {"n"}},
{nolink=true, term = "Hündlein", genders = {"n"}}
}
},
{"German nouns"}
)
might give (depending on the page it's run on):
<strong class="Latn headword" lang="de">Hund</strong> <span class="gender"><abbr title="masculine gender">m</abbr></span> ‎(''genitive'' <b class="Latn" lang="de">]</b> ''or'' <b class="Latn" lang="de">]</b>, ''plural'' <b class="Latn" lang="de">] </b>''or (nonstandard)''<b> ]</b>, ''diminutive'' <b class="Latn" lang="de">]</b> <span class="gender"><abbr title="neuter gender">n</abbr></span> ''or'' <b class="Latn" lang="de">Hündlein</b> <span class="gender"><abbr title="neuter gender">n</abbr></span>)]]
which displays as:
This example is in Russian, which has automatic transliteration:
full_headword(
require("Module:languages").getByCode("ru"),
nil,
{"кни́га"},
nil,
{"f-in"},
{
{label = "genitive", "кни́ги"},
{label = "nominative plural", "кни́ги"},
{label = "genitive plural", "книг"}
},
{"Russian nouns"}
)
might give (depending on the page it's run on):
<strong class="Cyrl headword" lang="ru">кни́га</strong> ] ‎(<span class="tr" lang=""><span class="tr" lang="">kníga</span></span>) <span class="gender"><abbr title="feminine gender">f</abbr> <abbr title="inanimate">inan</abbr></span> ‎(''genitive'' <b class="Cyrl" lang="ru">]</b>, ''nominative plural'' <b class="Cyrl" lang="ru">]</b>, ''genitive plural'' <b class="Cyrl" lang="ru">]</b>)]]
which displays as
This example is in Russian, with two headwords, each of which requires manual transliteration:
full_headword(
require("Module:languages").getByCode("ru"),
nil,
{"интервьюе́р", "интервью́ер"},
{"intɛrvʹjuér", "intɛrvʹjújer"},
{"m-an"},
{
{label = "genitive", "интервьюе́ра", "интервью́ера"},
{label = "nominative plural", "интервьюе́ры", "интервью́еры"},
{label = "genitive plural", "интервьюе́ров", "интервью́еров"},
},
{"Russian nouns"}
)
might give (depending on the page it's run on):
<strong class="Cyrl headword" lang="ru">интервьюе́р</strong> ''or'' <strong class="Cyrl headword" lang="ru">интервью́ер</strong> ] ‎(<span class="tr" lang=""><span class="tr" lang="">intɛrvʹjuér</span> ''or'' <span class="tr" lang="">intɛrvʹjújer</span></span>) <span class="gender"><abbr title="masculine gender">m</abbr> <abbr title="animate">anim</abbr></span> ‎(''genitive'' <b class="Cyrl" lang="ru">]</b> ''or'' <b class="Cyrl" lang="ru">]</b>, ''nominative plural'' <b class="Cyrl" lang="ru">]</b> ''or'' <b class="Cyrl" lang="ru">]</b>, ''genitive plural'' <b class="Cyrl" lang="ru">]</b> ''or'' <b class="Cyrl" lang="ru">]</b>)]]
which displays as
This example is in Arabic, with embedded links in the headword and manual transliteration in an inflection (note that Arabic also has automatic transliteration, and is one of the languages that will display automatic transliterations of inflections in the headword, unlike e.g. Russian):
full_headword(
require("Module:languages").getByCode("ar"),
nil,
{"] ] ]"},
{"ḡudda baṣaliyya ʾiḥlīliyya"},
{"f"},
{
{label = "plural", {term="غُدَد بَصَلِيَّة إِحْلِيلِيَة", translit="ḡudad baṣaliyya ʾiḥlīliyya"}},
},
{"Arabic nouns"}
)
might give (depending on the page it's run on):
<strong class="Arab headword" lang="ar">] ] ]</strong> ] ‎(<span class="tr" lang=""><span class="tr" lang="">ḡudda baṣaliyya ʾiḥlīliyya</span></span>) <span class="gender"><abbr title="feminine gender">f</abbr></span> ‎(''plural'' <b class="Arab" lang="ar">]</b> ‎(<span lang="" class="tr">ḡudad baṣaliyya ʾiḥlīliyya</span>))]]
which displays as
format_headword(heads, lang, sc)
Formats a headword, using the format appropriate for the given language object and script (see Module:script utilities#tag_text
).
The heads
parameter can either be a single string or a table of strings. If it's a table, then each string in the table is shown as a headword, separated by "or". This allows you to show multiple alternative headwords, such as when the same written form can be accented in different ways.
It has special behaviour in certain cases as well:
heads
parameter contains wikilinks, they are converted into language-section links for the given language (using Module:links#language_link
, which is also used by {{l}}
). For example, giving "] ]"
if the language provided is English will produce: ] ]
. If string is prefixed with * or if any of the links are, then they are interpreted as reconstructed terms and it will create links to the appendix namespace as appropriate.heads
is empty (nil
or the empty table), it will default to mw.title.getCurrentTitle().subpageText
(equivalent to {{SUBPAGENAME}}
in templates).
appendix-constructed
, then a * will be prepended to the headword to indicate that it is a reconstructed term.format_transliteration(tr, lang)
] (<span lang="">foo</span>)which looks like “• (foo)”.
(Note: the bullet/link is only added if the linked-to page actually exists.)
NOTE: This documentation is up-to-date. Keep in mind, however, that this function is not currently exported, and the contents of the argument data
will be overwritten.
format_genders(data)
Format gender specifications using Module:gender and number. For example:
format_genders({genders = {"m-in", "m-an-p"},
lang=require("Module:languages").getByCode("ru")})
gives:
<span class="gender"><abbr title="masculine gender">m</abbr> <abbr title="inanimate">inan</abbr>, <abbr title="masculine gender">m</abbr> <abbr title="animate">anim</abbr> <abbr title="plural number">pl</abbr></span>
displays as:
The argument is a table, consisting of elements .genders
and .lang
. NOTE: The table will be overwritten!!!
The value of .genders
is a list of gender/number strings, in the form required by Module:gender and number.
NOTE: This documentation is up-to-date. Keep in mind, however, that this function is not currently exported, and the contents of the argument data
will be overwritten.
format_inflections(data)
Format a list (table) of inflections, which are then concatenated together with commas and surrounded by parentheses. For example:
format_inflections({inflections = {
{label = "diminutive", "Hündchen"}
}, lang=require("Module:languages").getByCode("de")})
gives:
‎(''diminutive'' <b class="Latn" lang="de">]</b>)
displays as:
The argument is a table, consisting of elements .inflections
, .lang
, and optionally .sc
. NOTE: The table will be overwritten!!!
The value of .inflections
is a list of labeled inflections, each of which is a table:
.label
value which contains the label. It is displayed in italics and not linked..accel
value. This value is used to support accelerated entry creation using WT:ACCEL. The "form-of" and "lang-(code)" classes are added automatically, so only the "(form)-form-of" class needs to be given, along with any other classes that may be needed.Module:links#language_link
, just like in format_headword
..label
, then just the label is shown with no forms. If there is more than one form, they are shown with "or" between them.For example:
format_inflections({inflections = {
{label = "present", "krama"},
{label = "past", "kramade"},
{label = "past participle", "kramat"}
}, lang=require("Module:languages").getByCode("sv")})
format_inflections({inflections = {
{label = "plural", accel = "plural-form-of", "voorbeelden"},
}, lang=require("Module:languages").getByCode("nl")})
gives:
‎(''present'' <b class="Latn" lang="sv">]</b>, ''past'' <b class="Latn" lang="sv">]</b>, ''past participle'' <b class="Latn" lang="sv">]</b>) ‎(''plural'' <span class="form-of lang-nl plural-form-of "><b class="Latn" lang="nl">]</b></span>)
displays as:
It is also possible, but optional, to supply a table instead of a term. This table can contain the keys .term
(the actual term), .alt
(alternative display form), .sc
(script), .id
(sense id), .genders
(list of genders), .nolink
(if true, the function will not link to the term, but only display it boldfaced), .hypothetical
(if true, the function will not link to the term, but display it italicized and preceded by a *), .accel
(same as .accel
in the outer table but applies only to the given term; if both accelerators are specified, both will appear as CSS classes). Most of these are used the same way as for full_link
in Module:links, and are passed directly to it.
Example:
format_inflections({inflections = {
{label = "diminutive",
{term = "Hündchen", genders = {"n"}},
{nolink=true, term = "Hündlein", genders = {"n"}}
}}, lang=require("Module:languages").getByCode("de")})
gives:
‎(''diminutive'' <b class="Latn" lang="de">]</b> <span class="gender"><abbr title="neuter gender">n</abbr></span> ''or'' <b class="Latn" lang="de">Hündlein</b> <span class="gender"><abbr title="neuter gender">n</abbr></span>)
displays as:
local export = {}
local lemmas = {
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
}
local nonlemmas = {
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
}
local notranslit = {
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
= true,
}
local function preprocess(data)
if type(data.heads) ~= "table" then
data.heads = {data.heads}
end
if type(data.translits) ~= "table" then
data.translits = {data.translits}
end
if #data.heads == 0 then
data.heads = {""}
end
-- Create a default headword.
local default_head = mw.title.getCurrentTitle().subpageText
-- Determine if term is reconstructed
local is_reconstructed = data.lang:getType() == "reconstructed" or mw.title.getCurrentTitle().nsText == "Reconstruction"
-- Add links to multi-word page names when appropriate
if data.lang:getCode() ~= "zh" then
local WORDBREAKCHARS = "(+)"
local EXCLUDECHARS = "(+)" -- workaround for excluding characters from the above
local contains_words = false; mw.ustring.gsub(default_head, WORDBREAKCHARS, function(b) contains_words = contains_words or mw.ustring.match(b, "^" .. EXCLUDECHARS .. "$"); end)
if (not is_reconstructed) and contains_words then
local function workaround_to_exclude_chars(s)
return mw.ustring.gsub(s, EXCLUDECHARS, "]]%1[[")
end
default_head = "]"
-- default_head = "]%1]" -- use this when workaround is no longer needed
default_head = mw.ustring.gsub(default_head, "%%]", "") -- remove any empty links (which could have been created above at the beginning or end of the string)
end
end
if is_reconstructed then
default_head = "*" .. default_head
end
-- If a head is the empty string "", then replace it with the default
for i, head in ipairs(data.heads) do
if head == "" then
head = default_head
else
if head == default_head and data.lang:getCanonicalName() == "English" then
table.insert(data.categories, data.lang:getCanonicalName() .. " terms with redundant head parameter")
end
end
data.heads = head
end
-- Try to detect the script if it was not provided
-- We use the first headword for this, and assume that all of them have the same script
-- This *should* always be true, right?
if not data.sc then
data.sc = require("Module:scripts").findBestScript(data.heads, data.lang)
end
-- Make transliterations
for i, head in ipairs(data.heads) do
local translit = data.translits
-- Try to generate a transliteration if necessary
-- Generate it if the script is not Latn or similar, and if no transliteration was provided
if translit == "-" then
translit = nil
elseif not translit and not ((data.sc:getCode():find("Latn", nil, true)) or data.sc:getCode() == "Latinx" or data.sc:getCode() == "None") and (not data.sc or data.sc:getCode() ~= "Imag") then
translit = data.lang:transliterate(require("Module:links").remove_links(head), data.sc)
-- There is still no transliteration?
-- Add the entry to a cleanup category.
if not translit and not notranslit then
translit = "<small>transliteration needed</small>"
table.insert(data.categories, data.lang:getCanonicalName() .. " terms needing transliteration")
end
end
-- Link to the transliteration entry for languages that require this
if translit and data.lang:link_tr() then
translit = require("Module:links").full_link({term = translit, lang = data.lang, sc = require("Module:scripts").getByCode("Latn"), tr = "-"})
end
data.translits = translit
end
end
-- Format a headword with transliterations
local function format_headword(data)
local m_links = require("Module:links")
local m_scriptutils = require("Module:script utilities")
-- Are there non-empty transliterations?
-- Need to do it this way because translit might be nil while translit is not
local has_translits = false
-- Format the headwords
for i, head in ipairs(data.heads) do
if data.translits then
has_translits = true
end
-- Apply processing to the headword, for formatting links and such
if head:find("[[", nil, true) and (not data.sc or data.sc:getCode() ~= "Imag") then
head = m_links.language_link({term = head, lang = data.lang}, false)
end
-- Add language and script wrapper
head = m_scriptutils.tag_text(head, data.lang, data.sc, "head")
data.heads = head
end
local translits_formatted = ""
if has_translits then
-- Format the transliterations
for i, head in ipairs(data.heads) do
local translit = data.translits
if not translit then
translit = "?"
end
translit = "<span class=\"tr\" lang=\"\">" .. translit .. "</span>"
data.translits = translit
end
translits_formatted = " (<span class=\"tr\" lang=\"\">" .. table.concat(data.translits, " ''or'' ") .. "</span>)"
if mw.title.new(data.lang:getCanonicalName() .. " transliteration", "Wiktionary").exists then
translits_formatted = " ]" .. translits_formatted
end
end
return table.concat(data.heads, " ''or'' ") .. translits_formatted
end
local function format_genders(data)
if data.genders and #data.genders > 0 then
local gen = require("Module:gender and number")
return " " .. gen.format_list(data.genders, data.lang)
else
return ""
end
end
local function format_inflection_parts(data, parts)
local m_links = require("Module:links")
for key, part in ipairs(parts) do
if type(part) ~= "table" then
part = {term = part}
end
local qualifiers = ""
if part.qualifiers and #part.qualifiers > 0 then
qualifiers = mw.getCurrentFrame():expandTemplate{title = "qualifier", args = part.qualifiers} .. " "
end
local partaccel = part.accel
local face = part.hypothetical and "hypothetical" or "bold"
local nolink = part.hypothetical or part.nolink
-- Convert the term into a full link
-- Don't show a transliteration here, the consensus seems to be not to
-- show them in headword lines to avoid clutter.
part = m_links.full_link({term = not nolink and part.term or nil, alt = part.alt or (nolink and part.term or nil), lang = part.lang or data.lang, sc = part.sc or (not part.lang and data.sc), id = part.id, genders = part.genders, tr = part.translit or ((not (parts.enable_auto_translit or data.lang:getCode() == "ar")) and "-" or nil)}, face, false)
if parts.accel or partaccel then
part = "<span class=\"form-of lang-" .. data.lang:getCode() .. " " .. (parts.accel or "") .. " " .. (partaccel or "") .. "\">" .. part .. "</span>"
end
part = qualifiers .. part
parts = part
end
local parts_output = ""
if #parts > 0 then
parts_output = " " .. table.concat(parts, " ''or'' ")
elseif parts.request then
parts_output = " <small></small>" .. require("Module:utilities").format_categories({data.lang:getCanonicalName() .. " entries needing inflection"}, lang, nil, nil, data.force_cat_output)
end
return "''" .. parts.label .. "''" .. parts_output
end
-- Format the inflections following the headword
local function format_inflections(data)
if data.inflections and #data.inflections > 0 then
-- Format each inflection individually
for key, infl in ipairs(data.inflections) do
data.inflections = format_inflection_parts(data, infl)
end
return " (" .. table.concat(data.inflections, ", ") .. ")"
else
return ""
end
end
function export.show_headword_line(data)
-- Check the namespace against the language type
if mw.title.getCurrentTitle().nsText == "" then
if data.lang:getType() == "reconstructed" then
error("Entries for this language must be placed in the Reconstruction: namespace.")
elseif data.lang:getType() == "appendix-constructed" then
error("Entries for this language must be placed in the Appendix: namespace.")
end
end
data.categories = {}
local tracking_categories = {}
-- Is it a lemma category?
if lemmas or lemmas then
table.insert(data.categories, data.lang:getCanonicalName() .. " lemmas")
-- Is it a nonlemma category?
elseif nonlemmas or nonlemmas or lemmas or nonlemmas then
table.insert(data.categories, data.lang:getCanonicalName() .. " non-lemma forms")
-- It's neither; we don't know what this category is, so tag it with a tracking category.
else
table.insert(tracking_categories, "head tracking/unrecognized pos")
require("Module:debug").track("head tracking/unrecognized pos")
require("Module:debug").track("head tracking/unrecognized pos/lang/" .. data.lang:getCode())
require("Module:debug").track("head tracking/unrecognized pos/pos/" .. data.pos_category)
end
table.insert(data.categories, data.lang:getCanonicalName() .. " " .. data.pos_category)
-- Preprocess
preprocess(data)
local m_links = require("Module:links")
if data.lang:getType() ~= "reconstructed" then
for _, head in ipairs(data.heads) do
if mw.title.getCurrentTitle().prefixedText ~= m_links.getLinkPage(m_links.remove_links(head), data.lang) then
require("Module:debug").track("headword/pagename spelling mismatch")
require("Module:debug").track("headword/pagename spelling mismatch/" .. data.lang:getCode())
break
end
end
end
-- Format and return all the gathered information
return
format_headword(data) ..
format_genders(data) ..
format_inflections(data) ..
require("Module:utilities").format_categories(data.categories, data.lang, data.sort_key, nil, data.force_cat_output) ..
require("Module:utilities").format_categories(tracking_categories, data.lang, data.sort_key, nil, data.force_cat_output)
end
function export.full_headword(lang, sc, heads, translits, genders, inflections, categories, sort_key, force_cat_output)
local data = {lang = lang, sc = sc, heads = heads, translits = translits, genders = genders, inflections = inflections, pos_category = nil, sort_key = sort_key, force_cat_output = force_cat_output}
local tracking_categories = {}
categories = categories or error('No categories were supplied to the function "full_headword".')
-- Were any categories specified?
if #categories == 0 then
if lang:getCode() ~= "und" then
table.insert(tracking_categories, "head tracking/no pos")
require("Module:debug").track("head tracking/no pos")
require("Module:debug").track("head tracking/no pos/lang/" .. lang:getCode())
end
else
for _, cat in ipairs(categories) do
-- Does the category begin with the language name? If not, tag it with a tracking category.
if mw.ustring.sub(cat, 1, mw.ustring.len(lang:getCanonicalName()) + 1) ~= lang:getCanonicalName() .. " " then
table.insert(tracking_categories, "head tracking/no lang category")
require("Module:debug").track("head tracking/no lang category")
require("Module:debug").track("head tracking/no lang category/lang/" .. lang:getCode())
end
end
if mw.ustring.sub(categories, 1, mw.ustring.len(lang:getCanonicalName() .. " ")) == lang:getCanonicalName() .. " " then
data.pos_category = mw.ustring.sub(categories, mw.ustring.len(lang:getCanonicalName()) + 2)
table.remove(categories, 1)
end
end
if not data.pos_category then
error('No valid part-of-speech categories were found in the list of categories passed to the function "full_headword". The part-of-speech category should consist of a language\'s canonical name plus a part of speech.')
end
local standard = data.lang:getStandardCharacters()
if standard then
if mw.ustring.len(mw.title.getCurrentTitle().subpageText) ~= 1 then
for character in mw.ustring.gmatch(mw.title.getCurrentTitle().subpageText, "()") do
table.insert(categories, lang:getCanonicalName() .. " terms spelled with " .. mw.ustring.upper(character))
end
end
end
if mw.title.getCurrentTitle().nsText ~= "Reconstruction" and require('Module:palindromes').is_palindrome(mw.title.getCurrentTitle().subpageText, lang, sc) then
table.insert(categories, lang:getCanonicalName() .. " palindromes")
end
return
export.show_headword_line(data) ..
require("Module:utilities").format_categories(categories, data.lang, data.sort_key, nil, data.force_cat_output) ..
require("Module:utilities").format_categories(tracking_categories, data.lang, data.sort_key, nil, data.force_cat_output)
end
return export