Module:links: Difference between revisions
No edit summary |
No edit summary |
||
| Line 14: | Line 14: | ||
local anchors_module = "Module:anchors" | local anchors_module = "Module:anchors" | ||
local form_of_module = "Module:form of" | |||
local gender_and_number_module = "Module:getn" | local gender_and_number_module = "Module:getn" | ||
local languages_module = "Module:languages" | local languages_module = "Module:languages" | ||
| Line 42: | Line 43: | ||
local unstrip = mw.text.unstrip | local unstrip = mw.text.unstrip | ||
local NAMESPACE = get_current_title(). | local NAMESPACE = get_current_title().nsText | ||
local function anchor_encode(...) | local function anchor_encode(...) | ||
| Line 169: | Line 170: | ||
-- Unconditionally trimmed charset. | -- Unconditionally trimmed charset. | ||
local always_trim = | local always_trim = | ||
"\194\128-\194\159" .. | "\194\128-\194\159" .. -- U+0080-009F (C1 control characters) | ||
"\194\173" .. | "\194\173" .. -- U+00AD (soft hyphen) | ||
"\226\128\170-\226\128\174" .. -- U+202A-202E (directionality formatting characters) | "\226\128\170-\226\128\174" .. -- U+202A-202E (directionality formatting characters) | ||
"\226\129\166-\226\129\169" | "\226\129\166-\226\129\169" -- U+2066-2069 (directionality formatting characters) | ||
-- Standard trimmed charset. | -- Standard trimmed charset. | ||
local standard_trim = "%s" .. | local standard_trim = "%s" .. -- (default whitespace charset) | ||
"\226\128\139-\226\128\141" .. -- U+200B-200D (zero-width spaces) | "\226\128\139-\226\128\141" .. -- U+200B-200D (zero-width spaces) | ||
always_trim | always_trim | ||
| Line 234: | Line 235: | ||
function export.get_wikilink_parts(text, allow_bad_target) | function export.get_wikilink_parts(text, allow_bad_target) | ||
-- TODO: replace `allow_bad_target` with `allow_unsupported`, with support for links to unsupported titles, including escape sequences. | -- TODO: replace `allow_bad_target` with `allow_unsupported`, with support for links to unsupported titles, including escape sequences. | ||
if ( -- Filters out anything but "[[...]]" with no intermediate "[[" or "]]". | if ( -- Filters out anything but "[[...]]" with no intermediate "[[" or "]]". | ||
not match(text, "^()%[%[") or -- Faster than sub(text, 1, 2) ~= "[[". | |||
find(text, "[[", 3, true) or | |||
find(text, "]]", 3, true) ~= #text - 1 | |||
) then | |||
return nil, nil | return nil, nil | ||
end | end | ||
| Line 255: | Line 256: | ||
if title == nil then | if title == nil then | ||
return nil, nil | return nil, nil | ||
-- If the link target starts with "#" then mw.title.new returns a broken | |||
-- title object, so grab the current title and give it the correct fragment. | |||
elseif title.prefixedText == "" then | elseif title.prefixedText == "" then | ||
local fragment = title.fragment | local fragment = title.fragment | ||
| Line 292: | Line 293: | ||
if not close then | if not close then | ||
return get_fragment(text) | return get_fragment(text) | ||
-- If there is one, but it's redundant (i.e. encloses everything with no pipe), remove and process. | |||
elseif open == 1 and close == #text - 1 and not find(text, "|", 3, true) then | elseif open == 1 and close == #text - 1 and not find(text, "|", 3, true) then | ||
return get_fragment(sub(text, 3, -3)) | return get_fragment(sub(text, 3, -3)) | ||
| Line 316: | Line 317: | ||
return nil | return nil | ||
end | end | ||
target = remove_formatting(target) | target = remove_formatting(target) | ||
if target:sub(1, 1) == ":" then | if target:sub(1, 1) == ":" then | ||
-- FIXME, the auto_display (second return value) should probably remove the colon | -- FIXME, the auto_display (second return value) should probably remove the colon | ||
return target:sub(2), orig_target | return target:sub(2), orig_target | ||
end | end | ||
local prefix = target:match("^(.-):") | local prefix = target:match("^(.-):") | ||
-- Convert any escaped colons | -- Convert any escaped colons | ||
target = target:gsub("\\:", ":") | target = target:gsub("\\:", ":") | ||
if prefix then | if prefix then | ||
-- If this is an a link to another namespace or an interwiki link, ensure there's an initial colon and then return what we have (so that it works as a conventional link, and doesn't do anything weird like add the term to a category.) | -- If this is an a link to another namespace or an interwiki link, ensure there's an initial colon and then | ||
-- return what we have (so that it works as a conventional link, and doesn't do anything weird like add the term | |||
-- to a category.) | |||
prefix = ulower(trim(prefix)) | prefix = ulower(trim(prefix)) | ||
if prefix ~= "" and ( | if prefix ~= "" and ( | ||
load_data("Module:data/namespaces")[prefix] or | |||
load_data("Module:data/interwikis")[prefix] | |||
) then | |||
return target, orig_target | return target, orig_target | ||
end | end | ||
end | end | ||
-- Check if the term is reconstructed and remove any asterisk. Also check for anti-asterisk (!!). | -- Check if the term is reconstructed and remove any asterisk. Also check for anti-asterisk (!!). | ||
-- Otherwise, handle the escapes. | -- Otherwise, handle the escapes. | ||
| Line 354: | Line 357: | ||
end | end | ||
target, escaped = target:gsub("^(\\-)\\%*", "%1*") | target, escaped = target:gsub("^(\\-)\\%*", "%1*") | ||
if reconstructed == 0 and lang:hasType("reconstructed") and not lang:hasType("conlang") then | if reconstructed == 0 and lang:hasType("reconstructed") and not lang:hasType("conlang") then | ||
orig_target = "*" .. target | orig_target = "*" .. target | ||
reconstructed = 1 | reconstructed = 1 | ||
end | end | ||
if not (sc and sc:getCode() ~= "None") then | if not (sc and sc:getCode() ~= "None") then | ||
sc = lang:findBestScript(target) | sc = lang:findBestScript(target) | ||
| Line 372: | Line 375: | ||
-- Get the entry name for the language. | -- Get the entry name for the language. | ||
target = lang:makeEntryName(target, sc) | target = lang:makeEntryName(target, sc, reconstructed == 1 or lang:hasType("appendix-constructed")) | ||
-- If the link contains unexpanded template parameters, then don't create a link. | -- If the link contains unexpanded template parameters, then don't create a link. | ||
| Line 401: | Line 404: | ||
target = (lang:hasType("conlang") and "Contionary:" or "wikt:") .. target | target = (lang:hasType("conlang") and "Contionary:" or "wikt:") .. target | ||
return target, orig_target, escaped > 0 | return target, orig_target, escaped > 0 | ||
end | end | ||
| Line 437: | Line 440: | ||
auto_display = auto_display:gsub("\\([^\\]*%*)", "%1", 1) | auto_display = auto_display:gsub("\\([^\\]*%*)", "%1", 1) | ||
end | end | ||
-- Process the display form. | -- Process the display form. | ||
if link.display then | if link.display then | ||
| Line 448: | Line 451: | ||
-- If `no_alt_ast` is true, use pcall to catch the error which will be thrown if this is a reconstructed lang and the alt text doesn't have *. | -- If `no_alt_ast` is true, use pcall to catch the error which will be thrown if this is a reconstructed lang and the alt text doesn't have *. | ||
if link.display == auto_display then | if link.display == auto_display then | ||
insert(cats, lang:getFullName() .. " links with redundant alt parameters") | |||
else | else | ||
local ok, check | local ok, check | ||
| Line 455: | Line 459: | ||
ok = true | ok = true | ||
check = export.get_link_page(orig_display, lang, sc, plain) | check = export.get_link_page(orig_display, lang, sc, plain) | ||
end | |||
if ok and link.target == check then | |||
insert(cats, lang:getFullName() .. " links with redundant target parameters") | |||
end | end | ||
end | end | ||
| Line 461: | Line 468: | ||
link.display = lang:makeDisplayText(auto_display, sc) | link.display = lang:makeDisplayText(auto_display, sc) | ||
end | end | ||
if not link.target then | if not link.target then | ||
return link.display | return link.display | ||
end | end | ||
-- If the target is the same as the current page, there is no sense id | -- If the target is the same as the current page, there is no sense id | ||
-- and either the language code is "und" or the current L2 is the current | -- and either the language code is "und" or the current L2 is the current | ||
| Line 472: | Line 479: | ||
local fragment, current_L2 = link.fragment, get_current_L2() | local fragment, current_L2 = link.fragment, get_current_L2() | ||
if ( | if ( | ||
fragment and fragment == current_L2 or | |||
not (id or fragment) and (lang:getFullCode() == "und" or lang:getFullName() == current_L2) | |||
) then | |||
return tostring(mw.html.create("strong") | return tostring(mw.html.create("strong") | ||
:addClass("selflink") | :addClass("selflink") | ||
| Line 503: | Line 510: | ||
end | end | ||
end | end | ||
-- Put inward-facing square brackets around a link to isolated spacing character(s). | -- Put inward-facing square brackets around a link to isolated spacing character(s). | ||
if isolated and #link.display > 0 and not umatch(decode_entities(link.display), "%S") then | if isolated and #link.display > 0 and not umatch(decode_entities(link.display), "%S") then | ||
| Line 512: | Line 519: | ||
return m1 .. encode_entities(m2, "#%&+/:<=>@[\\]_{|}") | return m1 .. encode_entities(m2, "#%&+/:<=>@[\\]_{|}") | ||
end) | end) | ||
link.fragment = link.fragment and encode_entities(remove_formatting(link.fragment), "#%&+/:<=>@[\\]_{|}") | link.fragment = link.fragment and encode_entities(remove_formatting(link.fragment), "#%&+/:<=>@[\\]_{|}") | ||
return "[[" .. link.target:gsub("^[^:]", ":%0") .. (link.fragment and "#" .. link.fragment or "") .. "|" .. link.display .. "]]" | return "[[" .. | ||
link.target:gsub("^[^:]", ":%0") .. (link.fragment and "#" .. link.fragment or "") .. "|" .. link.display .. "]]" | |||
end | end | ||
| Line 520: | Line 528: | ||
-- Split a link into its parts | -- Split a link into its parts | ||
local function parse_link(linktext) | local function parse_link(linktext) | ||
local link = {target = linktext} | local link = { target = linktext } | ||
local target = link.target | local target = link.target | ||
| Line 531: | Line 539: | ||
-- There's no point in processing these, as they aren't real links. | -- There's no point in processing these, as they aren't real links. | ||
local target_lower = link.target:lower() | local target_lower = link.target:lower() | ||
for _, false_positive in ipairs({"category", "cat", "file", "image"}) do | for _, false_positive in ipairs({ "category", "cat", "file", "image" }) do | ||
if target_lower:match("^" .. false_positive .. ":") then | if target_lower:match("^" .. false_positive .. ":") then | ||
return nil | return nil | ||
| Line 576: | Line 584: | ||
text = text:gsub("^(\\-)\\%*", "%1*") | text = text:gsub("^(\\-)\\%*", "%1*") | ||
end | end | ||
check_params_ignored_when_embedded(alt, lang, id, cats) | check_params_ignored_when_embedded(alt, lang, id, cats) | ||
| Line 615: | Line 623: | ||
-- If the script uses ^ to capitalize transliterations, make sure that any carets preceding links are on the inside, so that they get processed with the following text. | -- If the script uses ^ to capitalize transliterations, make sure that any carets preceding links are on the inside, so that they get processed with the following text. | ||
if ( | if ( | ||
text:find("^", nil, true) and | |||
not sc:hasCapitalization() and | |||
sc:isTransliterated() | |||
) then | |||
text = escape(text, "^") | text = escape(text, "^") | ||
:gsub("%^\1", "\1%^") | :gsub("%^\1", "\1%^") | ||
| Line 641: | Line 649: | ||
lang, plain = get_lang("und"), true | lang, plain = get_lang("und"), true | ||
end | end | ||
-- Get the link target and display text. If the term is the empty string, treat the input as a link to the current page. | -- Get the link target and display text. If the term is the empty string, treat the input as a link to the current page. | ||
if term == "" then | if term == "" then | ||
| Line 663: | Line 671: | ||
end | end | ||
term, alt = new_term, new_alt | term, alt = new_term, new_alt | ||
if cats then | |||
if not (srwc and srwc(term, alt)) then | |||
insert(cats, lang:getFullName() .. " links with redundant wikilinks") | |||
end | |||
end | |||
end | end | ||
end | end | ||
| Line 676: | Line 689: | ||
return nil | return nil | ||
end | end | ||
-- If there is no script, get one. | -- If there is no script, get one. | ||
if not sc then | if not sc then | ||
sc = lang:findBestScript(alt or term) | sc = lang:findBestScript(alt or term) | ||
end | end | ||
-- Embedded wikilinks need to be processed individually. | -- Embedded wikilinks need to be processed individually. | ||
if term then | if term then | ||
| Line 726: | Line 739: | ||
function export.language_link(data) | function export.language_link(data) | ||
if type(data) ~= "table" then | if type(data) ~= "table" then | ||
error("The first argument to the function language_link must be a table. See Module:links/documentation for more information.") | error( | ||
"The first argument to the function language_link must be a table. See Module:links/documentation for more information.") | |||
end | end | ||
| Line 750: | Line 764: | ||
function export.plain_link(data) | function export.plain_link(data) | ||
if type(data) ~= "table" then | if type(data) ~= "table" then | ||
error("The first argument to the function plain_link must be a table. See Module:links/documentation for more information.") | error( | ||
"The first argument to the function plain_link must be a table. See Module:links/documentation for more information.") | |||
end | end | ||
| Line 769: | Line 784: | ||
function export.embedded_language_links(data) | function export.embedded_language_links(data) | ||
if type(data) ~= "table" then | if type(data) ~= "table" then | ||
error("The first argument to the function embedded_language_links must be a table. See Module:links/documentation for more information.") | error( | ||
"The first argument to the function embedded_language_links must be a table. See Module:links/documentation for more information.") | |||
end | end | ||
local term, lang, sc = data.term, data.lang, data.sc | local term, lang, sc = data.term, data.lang, data.sc | ||
-- If we don't have a script, get one. | -- If we don't have a script, get one. | ||
if not sc then | if not sc then | ||
sc = lang:findBestScript(term) | sc = lang:findBestScript(term) | ||
end | end | ||
-- Do we have embedded wikilinks? If so, they need to be processed individually. | -- Do we have embedded wikilinks? If so, they need to be processed individually. | ||
local open = find(term, "[[", nil, true) | local open = find(term, "[[", nil, true) | ||
| Line 784: | Line 800: | ||
return process_embedded_links(term, data.alt, lang, sc, data.id, data.cats, data.no_alt_ast) | return process_embedded_links(term, data.alt, lang, sc, data.id, data.cats, data.no_alt_ast) | ||
end | end | ||
-- If not, return the display text. | -- If not, return the display text. | ||
term = selective_trim(term) | term = selective_trim(term) | ||
-- FIXME: Double-escape any percent-signs, because we don't want to treat non-linked text as having percent-encoded characters. This is a hack: percent-decoding should come out of [[Module:languages]] and only dealt with in this module, as it's specific to links. | -- FIXME: Double-escape any percent-signs, because we don't want to treat non-linked text as having percent-encoded characters. This is a hack: percent-decoding should come out of [[Module:languages]] and only dealt with in this module, as it's specific to links. | ||
term = term:gsub("%%", "%%25") | term = term:gsub("%%", "%%25") | ||
return | return lang:makeDisplayText(term, sc, true) | ||
end | end | ||
| Line 815: | Line 831: | ||
tag = { '<span class="mention-gloss-paren annotation-paren">(</span>', | tag = { '<span class="mention-gloss-paren annotation-paren">(</span>', | ||
'<span class="mention-gloss-paren annotation-paren">)</span>' } | '<span class="mention-gloss-paren annotation-paren">)</span>' } | ||
elseif item_type == "infl" then | |||
tag = { '<span class="ann-infl">', '</span>' } | |||
end | end | ||
| Line 826: | Line 844: | ||
local pos_tags | local pos_tags | ||
--[==[Formats the annotations that are displayed with a link created by {{code|lua|full_link}}. Annotations are the extra bits of information that are displayed following the linked term, and include things such as gender, transliteration, gloss and so on. | --[==[Formats the annotations that are displayed with a link created by {{code|lua|full_link}}. Annotations are the extra bits of information that are displayed following the linked term, and include things such as gender, transliteration, gloss and so on. | ||
* The first argument is a table possessing some or all of the following keys: | * The first argument is a table possessing some or all of the following keys: | ||
*:; <code class="n">genders</code> | *:; <code class="n">genders</code> | ||
| Line 840: | Line 858: | ||
*:; <code class="n">lit</code> | *:; <code class="n">lit</code> | ||
*:: Literal meaning of the term, if the usual meaning is figurative or idiomatic. | *:: Literal meaning of the term, if the usual meaning is figurative or idiomatic. | ||
*:; <code class="n">infl</code> | |||
*:: Table containing a list of grammar tags in the style of [[Module:form of]] `tagged_inflections`. | |||
*:Any of the above values can be omitted from the <code class="n">info</code> argument. If a completely empty table is given (with no annotations at all), then an empty string is returned. | *:Any of the above values can be omitted from the <code class="n">info</code> argument. If a completely empty table is given (with no annotations at all), then an empty string is returned. | ||
* The second argument is a string. Valid values are listed in [[Module:script utilities/data]] "data.translit" table.]==] | * The second argument is a string. Valid values are listed in [[Module:script utilities/data]] "data.translit" table.]==] | ||
| Line 910: | Line 930: | ||
end | end | ||
insert(annotations, export.mark(pos or data.pos, "pos")) | insert(annotations, export.mark(pos or data.pos, "pos")) | ||
end | |||
-- Inflection data | |||
if data.infl then | |||
local m_form_of = require(form_of_module) | |||
-- Split tag sets manually, since tagged_inflections creates a numbered list, and we do not want that. | |||
local infl_outputs = {} | |||
local tag_sets = m_form_of.split_tag_set(data.infl) | |||
for _, tag_set in ipairs(tag_sets) do | |||
table.insert(infl_outputs, | |||
m_form_of.tagged_inflections({ tags = tag_set, lang = data.lang, nocat = true, nolink = true, nowrap = true })) | |||
end | |||
insert(annotations, export.mark(table.concat(infl_outputs, "; "), "infl")) | |||
end | end | ||
| Line 983: | Line 1,016: | ||
end | end | ||
local function get_class(lang, tr, accel) | local function insert_if_not_blank(list, item) | ||
if not accel then | if item == "" then | ||
return | |||
end | |||
insert(list, item) | |||
end | |||
local function get_class(lang, tr, accel, nowrap) | |||
if not accel and not nowrap then | |||
return "" | return "" | ||
end | end | ||
local | local classes = {} | ||
if accel then | |||
( | insert(classes, "form-of lang-" .. lang:getFullCode()) | ||
(encode_accel_param("gender-", accel.gender)) | local form = accel.form | ||
(encode_accel_param("pos-", accel.pos)) | if form then | ||
(encode_accel_param("transliteration-", accel.translit or (tr ~= "-" and tr or nil))) | insert(classes, encode_accel_param_chars(form) .. "-form-of") | ||
(encode_accel_param("target-", accel.target)) | end | ||
(encode_accel_param("origin-", accel.lemma)) | insert_if_not_blank(classes, encode_accel_param("gender-", accel.gender)) | ||
(encode_accel_param("origin_transliteration-", accel.lemma_translit)) | insert_if_not_blank(classes, encode_accel_param("pos-", accel.pos)) | ||
insert_if_not_blank(classes, encode_accel_param("transliteration-", accel.translit or (tr ~= "-" and tr or nil))) | |||
insert_if_not_blank(classes, encode_accel_param("target-", accel.target)) | |||
insert_if_not_blank(classes, encode_accel_param("origin-", accel.lemma)) | |||
insert_if_not_blank(classes, encode_accel_param("origin_transliteration-", accel.lemma_translit)) | |||
if accel.no_store then | |||
insert(classes, "form-of-nostore") | |||
end | |||
end | |||
if nowrap then | |||
insert(classes, nowrap) | |||
end | |||
return concat(classes, " ") | |||
end | end | ||
| Line 1,016: | Line 1,067: | ||
local q = data.q | local q = data.q | ||
if type(q) == "string" then | if type(q) == "string" then | ||
q = {q} | q = { q } | ||
end | end | ||
local qq = data.qq | local qq = data.qq | ||
if type(qq) == "string" then | if type(qq) == "string" then | ||
qq = {qq} | qq = { qq } | ||
end | end | ||
if q and q[1] or qq and qq[1] or data.a and data.a[1] or data.aa and data.aa[1] or data.l and data.l[1] or | if q and q[1] or qq and qq[1] or data.a and data.a[1] or data.aa and data.aa[1] or data.l and data.l[1] or | ||
data.ll and data.ll[1] or data.refs and data.refs[1] then | data.ll and data.ll[1] or data.refs and data.refs[1] then | ||
formatted = format_qualifiers{ | formatted = format_qualifiers { | ||
lang = data.lang, | lang = data.lang, | ||
text = formatted, | text = formatted, | ||
| Line 1,041: | Line 1,092: | ||
--[==[Creates a full link, with annotations (see | --[==[ | ||
The first argument, | Creates a full link, with annotations (see `[[#format_link_annotations|format_link_annotations]]`), in the style of {{tl|l}} or {{tl|m}}. | ||
The first argument, `data`, must be a table. It contains the various elements that can be supplied as parameters to {{tl|l}} or {{tl|m}}: | |||
{ { | { { | ||
term = entry_to_link_to, | term = entry_to_link_to, | ||
| Line 1,054: | Line 1,106: | ||
genders = { "gender1", "gender2", ... }, | genders = { "gender1", "gender2", ... }, | ||
tr = transliteration, | tr = transliteration, | ||
respect_link_tr = boolean, | |||
ts = transcription, | ts = transcription, | ||
gloss = gloss, | gloss = gloss, | ||
| Line 1,059: | Line 1,112: | ||
ng = non-gloss text, | ng = non-gloss text, | ||
lit = literal_translation, | lit = literal_translation, | ||
infl = { "form_of_grammar_tag1", "form_of_grammar_tag2", ... }, | |||
no_alt_ast = boolean, | no_alt_ast = boolean, | ||
accel = {accelerated_creation_tags}, | accel = {accelerated_creation_tags}, | ||
| Line 1,073: | Line 1,127: | ||
show_qualifiers = boolean, | show_qualifiers = boolean, | ||
} } | } } | ||
Any one of the items in the | Any one of the items in the `data` table may be {nil}, but an error will be shown if neither `term` nor `alt` nor `tr` | ||
Thus, calling { | is present. Thus, calling {full_link{ term = term, lang = lang, sc = sc }}, where `term` is the page to link to (which | ||
may have diacritics that will be stripped and/or embedded bracketed links) and `lang` is a | |||
[[Module:languages#Language objects|language object]] from [[Module:languages]], will give a plain link similar to the | |||
one produced by the template {{tl|l}}, and calling {full_link( { term = term, lang = lang, sc = sc }, "term" )} will | |||
give a link similar to the one produced by the template {{tl|m}}. | |||
The function will: | The function will: | ||
* Try to determine the script, based on the characters found in the term or alt argument, if the script was not given. If a script is given and | * Try to determine the script, based on the characters found in the `term` or `alt` argument, if the script was not | ||
* Call | given. If a script is given and `track_sc` is {true}, it will check whether the input script is the same as the one | ||
* Call | which would have been automatically generated and add the category [[:Category:LANG terms with redundant script codes]] | ||
* Generate a transliteration, based on the alt or term arguments, if the script is not Latin | if yes, or [[:Category:LANG terms with non-redundant manual script codes]] if no. This should be used when the input | ||
script object is directly determined by a template's `sc` parameter. | |||
* Call `[[#language_link|language_link]]` on the `term` or `alt` forms, to remove diacritics in the page name, process | |||
any embedded wikilinks and create links to Reconstruction or Appendix pages when necessary. | |||
* Call `[[Module:script utilities#tag_text]]` to add the appropriate language and script tags to the term and | |||
italicize terms written in the Latin script if necessary. Accelerated creation tags, as used by [[WT:ACCEL]], are | |||
included. | |||
* Generate a transliteration, based on the `alt` or `term` arguments, if the script is not Latin, no transliteration was | |||
provided in `tr` and the combination of the term's language and script support automatic transliteration. The | |||
transliteration itself will be linked if both `.respect_link_tr` is specified and the language of the term has the | |||
`link_tr` property set for the script of the term; but not otherwise. | |||
* Add the annotations (transliteration, gender, gloss, etc.) after the link. | * Add the annotations (transliteration, gender, gloss, etc.) after the link. | ||
* If | * If `no_alt_ast` is specified, then the `alt` text does not need to contain an asterisk if the language is | ||
* If | reconstructed. This should only be used by modules which really need to allow links to reconstructions that don't | ||
* If | display asterisks (e.g. number boxes). | ||
* If `pretext` or `posttext` is specified, this is text to (respectively) prepend or append to the output, directly | |||
before processing qualifiers, labels and references. This can be used to add arbitrary extra text inside of the | |||
qualifiers, labels and references. | |||
* If `show_qualifiers` is specified or the `show_qualifiers` argument is given, then left and right qualifiers, accent | |||
qualifiers, labels and references will be displayed, otherwise they will be ignored. (This is because a fair amount of | |||
code stores qualifiers, labels and/or references in these fields and displays them itself, rather than expecting | |||
{full_link()} to display them.)]==] | |||
function export.full_link(data, face, allow_self_link, show_qualifiers) | function export.full_link(data, face, allow_self_link, show_qualifiers) | ||
if type(data) ~= "table" then | if type(data) ~= "table" then | ||
error("The first argument to the function full_link must be a table. " | error("The first argument to the function full_link must be a table. " | ||
.. "See Module:links/documentation for more information.") | .. "See Module:links/documentation for more information.") | ||
end | end | ||
-- Prevent data from being destructively modified. | |||
local data = shallow_copy(data) | |||
-- FIXME: this shouldn't be added to `data`, as that means the input table needs to be cloned. | -- FIXME: this shouldn't be added to `data`, as that means the input table needs to be cloned. | ||
data.cats = {} | data.cats = {} | ||
-- Categorize links to "und". | -- Categorize links to "und". | ||
local lang, cats = data.lang, data.cats | local lang, cats = data.lang, data.cats | ||
| Line 1,102: | Line 1,178: | ||
end | end | ||
local terms = {true} | local terms = { true } | ||
-- Generate multiple forms if applicable. | -- Generate multiple forms if applicable. | ||
for _, param in ipairs{"term", "alt"} do | for _, param in ipairs { "term", "alt" } do | ||
if type(data[param]) == "string" and data[param]:find("//", nil, true) then | if type(data[param]) == "string" and data[param]:find("//", nil, true) then | ||
data[param] = export.split_on_slashes(data[param]) | data[param] = export.split_on_slashes(data[param]) | ||
elseif type(data[param]) == "string" and not (type(data.term) == "string" and data.term:find("//", nil, true)) then | elseif type(data[param]) == "string" and not (type(data.term) == "string" and data.term:find("//", nil, true)) then | ||
data[param] = lang:generateForms(data[param]) | if not data.no_generate_forms then | ||
data[param] = lang:generateForms(data[param]) | |||
else | |||
data[param] = { data[param] } | |||
end | |||
else | else | ||
data[param] = {} | data[param] = {} | ||
| Line 1,115: | Line 1,195: | ||
end | end | ||
for _, param in ipairs{"sc", "tr", "ts"} do | for _, param in ipairs { "sc", "tr", "ts" } do | ||
data[param] = {data[param]} | data[param] = { data[param] } | ||
end | end | ||
for _, param in ipairs{"term", "alt", "sc", "tr", "ts"} do | for _, param in ipairs { "term", "alt", "sc", "tr", "ts" } do | ||
for i in pairs(data[param]) do | for i in pairs(data[param]) do | ||
terms[i] = true | terms[i] = true | ||
end | end | ||
end | end | ||
-- Create the link | -- Create the link | ||
local output = {} | local output = {} | ||
local id, no_alt_ast, srwc, accel, nevercalltr = data.id, data.no_alt_ast, data.suppress_redundant_wikilink_cat, data.accel, data.never_call_transliteration_module | local id, no_alt_ast, srwc, accel, nevercalltr = data.id, data.no_alt_ast, data.suppress_redundant_wikilink_cat, | ||
data.accel, data.never_call_transliteration_module | |||
local link_tr = data.respect_link_tr and lang:link_tr(data.sc[1]) | |||
for i in ipairs(terms) do | for i in ipairs(terms) do | ||
| Line 1,138: | Line 1,220: | ||
-- no_nonstandard_sc_cat is intended for use in [[Module:interproject]] | -- no_nonstandard_sc_cat is intended for use in [[Module:interproject]] | ||
if ( | if ( | ||
not data.no_nonstandard_sc_cat and | |||
best:getCode() == "None" and | |||
find_best_script_without_lang(display_term):getCode() ~= "None" | |||
) then | |||
insert(cats, lang:getFullName() .. " terms in nonstandard scripts") | insert(cats, lang:getFullName() .. " terms in nonstandard scripts") | ||
end | end | ||
if not data.sc[i] then | if not data.sc[i] then | ||
data.sc[i] = best | data.sc[i] = best | ||
-- Track uses of sc parameter. | |||
elseif data.track_sc then | |||
if data.sc[i]:getCode() == best:getCode() then | |||
insert(cats, lang:getFullName() .. " terms with redundant script codes") | |||
else | |||
insert(cats, lang:getFullName() .. " terms with non-redundant manual script codes") | |||
end | |||
end | end | ||
| Line 1,170: | Line 1,259: | ||
if link then | if link then | ||
-- Add "nowrap" class to prefixes in order to prevent wrapping after the hyphen | -- Add "nowrap" class to prefixes in order to prevent wrapping after the hyphen | ||
local nowrap | local nowrap | ||
local display_term = data.alt[i] or data.term[i] | local display_term = data.alt[i] or data.term[i] | ||
if display_term and ( | if display_term and (display_term:find("^%-") or display_term:find("^־")) then -- Hebrew maqqef -- FIXME, use hyphens from [[Module:affix]] | ||
nowrap = " nowrap" | nowrap = "nowrap" | ||
end | end | ||
link = tag_text(link, lang, data.sc[i], face, get_class(lang, data.tr[i], accel) | link = tag_text(link, lang, data.sc[i], face, get_class(lang, data.tr[i], accel, nowrap)) | ||
else | else | ||
--[[ No term to show. | --[[ No term to show. | ||
| Line 1,187: | Line 1,276: | ||
remove(output) | remove(output) | ||
break | break | ||
elseif NAMESPACE ~= | elseif NAMESPACE ~= "Template" then | ||
insert(cats, lang:getFullName() .. " term requests") | insert(cats, lang:getFullName() .. " term requests") | ||
end | end | ||
| Line 1,197: | Line 1,286: | ||
end | end | ||
-- | -- When suppress_tr is true, do not show or generate any transliteration | ||
if data. | if data.suppress_tr then | ||
data.tr[1] = nil | data.tr[1] = nil | ||
else | else | ||
local phonetic_extraction = load_data("Module:links/data").phonetic_extraction | -- TODO: Currently only handles the first transliteration, pending consensus on how to handle multiple translits for multiple forms, as this is not always desirable (e.g. traditional/simplified Chinese). | ||
if data.tr[1] == "" or data.tr[1] == "-" then | |||
data.tr[1] = nil | |||
else | |||
local phonetic_extraction = load_data("Module:links/data").phonetic_extraction | |||
phonetic_extraction = phonetic_extraction[lang:getCode()] or phonetic_extraction[lang:getFullCode()] | |||
if phonetic_extraction then | |||
data.tr[1] = data.tr[1] or | |||
require(phonetic_extraction).getTranslit(export.remove_links(data.alt[1] or data.term[1])) | |||
elseif (data.term[1] or data.alt[1]) and data.sc[1]:isTransliterated() then | |||
-- Track whenever there is manual translit. The categories below like 'terms with redundant transliterations' | |||
-- aren't sufficient because they only work with reference to automatic translit and won't operate at all in | |||
-- languages without any automatic translit, like Persian and Hebrew. | |||
if data.tr[1] then | |||
local full_code = lang:getFullCode() | |||
end | |||
if not nevercalltr then | |||
-- Try to generate a transliteration. | |||
local text = data.alt[1] or data.term[1] | |||
if not link_tr then | |||
text = export.remove_links(text, true) | |||
end | |||
local automated_tr = lang:transliterate(text, data.sc[1]) | |||
if automated_tr then | |||
local manual_tr = data.tr[1] | |||
if manual_tr then | |||
if export.remove_links(manual_tr) == export.remove_links(automated_tr) then | |||
insert(cats, lang:getFullName() .. " terms with redundant transliterations") | |||
else | |||
-- Prevents Arabic root categories from flooding the tracking categories. | |||
if NAMESPACE ~= "Category" then | |||
insert(cats, | |||
lang:getFullName() .. " terms with non-redundant manual transliterations") | |||
end | |||
end | |||
end | |||
if not manual_tr or lang:overrideManualTranslit(data.sc[1]) then | |||
data.tr[1] = automated_tr | |||
end | end | ||
end | end | ||
| Line 1,240: | Line 1,342: | ||
-- Link to the transliteration entry for languages that require this | -- Link to the transliteration entry for languages that require this | ||
if data.tr[1] and | if data.tr[1] and link_tr and not data.tr[1]:match("%[%[(.-)%]%]") then | ||
data.tr[1] = simple_link( | data.tr[1] = simple_link( | ||
data.tr[1], | data.tr[1], | ||
| Line 1,252: | Line 1,354: | ||
srwc | srwc | ||
) | ) | ||
elseif data.tr[1] and not | elseif data.tr[1] and not link_tr then | ||
-- Remove the pseudo-HTML tags added by remove_links. | -- Remove the pseudo-HTML tags added by remove_links. | ||
data.tr[1] = data.tr[1]:gsub("</?link>", "") | data.tr[1] = data.tr[1]:gsub("</?link>", "") | ||
| Line 1,299: | Line 1,401: | ||
function(c1, c2, c3) | function(c1, c2, c3) | ||
-- Don't remove files. | -- Don't remove files. | ||
for _, false_positive in ipairs({"file", "image"}) do | for _, false_positive in ipairs({ "file", "image" }) do | ||
if c2:lower():match("^" .. false_positive .. ":") then return c1 .. c2 .. c3 end | if c2:lower():match("^" .. false_positive .. ":") then return c1 .. c2 .. c3 end | ||
end | end | ||
-- Remove categories completely. | -- Remove categories completely. | ||
for _, false_positive in ipairs({"category", "cat"}) do | for _, false_positive in ipairs({ "category", "cat" }) do | ||
if c2:lower():match("^" .. false_positive .. ":") then return "" end | if c2:lower():match("^" .. false_positive .. ":") then return "" end | ||
end | end | ||
| Line 1,326: | Line 1,428: | ||
error("The first argument to section_link was a " .. type(link) .. ", but it should be a string.") | error("The first argument to section_link was a " .. type(link) .. ", but it should be a string.") | ||
end | end | ||
local target, section = get_fragment((link:gsub("_", " "))) | local target, section = get_fragment((link:gsub("_", " "))) | ||
if not section then | if not section then | ||
error("No \"#\" delineating a section name") | error("No \"#\" delineating a section name") | ||