Module:Citation/CS1: Difference between revisions
Content added Content deleted
m (1 revision imported) |
en>Trappist the monk (synch from sandbox;) |
||
Line 153: | Line 153: | ||
if not domain:match ('^[%a%d]') then -- first character must be letter or digit |
if not domain:match ('^[%a%d]') then -- first character must be letter or digit |
||
return false; |
|||
end |
|||
if domain:match ('^%a+:') then -- hack to detect things that look like s:Page:Title where Page: is namespace at wikisource |
|||
return false; |
return false; |
||
end |
end |
||
Line 399: | Line 403: | ||
local path; |
local path; |
||
local base_url; |
local base_url; |
||
if not is_set( label ) then |
if not is_set( label ) then |
||
label = URL; |
label = URL; |
||
Line 415: | Line 419: | ||
if path then -- if there is a path portion |
if path then -- if there is a path portion |
||
path = path:gsub ('[%[%]]', {['[']='%5b',[']']='%5d'}); -- replace '[' and ']' with their percent encoded values |
path = path:gsub ('[%[%]]', {['[']='%5b',[']']='%5d'}); -- replace '[' and ']' with their percent encoded values |
||
URL=domain |
URL = table.concat ({domain, path}); -- and reassemble |
||
end |
end |
||
base_url = table.concat({ "[", URL, " ", safe_for_url (label), "]" }); -- assemble a wikimarkup url |
|||
if is_set (access) then -- access level (subscription, registration, limited) |
if is_set (access) then -- access level (subscription, registration, limited) |
||
base_url = substitute (cfg.presentation['ext-link-access-signal'], {cfg.presentation[access].class, cfg.presentation[access].title, base_url}); -- add the appropriate icon |
|||
label = safe_for_url (label); -- replace square brackets and newlines |
|||
base_url = table.concat ( -- assemble external link with access signal |
|||
{ |
|||
'<span class="plainlinks">[', -- opening css and url markup |
|||
URL, -- the url |
|||
' ', -- the required space |
|||
label, |
|||
'<span style="padding-left:0.15em">', -- signal spacing css |
|||
cfg.presentation[access], -- the appropriate icon |
|||
'</span>', -- close signal spacing span |
|||
']</span>' -- close url markup and plain links span |
|||
}); |
|||
else |
|||
base_url = table.concat({ "[", URL, " ", safe_for_url( label ), "]" }); -- no signal markup |
|||
end |
end |
||
return table.concat({ |
return table.concat ({base_url, error_str}); |
||
end |
end |
||
Line 549: | Line 541: | ||
end |
end |
||
-- if we get this far we have prefix and script |
-- if we get this far we have prefix and script |
||
name = mw.language.fetchLanguageName( lang, "en" ); |
name = cfg.lang_code_remap[lang] or mw.language.fetchLanguageName( lang, "en" ); -- get language name so that we can use it to categorize |
||
if is_set (name) then -- is prefix a proper ISO 639-1 language code? |
if is_set (name) then -- is prefix a proper ISO 639-1 language code? |
||
script_value = script_value:gsub ('^%l%l%s*:%s*', ''); -- strip prefix from script |
script_value = script_value:gsub ('^%l%l%s*:%s*', ''); -- strip prefix from script |
||
Line 605: | Line 597: | ||
return substitute( cfg.messages[key], str ); |
return substitute( cfg.messages[key], str ); |
||
end |
end |
||
end |
|||
--[[--------------------------< W I K I S O U R C E _ U R L _ M A K E >---------------------------------------- |
|||
makes a wikisource url from wikisource interwiki link. returns the url and appropriate label; nil else. |
|||
str is the value assigned to |chapter= (or aliases) or |title= or |title-link= |
|||
]] |
|||
local function wikisource_url_make (str) |
|||
local wl_type, D, L; |
|||
local ws_url, ws_label; |
|||
wl_type, D, L = is_wikilink (str); -- wl_type is 0 (not a wikilink), 1 (simple wikilink), 2 (complex wikilink) |
|||
if 0 == wl_type then -- not a wikilink; might be from |title-link= |
|||
str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace |
|||
if is_set (str) then |
|||
ws_url = table.concat ({ -- build a wikisource url |
|||
'https://en.wikisource.org/wiki/', -- prefix |
|||
str, -- article title |
|||
}); |
|||
ws_label = str; -- label for the url |
|||
end |
|||
elseif 1 == wl_type then -- simple wikilink: [[Wikisource:ws article]] |
|||
str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace |
|||
if is_set (str) then |
|||
ws_url = table.concat ({ -- build a wikisource url |
|||
'https://en.wikisource.org/wiki/', -- prefix |
|||
str, -- article title |
|||
}); |
|||
ws_label = str; -- label for the url |
|||
end |
|||
elseif 2 == wl_type then -- non-so-simple wikilink: [[Wikisource:ws article|displayed text]] ([[L|D]]) |
|||
str = L:match ('^[Ww]ikisource:(.+)') or L:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace |
|||
if is_set (str) then |
|||
ws_label = D; -- get ws article name from display portion of interwiki link |
|||
ws_url = table.concat ({ -- build a wikisource url |
|||
'https://en.wikisource.org/wiki/', -- prefix |
|||
str, -- article title without namespace from link portion of wikilink |
|||
}); |
|||
end |
|||
end |
|||
if ws_url then |
|||
ws_url = mw.uri.encode (ws_url, 'WIKI'); -- make a usable url |
|||
ws_url = ws_url:gsub ('%%23', '#'); -- undo percent encoding of anchor |
|||
end |
|||
return ws_url, ws_label, L or D; -- return proper url or nil and a label or nil |
|||
end |
end |
||
Line 617: | Line 661: | ||
local function format_chapter_title (scriptchapter, chapter, transchapter, chapterurl, chapter_url_source, no_quotes, access) |
local function format_chapter_title (scriptchapter, chapter, transchapter, chapterurl, chapter_url_source, no_quotes, access) |
||
local chapter_error = ''; |
local chapter_error = ''; |
||
local ws_url, ws_label, L = wikisource_url_make (chapter); -- make a wikisource url and label from a wikisource interwiki link |
|||
if ws_url then |
|||
ws_label = ws_label:gsub ('_', ''); -- replace underscore separaters with space characters |
|||
chapter = ws_label; |
|||
end |
|||
if not is_set (chapter) then |
if not is_set (chapter) then |
||
chapter = ''; -- to be safe for concatenation |
chapter = ''; -- to be safe for concatenation |
||
Line 628: | Line 678: | ||
chapter = script_concatenate (chapter, scriptchapter) -- <bdi> tags, lang atribute, categorization, etc; must be done after title is wrapped |
chapter = script_concatenate (chapter, scriptchapter) -- <bdi> tags, lang atribute, categorization, etc; must be done after title is wrapped |
||
if is_set (chapterurl) then |
|||
chapter = external_link (chapterurl, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate |
|||
elseif ws_url then |
|||
chapter = external_link (ws_url, chapter .. ' ', 'ws link in chapter'); -- adds bare_url_missing_title error if appropriate; space char to move icon away from chap text; TODO: better way to do this? |
|||
chapter = substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, chapter}); |
|||
end |
|||
if is_set (transchapter) then |
if is_set (transchapter) then |
||
Line 639: | Line 696: | ||
end |
end |
||
-- if is_set (chapterurl) then |
|||
chapter = external_link (chapterurl, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate |
-- chapter = external_link (chapterurl, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate |
||
-- end |
|||
return chapter .. chapter_error; |
return chapter .. chapter_error; |
||
Line 689: | Line 746: | ||
if position then |
if position then |
||
if 'nowiki' == capture or 'math' == capture |
if 'nowiki' == capture or 'math' == capture or -- nowiki and math stripmarkers (not an error condition) |
||
('templatestyles' == capture and in_array (param, {'id', 'quote'})) then -- templatestyles stripmarker allowed in these parameters |
|||
stripmarker = true; -- set a flag |
|||
stripmarker = true; -- set a flag |
|||
elseif true == stripmarker and 'delete' == char then -- because stripmakers begin and end with the delete char, assume that we've found one end of a stripmarker |
elseif true == stripmarker and 'delete' == char then -- because stripmakers begin and end with the delete char, assume that we've found one end of a stripmarker |
||
position = nil; -- unset |
position = nil; -- unset |
||
Line 757: | Line 815: | ||
end, |
end, |
||
}); |
}); |
||
end |
|||
--[[--------------------------< V A L I D A T E >-------------------------------------------------------------- |
|||
Looks for a parameter's name in one of several whitelists. |
|||
Parameters in the whitelist can have three values: |
|||
true - active, supported parameters |
|||
false - deprecated, supported parameters |
|||
nil - unsupported parameters |
|||
]] |
|||
local function validate( name, cite_class ) |
|||
local name = tostring( name ); |
|||
local state; |
|||
if in_array (cite_class, {'arxiv', 'biorxiv', 'citeseerx'}) then -- limited parameter sets allowed for these templates |
|||
state = whitelist.limited_basic_arguments[ name ]; |
|||
if true == state then return true; end -- valid actively supported parameter |
|||
if false == state then |
|||
deprecated_parameter (name); -- parameter is deprecated but still supported |
|||
return true; |
|||
end |
|||
if 'arxiv' == cite_class then -- basic parameters unique to these templates |
|||
state = whitelist.arxiv_basic_arguments[name]; |
|||
end |
|||
if 'biorxiv' == cite_class then |
|||
state = whitelist.biorxiv_basic_arguments[name]; |
|||
end |
|||
if 'citeseerx' == cite_class then |
|||
state = whitelist.citeseerx_basic_arguments[name]; |
|||
end |
|||
if true == state then return true; end -- valid actively supported parameter |
|||
if false == state then |
|||
deprecated_parameter (name); -- parameter is deprecated but still supported |
|||
return true; |
|||
end |
|||
-- limited enumerated parameters list |
|||
name = name:gsub( "%d+", "#" ); -- replace digit(s) with # (last25 becomes last#) |
|||
state = whitelist.limited_numbered_arguments[ name ]; |
|||
if true == state then return true; end -- valid actively supported parameter |
|||
if false == state then |
|||
deprecated_parameter (name); -- parameter is deprecated but still supported |
|||
return true; |
|||
end |
|||
return false; -- not supported because not found or name is set to nil |
|||
end -- end limited parameter-set templates |
|||
state = whitelist.basic_arguments[ name ]; -- all other templates; all normal parameters allowed |
|||
if true == state then return true; end -- valid actively supported parameter |
|||
if false == state then |
|||
deprecated_parameter (name); -- parameter is deprecated but still supported |
|||
return true; |
|||
end |
|||
-- all enumerated parameters allowed |
|||
name = name:gsub( "%d+", "#" ); -- replace digit(s) with # (last25 becomes last# |
|||
state = whitelist.numbered_arguments[ name ]; |
|||
if true == state then return true; end -- valid actively supported parameter |
|||
if false == state then |
|||
deprecated_parameter (name); -- parameter is deprecated but still supported |
|||
return true; |
|||
end |
|||
return false; -- not supported because not found or name is set to nil |
|||
end |
end |
||
Line 877: | Line 864: | ||
--[[--------------------------< H Y P H E N _ T O _ D A S H >-------------------------------------------------- |
--[[--------------------------< H Y P H E N _ T O _ D A S H >-------------------------------------------------- |
||
Converts a hyphen to a dash |
Converts a hyphen to a dash under certain conditions. The hyphen must separate like items; unlike items are |
||
returned unmodified. These forms are modified: |
|||
letter - letter (A - B) |
|||
digit - digit (4-5) |
|||
digit separator digit - digit separator digit (4.1-4.5 or 4-1-4-5) |
|||
letterdigit - letterdigit (A1-A5) (an optional separator between letter and digit is supported – a.1-a.5 or a-1-a-5) |
|||
digitletter - digitletter (5a - 5d) (an optional separator between letter and digit is supported – 5.a-5.d or 5-a-5-d) |
|||
any other forms are returned unmodified. |
|||
str may be a comma- or semicolon-separated list |
|||
]] |
]] |
||
local function hyphen_to_dash( str ) |
local function hyphen_to_dash( str ) |
||
if not is_set(str) |
if not is_set (str) then |
||
return str; |
return str; |
||
end |
end |
||
return str:gsub( '-', '–' ); |
|||
str, count = str:gsub ('^%(%((.+)%)%)$', '%1'); -- remove accept-this-as-written markup when it wraps all of str |
|||
if 0 ~= count then -- non-zero when markup removed; zero else |
|||
return str; -- nothing to do, we're done |
|||
end |
|||
str = str:gsub ('&[nm]dash;', {['–'] = '–', ['—'] = '—'}); -- replace — and – entities with their characters; semicolon mucks up the text.split |
|||
local out = {}; |
|||
local list = mw.text.split (str, '%s*[,;]%s*'); -- split str at comma or semicolon separators if there are any |
|||
for _, item in ipairs (list) do -- for each item in the list |
|||
if mw.ustring.match (item, '^%w*[%.%-]?%w+%s*[%-–—]%s*%w*[%.%-]?%w+$') then -- if a hyphenated range or has endash or emdash separators |
|||
if item:match ('%a+[%.%-]?%d+%s*%-%s*%a+[%.%-]?%d+') or -- letterdigit hyphen letterdigit (optional separator between letter and digit) |
|||
item:match ('%d+[%.%-]?%a+%s*%-%s*%d+[%.%-]?%a+') or -- digitletter hyphen digitletter (optional separator between digit and letter) |
|||
item:match ('%d+[%.%-]%d+%s*%-%s*%d+[%.%-]%d+') or -- digit separator digit hyphen digit separator digit |
|||
item:match ('%d+%s*%-%s*%d+') or -- digit hyphen digit |
|||
item:match ('%a+%s*%-%s*%a+') then -- letter hyphen letter |
|||
item = item:gsub ('(%w*[%.%-]?%w+)%s*%-%s*(%w*[%.%-]?%w+)', '%1–%2'); -- replace hyphen, remove extraneous space characters |
|||
else |
|||
item = mw.ustring.gsub (item, '%s*[–—]%s*', '–'); -- for endash or emdash separated ranges, replace em with en, remove extraneous white space |
|||
end |
|||
end |
|||
item = item:gsub ('^%(%((.+)%)%)$', '%1'); -- remove the accept-this-as-written markup |
|||
table.insert (out, item); -- add the (possibly modified) item to the output table |
|||
end |
|||
return table.concat (out, ', '); -- concatenate the output table into a comma separated string |
|||
end |
end |
||
Line 896: | Line 920: | ||
local function safe_join( tbl, duplicate_char ) |
local function safe_join( tbl, duplicate_char ) |
||
local f = {}; -- create a function table appropriate to type of 'dupicate character' |
|||
--[[ |
|||
if 1 == #duplicate_char then -- for single byte ascii characters use the string library functions |
|||
Note: we use string functions here, rather than ustring functions. |
|||
f.gsub=string.gsub |
|||
f.match=string.match |
|||
This has considerably faster performance and should work correctly as |
|||
f.sub=string.sub |
|||
long as the duplicate_char is strict ASCII. The strings |
|||
else -- for multi-byte characters use the ustring library functions |
|||
in tbl may be ASCII or UTF8. |
|||
f.gsub=mw.ustring.gsub |
|||
]] |
|||
f.match=mw.ustring.match |
|||
f.sub=mw.ustring.sub |
|||
end |
|||
local str = ''; -- the output string |
local str = ''; -- the output string |
||
local comp = ''; -- what does 'comp' mean? |
local comp = ''; -- what does 'comp' mean? |
||
Line 920: | Line 947: | ||
end |
end |
||
-- typically duplicate_char is sepc |
-- typically duplicate_char is sepc |
||
if |
if f.sub(comp, 1,1) == duplicate_char then -- is first character same as duplicate_char? why test first character? |
||
-- Because individual string segments often (always?) begin with terminal punct for |
-- Because individual string segments often (always?) begin with terminal punct for the |
||
-- preceding segment: 'First element' .. 'sepc next element' .. etc? |
-- preceding segment: 'First element' .. 'sepc next element' .. etc? |
||
trim = false; |
trim = false; |
||
end_chr = |
end_chr = f.sub(str, -1,-1); -- get the last character of the output string |
||
-- str = str .. "<HERE(enchr=" .. end_chr.. ")" -- debug stuff? |
-- str = str .. "<HERE(enchr=" .. end_chr.. ")" -- debug stuff? |
||
if end_chr == duplicate_char then -- if same as separator |
if end_chr == duplicate_char then -- if same as separator |
||
str = |
str = f.sub(str, 1,-2); -- remove it |
||
elseif end_chr == "'" then -- if it might be wikimarkup |
elseif end_chr == "'" then -- if it might be wikimarkup |
||
if |
if f.sub(str, -3,-1) == duplicate_char .. "''" then -- if last three chars of str are sepc'' |
||
str = |
str = f.sub(str, 1, -4) .. "''"; -- remove them and add back '' |
||
elseif |
elseif f.sub(str, -5,-1) == duplicate_char .. "]]''" then -- if last five chars of str are sepc]]'' |
||
trim = true; -- why? why do this and next differently from previous? |
trim = true; -- why? why do this and next differently from previous? |
||
elseif |
elseif f.sub(str, -4,-1) == duplicate_char .. "]''" then -- if last four chars of str are sepc]'' |
||
trim = true; -- same question |
trim = true; -- same question |
||
end |
end |
||
elseif end_chr == "]" then -- if it might be wikimarkup |
elseif end_chr == "]" then -- if it might be wikimarkup |
||
if |
if f.sub(str, -3,-1) == duplicate_char .. "]]" then -- if last three chars of str are sepc]] wikilink |
||
trim = true; |
trim = true; |
||
elseif |
elseif f.sub(str, -3,-1) == duplicate_char .. '"]' then -- if last three chars of str are sepc"] quoted external link |
||
trim = true; |
trim = true; |
||
elseif |
elseif f.sub(str, -2,-1) == duplicate_char .. "]" then -- if last two chars of str are sepc] external link |
||
trim = true; |
trim = true; |
||
elseif |
elseif f.sub(str, -4,-1) == duplicate_char .. "'']" then -- normal case when |url=something & |title=Title. |
||
trim = true; |
trim = true; |
||
end |
end |
||
elseif end_chr == " " then -- if last char of output string is a space |
elseif end_chr == " " then -- if last char of output string is a space |
||
if |
if f.sub(str, -2,-1) == duplicate_char .. " " then -- if last two chars of str are <sepc><space> |
||
str = |
str = f.sub(str, 1,-3); -- remove them both |
||
end |
end |
||
end |
end |
||
Line 955: | Line 982: | ||
if value ~= comp then -- value does not equal comp when value contains html markup |
if value ~= comp then -- value does not equal comp when value contains html markup |
||
local dup2 = duplicate_char; |
local dup2 = duplicate_char; |
||
if |
if f.match(dup2, "%A" ) then dup2 = "%" .. dup2; end -- if duplicate_char not a letter then escape it |
||
value = |
value = f.gsub(value, "(%b<>)" .. dup2, "%1", 1 ) -- remove duplicate_char if it follows html markup |
||
else |
else |
||
value = |
value = f.sub(value, 2, -1 ); -- remove duplicate_char when it is first character |
||
end |
end |
||
end |
end |
||
Line 967: | Line 994: | ||
end |
end |
||
return str; |
return str; |
||
end |
end |
||
Line 1,105: | Line 1,132: | ||
if 'vanc' == format then -- Vancouver-like author/editor name styling? |
if 'vanc' == format then -- Vancouver-like author/editor name styling? |
||
sep = ' |
sep = cfg.presentation['sep_nl_vanc']; -- name-list separator between authors is a comma |
||
namesep = ' |
namesep = cfg.presentation['sep_name_vanc']; -- last/first separator is a space |
||
else |
else |
||
sep = ' |
sep = cfg.presentation['sep_nl']; -- name-list separator between authors is a semicolon |
||
namesep = ' |
namesep = cfg.presentation['sep_name']; -- last/first separator is <comma><space> |
||
end |
end |
||
Line 1,379: | Line 1,406: | ||
return the original language name string. |
return the original language name string. |
||
mw.language.fetchLanguageNames(<local wiki language>, 'all') |
mw.language.fetchLanguageNames(<local wiki language>, 'all') returns a list of languages that in some cases may include |
||
extensions. For example, code 'cbk-zam' and its associated name 'Chavacano de Zamboanga' (MediaWiki does not support |
extensions. For example, code 'cbk-zam' and its associated name 'Chavacano de Zamboanga' (MediaWiki does not support |
||
code 'cbk' or name 'Chavacano'. |
code 'cbk' or name 'Chavacano'. Most (all?) of these languages are not used a 'language' codes per se, rather they |
||
are used as sub-domain names: cbk-zam.wikipedia.org. A list of language names and codes supported by fetchLanguageNames() |
|||
can be found at Template:Citation Style documentation/language/doc |
|||
Names |
Names that are included in the list will be found if that name is provided in the |language= parameter. For example, |
||
if |language=Chavacano de Zamboanga, that name will be found with the associated code 'cbk-zam'. When names are found |
if |language=Chavacano de Zamboanga, that name will be found with the associated code 'cbk-zam'. When names are found |
||
and the associated code is not two or three characters, this function returns only the |
and the associated code is not two or three characters, this function returns only the WikiMedia language name. |
||
Some language names have multiple entries under different codes: |
|||
Aromanian has code rup and code roa-rup |
|||
When this occurs, this function returns the language name and the 2- or 3-character code |
|||
Adapted from code taken from Module:Check ISO 639-1. |
Adapted from code taken from Module:Check ISO 639-1. |
||
Line 1,392: | Line 1,425: | ||
local function get_iso639_code (lang, this_wiki_code) |
local function get_iso639_code (lang, this_wiki_code) |
||
if |
if cfg.lang_name_remap[lang:lower()] then -- if there is a remapped name (because MediaWiki uses something that we don't think is correct) |
||
return cfg.lang_name_remap[lang:lower()][1], cfg.lang_name_remap[lang:lower()][2]; -- for this language 'name', return a possibly new name and appropriate code |
|||
return 'Bengali', 'bn'; -- make sure rendered version is properly capitalized |
|||
end |
end |
||
local ietf_code; -- because some languages have both ietf-like codes and iso 639-like codes |
|||
local ietf_name; |
|||
local languages = mw.language.fetchLanguageNames(this_wiki_code, 'all') -- get a list of language names known to Wikimedia |
local languages = mw.language.fetchLanguageNames(this_wiki_code, 'all') -- get a list of language names known to Wikimedia |
||
-- ('all' is required for North Ndebele, South Ndebele, and Ojibwa) |
-- ('all' is required for North Ndebele, South Ndebele, and Ojibwa) |
||
local langlc = mw.ustring.lower(lang); -- lower case version for comparisons |
local langlc = mw.ustring.lower(lang); -- lower case version for comparisons |
||
for code, name in pairs(languages) do -- scan the list to see if we can find our language |
for code, name in pairs(languages) do -- scan the list to see if we can find our language |
||
if langlc == mw.ustring.lower(name) then |
if langlc == mw.ustring.lower(name) then |
||
if 2 |
if 2 == code:len() or 3 == code:len() then -- two- or three-character codes only; extensions not supported |
||
return name; |
return name, code; -- so return the name and the code |
||
end |
end |
||
ietf_code = code; -- remember that we found an ietf-like code and save its name |
|||
ietf_name = name; -- but keep looking for a 2- or 3-char code |
|||
end |
end |
||
end |
end |
||
-- didn't find name with 2- or 3-char code; if ietf-like code found return |
|||
return ietf_code and ietf_name or lang; -- associated name; return original language text else |
|||
end |
end |
||
Line 1,442: | Line 1,480: | ||
for _, lang in ipairs (names_table) do -- reuse lang |
for _, lang in ipairs (names_table) do -- reuse lang |
||
name = cfg.lang_code_remap[lang:lower()]; -- first see if this is a code that is not supported by MediaWiki but is in remap |
|||
if |
if name then -- there was a remapped code so |
||
lang = lang: |
lang = lang:gsub ('^(%a%a%a?)%-.*', '%1'); -- strip ietf tags from code |
||
else |
|||
if |
if lang:match ('^%a%a%-') then -- strip ietf tags from code; TODO: is there a need to support 3-char with tag? |
||
lang = lang:match ('(%a%a)%-') -- keep only 639-1 code portion to lang; TODO: do something with 3166 alpha 2 country code? |
|||
name = mw.language.fetchLanguageName( lang:lower(), this_wiki_code); -- get language name if |language= is a proper code |
|||
end |
|||
if 2 == lang:len() or 3 == lang:len() then -- if two-or three-character code |
|||
name = mw.language.fetchLanguageName (lang:lower(), this_wiki_code); -- get language name if |language= is a proper code |
|||
end |
|||
end |
end |
||
if is_set (name) then -- if |language= specified a valid code |
if is_set (name) then -- if |language= specified a valid code |
||
code = lang:lower(); -- save it |
code = lang:lower(); -- save it |
||
Line 1,457: | Line 1,500: | ||
if is_set (code) then -- only 2- or 3-character codes |
if is_set (code) then -- only 2- or 3-character codes |
||
name = cfg.lang_code_remap[code] or name; -- override wikimedia when they misuse language codes/names |
|||
if this_wiki_code ~= code then -- when the language is not the same as this wiki's language |
if this_wiki_code ~= code then -- when the language is not the same as this wiki's language |
||
if 2 == code:len() then -- and is a two-character code |
if 2 == code:len() then -- and is a two-character code |
||
add_prop_cat ('foreign_lang_source' .. code, {name, code}) |
add_prop_cat ('foreign_lang_source' .. code, {name, code}) -- categorize it |
||
else -- or is a recognized language (but has a three-character code) |
else -- or is a recognized language (but has a three-character code) |
||
add_prop_cat ('foreign_lang_source_2' .. code, {code}) |
add_prop_cat ('foreign_lang_source_2' .. code, {code}) -- categorize it differently TODO: support mutliple three-character code categories per cs1|2 template |
||
end |
end |
||
end |
end |
||
Line 1,475: | Line 1,519: | ||
code = #language_list -- reuse code as number of languages in the list |
code = #language_list -- reuse code as number of languages in the list |
||
if 2 >= code then |
if 2 >= code then |
||
name = table.concat (language_list, ' |
name = table.concat (language_list, cfg.messages['parameter-pair-separator']) -- insert '<space>and<space>' between two language names |
||
elseif 2 < code then |
elseif 2 < code then |
||
name = table.concat (language_list, ', '); -- and concatenate with '<comma><space>' separators |
|||
name = |
name = name:gsub (', ([^,]+)$', cfg.messages['parameter-final-separator'] .. '%1'); -- replace last '<comma><space>' separator with '<comma><space>and<space>' separator |
||
end |
end |
||
if this_wiki_name == name then |
if this_wiki_name == name then |
||
Line 1,493: | Line 1,537: | ||
Set style settings for CS1 citation templates. Returns separator and postscript settings |
Set style settings for CS1 citation templates. Returns separator and postscript settings |
||
At en.wiki, for cs1: |
|||
ps gets: '.' |
|||
sep gets: '.' |
|||
]] |
]] |
||
Line 1,498: | Line 1,545: | ||
local function set_cs1_style (ps) |
local function set_cs1_style (ps) |
||
if not is_set (ps) then -- unless explicitely set to something |
if not is_set (ps) then -- unless explicitely set to something |
||
ps = |
ps = cfg.presentation['ps_cs1']; -- terminate the rendered citation |
||
end |
end |
||
return |
return cfg.presentation['sep_cs1'], ps; -- element separator |
||
end |
end |
||
Line 1,507: | Line 1,554: | ||
Set style settings for CS2 citation templates. Returns separator, postscript, ref settings |
Set style settings for CS2 citation templates. Returns separator, postscript, ref settings |
||
At en.wiki, for cs2: |
|||
ps gets: '' (empty string - no terminal punctuation) |
|||
sep gets: ',' |
|||
]] |
]] |
||
Line 1,512: | Line 1,562: | ||
local function set_cs2_style (ps, ref) |
local function set_cs2_style (ps, ref) |
||
if not is_set (ps) then -- if |postscript= has not been set, set cs2 default |
if not is_set (ps) then -- if |postscript= has not been set, set cs2 default |
||
ps = ''; |
ps = cfg.presentation['ps_cs2']; -- terminate the rendered citation |
||
end |
end |
||
if not is_set (ref) then -- if |ref= is not set |
if not is_set (ref) then -- if |ref= is not set |
||
ref = "harv"; -- set default |ref=harv |
ref = "harv"; -- set default |ref=harv |
||
end |
end |
||
return ' |
return cfg.presentation['sep_cs2'], ps, ref; -- element separator |
||
end |
end |
||
Line 1,897: | Line 1,947: | ||
end |
end |
||
local vol = ''; |
local vol = ''; -- here for all cites except magazine |
||
if is_set (volume) then |
if is_set (volume) then |
||
if volume:match ('^[MDCLXVI]+$') or volume:match ('^%d+$')then -- volume value is all digits or all uppercase roman numerals |
|||
if (4 < mw.ustring.len(volume)) then |
|||
vol = substitute (cfg. |
vol = substitute (cfg.presentation['vol-bold'], {sepc, hyphen_to_dash(volume)}); -- render in bold face |
||
elseif (4 < mw.ustring.len(volume)) then -- not all digits or roman numerals and longer than 4 characters |
|||
else |
|||
vol = substitute (cfg. |
vol = substitute (cfg.messages['j-vol'], {sepc, volume}); -- not bold |
||
add_prop_cat ('long_vol'); |
|||
else -- four or less characters |
|||
vol = substitute (cfg.presentation['vol-bold'], {sepc, hyphen_to_dash(volume)}); -- bold |
|||
end |
end |
||
end |
end |
||
Line 1,940: | Line 1,993: | ||
end |
end |
||
local is_journal = 'journal' == cite_class or (in_array (cite_class, {'citation', 'map'}) and 'journal' == origin); |
local is_journal = 'journal' == cite_class or (in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); |
||
if is_set (page) then |
if is_set (page) then |
||
Line 1,964: | Line 2,017: | ||
return '', '', '', ''; -- return empty strings |
return '', '', '', ''; -- return empty strings |
||
end |
end |
||
--[[--------------------------< I N S O U R C E _ L O C _ G E T >---------------------------------------------- |
|||
returns one of the in-source locators: page, pages, or at. |
|||
If any of these are interwiki links to wikisource, returns the label portion of the interwikilink as plain text |
|||
for use in COinS. This COinS thing is done because here we convert an interwiki link to and external link and |
|||
add an icon span around that; get_coins_pages() doesn't know about the span. TODO: should it? |
|||
TODO: add support for sheet and sheets?; streamline; |
|||
TODO: make it so that this function returns only one of the three as the single in-source (the return value assigned |
|||
to a new name)? |
|||
]] |
|||
local function insource_loc_get (page, pages, at) |
|||
local ws_url, ws_label, coins_pages, L; -- for wikisource interwikilinks; TODO: this corrupts page metadata (span remains in place after cleanup; fix there?) |
|||
if is_set (page) then |
|||
if is_set (pages) or is_set(at) then |
|||
pages = ''; -- unset the others |
|||
at = ''; |
|||
end |
|||
extra_text_in_page_check (page); -- add this page to maint cat if |page= value begins with what looks like p. or pp. |
|||
ws_url, ws_label, L = wikisource_url_make (page); -- make ws url from |page= interwiki link; link portion L becomes tool tip label |
|||
if ws_url then |
|||
page = external_link (ws_url, ws_label .. ' ', 'ws link in page'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? |
|||
page = substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, page}); |
|||
coins_pages = ws_label; |
|||
end |
|||
elseif is_set (pages) then |
|||
if is_set (at) then |
|||
at = ''; -- unset |
|||
end |
|||
extra_text_in_page_check (pages); -- add this page to maint cat if |pages= value begins with what looks like p. or pp. |
|||
ws_url, ws_label, L = wikisource_url_make (pages); -- make ws url from |pages= interwiki link; link portion L becomes tool tip label |
|||
if ws_url then |
|||
pages = external_link (ws_url, ws_label .. ' ', 'ws link in pages'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? |
|||
pages = substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, pages}); |
|||
coins_pages = ws_label; |
|||
end |
|||
elseif is_set (at) then |
|||
ws_url, ws_label, L = wikisource_url_make (at); -- make ws url from |at= interwiki link; link portion L becomes tool tip label |
|||
if ws_url then |
|||
at = external_link (ws_url, ws_label .. ' ', 'ws link in at'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? |
|||
at = substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, at}); |
|||
coins_pages = ws_label; |
|||
end |
|||
end |
|||
return page, pages, at, coins_pages; |
|||
end |
|||
Line 2,036: | Line 2,146: | ||
else |
else |
||
return url, date; -- preview mode so return archiveURL and ArchiveDate |
return url, date; -- preview mode so return archiveURL and ArchiveDate |
||
end |
|||
end |
|||
--[[--------------------------< M I S S I N G _ P I P E _ C H E C K >------------------------------------------ |
|||
Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal |
|||
sign, compare the alphanumeric string to the list of cs1|2 parameters. If found, then the string is possibly a |
|||
parameter that is missing its pipe: |
|||
{{cite ... |title=Title access-date=2016-03-17}} |
|||
cs1|2 shares some parameter names with xml/html atributes: class=, title=, etc. To prevent false positives xml/html |
|||
tags are removed before the search. |
|||
If a missing pipe is detected, this function adds the missing pipe maintenance category. |
|||
]] |
|||
local function missing_pipe_check (value) |
|||
local capture; |
|||
value = value:gsub ('%b<>', ''); -- remove xml/html tags because attributes: class=, title=, etc |
|||
capture = value:match ('%s+(%a[%a%d]+)%s*=') or value:match ('^(%a[%a%d]+)%s*='); -- find and categorize parameters with possible missing pipes |
|||
if capture and validate (capture) then -- if the capture is a valid parameter name |
|||
add_maint_cat ('missing_pipe'); |
|||
end |
end |
||
end |
end |
||
Line 2,135: | Line 2,220: | ||
t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= |
t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= |
||
local interviewers_list = {}; |
local interviewers_list = {}; |
||
local Interviewers |
local Interviewers; -- used later |
||
interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters |
|||
if is_set (Interviewers) then -- add a maint cat if the |interviewers= is used |
|||
add_maint_cat ('interviewers'); -- because use of this parameter is discouraged |
|||
else |
|||
interviewers_list = extract_names (args, 'InterviewerList'); -- else, process preferred interviewers parameters |
|||
end |
|||
local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs |
local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs |
||
Line 2,227: | Line 2,308: | ||
-- conference & map books do not support issue |
-- conference & map books do not support issue |
||
if in_array (config.CitationClass, cfg.templates_using_issue) and not (in_array (config.CitationClass, {'conference', 'map'}) and not is_set (Periodical))then |
if in_array (config.CitationClass, cfg.templates_using_issue) and not (in_array (config.CitationClass, {'conference', 'map'}) and not is_set (Periodical))then |
||
Issue = A['Issue']; |
Issue = hyphen_to_dash (A['Issue']); |
||
end |
end |
||
local Position = ''; |
local Position = ''; |
||
if not in_array (config.CitationClass, cfg.templates_not_using_page) then |
if not in_array (config.CitationClass, cfg.templates_not_using_page) then |
||
Page = A['Page']; |
Page = A['Page']; |
||
Pages = hyphen_to_dash( |
Pages = hyphen_to_dash (A['Pages']); |
||
At = A['At']; |
At = A['At']; |
||
end |
end |
||
Line 2,350: | Line 2,431: | ||
-- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it) |
-- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it) |
||
select_one( args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'redundant_parameters' ); -- this is a dummy call simply to get the error message and category |
select_one( args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'redundant_parameters' ); -- this is a dummy call simply to get the error message and category |
||
local coins_pages; |
|||
Page, Pages, At, coins_pages = insource_loc_get (Page, Pages, At); |
|||
local NoPP = A['NoPP'] |
local NoPP = A['NoPP'] |
||
Line 2,357: | Line 2,442: | ||
NoPP = nil; -- unset, used as a flag later |
NoPP = nil; -- unset, used as a flag later |
||
end |
end |
||
if is_set(Page) then |
|||
if is_set(Pages) or is_set(At) then |
|||
Pages = ''; -- unset the others |
|||
At = ''; |
|||
end |
|||
extra_text_in_page_check (Page); -- add this page to maint cat if |page= value begins with what looks like p. or pp. |
|||
elseif is_set(Pages) then |
|||
if is_set(At) then |
|||
At = ''; -- unset |
|||
end |
|||
extra_text_in_page_check (Pages); -- add this page to maint cat if |pages= value begins with what looks like p. or pp. |
|||
end |
|||
-- both |publication-place= and |place= (|location=) allowed if different |
-- both |publication-place= and |place= (|location=) allowed if different |
||
Line 2,385: | Line 2,457: | ||
|encyclopedia then map |encyclopedia to |title |
|encyclopedia then map |encyclopedia to |title |
||
| |
|trans-title maps to |trans-chapter when |title is re-mapped |
||
|url maps to |chapterurl when |title is remapped |
|url maps to |chapterurl when |title is remapped |
||
Line 2,585: | Line 2,657: | ||
-- legacy: promote PublicationDate to Date if neither Date nor Year are set. |
-- legacy: promote PublicationDate to Date if neither Date nor Year are set. |
||
local Date_origin; -- to hold the name of parameter promoted to Date; required for date error messaging |
|||
if not is_set (Date) then |
if not is_set (Date) then |
||
Date = Year; -- promote Year to Date |
Date = Year; -- promote Year to Date |
||
Line 2,591: | Line 2,665: | ||
Date = PublicationDate; -- promote PublicationDate to Date |
Date = PublicationDate; -- promote PublicationDate to Date |
||
PublicationDate = ''; -- unset, no longer needed |
PublicationDate = ''; -- unset, no longer needed |
||
Date_origin = A:ORIGIN('PublicationDate'); -- save the name of the promoted parameter |
|||
else |
|||
Date_origin = A:ORIGIN('Year'); -- save the name of the promoted parameter |
|||
end |
end |
||
else |
|||
Date_origin = A:ORIGIN('Date'); -- not a promotion; name required for error messaging |
|||
end |
end |
||
Line 2,605: | Line 2,684: | ||
local error_message = ''; |
local error_message = ''; |
||
-- AirDate has been promoted to Date so not necessary to check it |
-- AirDate has been promoted to Date so not necessary to check it |
||
local date_parameters_list = { |
local date_parameters_list = { |
||
['access-date'] = {val=AccessDate, name=A:ORIGIN ('AccessDate')}, |
|||
['embargo']=Embargo, ['lay-date']=LayDate, ['publication-date']=PublicationDate, ['year']=Year}; |
|||
['archive-date'] = {val=ArchiveDate, name=A:ORIGIN ('ArchiveDate')}, |
|||
['date'] = {val=Date, name=Date_origin}, |
|||
['doi-broken-date'] = {val=DoiBroken, name=A:ORIGIN ('DoiBroken')}, |
|||
['embargo'] = {val=Embargo, name=A:ORIGIN ('Embargo')}, |
|||
['lay-date'] = {val=LayDate, name=A:ORIGIN ('LayDate')}, |
|||
['publication-date'] ={val=PublicationDate, name=A:ORIGIN ('PublicationDate')}, |
|||
['year'] = {val=Year, name=A:ORIGIN ('Year')}, |
|||
}; |
|||
anchor_year, Embargo, error_message = dates(date_parameters_list, COinS_date); |
anchor_year, Embargo, error_message = dates(date_parameters_list, COinS_date); |
||
-- start temporary Julian / Gregorian calendar uncertainty categorization |
|||
if COinS_date.inter_cal_cat then |
|||
add_prop_cat ('jul_greg_uncertainty'); |
|||
end |
|||
-- end temporary Julian / Gregorian calendar uncertainty categorization |
|||
if is_set (Year) and is_set (Date) then -- both |date= and |year= not normally needed; |
if is_set (Year) and is_set (Date) then -- both |date= and |year= not normally needed; |
||
Line 2,636: | Line 2,728: | ||
-- for those wikis that can and want to have English date names translated to the local language, |
-- for those wikis that can and want to have English date names translated to the local language, |
||
-- uncomment these three lines. Not supported by en.wiki (for obvious reasons) |
-- uncomment these three lines. Not supported by en.wiki (for obvious reasons) |
||
-- set date_name_xlate() second argument to true to translate English digits to local digits (will translate ymd dates) |
|||
-- if date_name_xlate (date_parameters_list) then |
|||
-- if date_name_xlate (date_parameters_list, false) then |
|||
-- modified = true; |
-- modified = true; |
||
-- end |
-- end |
||
if modified then -- if the date_parameters_list values were modified |
if modified then -- if the date_parameters_list values were modified |
||
AccessDate = date_parameters_list['access-date']; |
AccessDate = date_parameters_list['access-date'].val; -- overwrite date holding parameters with modified values |
||
ArchiveDate = date_parameters_list['archive-date']; |
ArchiveDate = date_parameters_list['archive-date'].val; |
||
Date = date_parameters_list['date']; |
Date = date_parameters_list['date'].val; |
||
DoiBroken = date_parameters_list['doi-broken-date']; |
DoiBroken = date_parameters_list['doi-broken-date'].val; |
||
LayDate = date_parameters_list['lay-date']; |
LayDate = date_parameters_list['lay-date'].val; |
||
PublicationDate = date_parameters_list['publication-date']; |
PublicationDate = date_parameters_list['publication-date'].val; |
||
end |
end |
||
else |
else |
||
Line 2,725: | Line 2,818: | ||
['Volume'] = Volume, |
['Volume'] = Volume, |
||
['Issue'] = Issue, |
['Issue'] = Issue, |
||
['Pages'] = get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At}, 5)), -- pages stripped of external links |
['Pages'] = coins_pages or get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At}, 5)), -- pages stripped of external links |
||
['Edition'] = Edition, |
['Edition'] = Edition, |
||
['PublisherName'] = PublisherName, |
['PublisherName'] = PublisherName, |
||
Line 2,843: | Line 2,936: | ||
DeadURL = DeadURL:lower(); -- used later when assembling archived text |
DeadURL = DeadURL:lower(); -- used later when assembling archived text |
||
if is_set( ArchiveURL ) then |
if is_set( ArchiveURL ) then |
||
if is_set (ChapterURL) then -- |
if is_set (ChapterURL) then -- if chapter-url is set apply archive url to it |
||
OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text |
OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text |
||
OriginalURLorigin = ChapterURLorigin; -- name of chapter-url parameter for error messages |
OriginalURLorigin = ChapterURLorigin; -- name of chapter-url parameter for error messages |
||
OriginalFormat = ChapterFormat; -- and original |format= |
OriginalFormat = ChapterFormat; -- and original |chapter-format= |
||
if 'no' ~= DeadURL then |
if 'no' ~= DeadURL then |
||
ChapterURL = ArchiveURL -- swap-in the archive's url |
ChapterURL = ArchiveURL -- swap-in the archive's url |
||
ChapterURLorigin = A:ORIGIN('ArchiveURL') -- name of archive-url parameter for error messages |
ChapterURLorigin = A:ORIGIN('ArchiveURL') -- name of archive-url parameter for error messages |
||
ChapterFormat = ArchiveFormat or ''; -- swap in archive's format |
ChapterFormat = ArchiveFormat or ''; -- swap in archive's format |
||
ChapterUrlAccess = nil; -- restricted access levels do not make sense for archived urls |
|||
end |
end |
||
elseif is_set (URL) then |
elseif is_set (URL) then |
||
Line 2,910: | Line 3,004: | ||
-- Format main title. |
-- Format main title. |
||
if is_set (ArchiveURL) and mw.ustring.match (mw.ustring.lower(Title), cfg.special_case_translation['archived_copy']) then -- if title is 'Archived copy' (place holder added by bots that can't find proper title) |
|||
Title = mw.ustring.gsub(Title, '%'..sepc..'$', ''); -- remove any trailing separator character |
|||
add_maint_cat ('archived_copy'); -- add maintenance category before we modify the content of Title |
|||
if is_set(TitleLink) and is_set(Title) then |
|||
Title = make_wikilink (TitleLink, Title); |
|||
end |
end |
||
if Title:match ('^%(%(.*%)%)$') then -- if keep as written markup: |
|||
Title= Title:gsub ('^%(%((.*)%)%)$', '%1') -- remove the markup |
|||
else |
|||
if '...' == Title:sub (-3) then -- if elipsis is the last three characters of |title= |
|||
Title = Title:gsub ('(%.%.%.)%.+$', '%1'); -- limit the number of dots to three |
|||
elseif not mw.ustring.find (Title, '%.%s*%a%.$') and -- end of title is not a 'dot-(optional space-)letter-dot' initialism ... |
|||
not mw.ustring.find (Title, '%s+%a%.$') then -- ...and not a 'space-letter-dot' initial (''Allium canadense'' L.) |
|||
Title = mw.ustring.gsub(Title, '%'..sepc..'$', ''); -- remove any trailing separator character; sepc and ms.ustring() here for languages that use multibyte separator characters |
|||
end |
|||
end |
|||
if in_array(config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx'}) or |
if in_array(config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx'}) or |
||
('citation' == config.CitationClass and is_set (Periodical) and not is_set (Encyclopedia)) or |
('citation' == config.CitationClass and is_set (Periodical) and not is_set (Encyclopedia)) or |
||
Line 2,939: | Line 3,043: | ||
end |
end |
||
end |
end |
||
if is_set(Title) then |
if is_set(Title) then |
||
if not is_set(TitleLink) and is_set(URL) then |
if not is_set (TitleLink) and is_set (URL) then |
||
Title = external_link (URL, Title, URLorigin, UrlAccess) .. TransTitle .. TransError .. Format; |
|||
Title = external_link( URL, Title, URLorigin, UrlAccess ) .. TransTitle .. TransError .. Format; |
|||
URL = ''; -- unset these because no longer needed |
URL = ''; -- unset these because no longer needed |
||
Format = ""; |
Format = ""; |
||
elseif is_set (TitleLink) and not is_set (URL) then |
|||
local ws_url; |
|||
ws_url = wikisource_url_make (TitleLink); -- ignore ws_label return; not used here |
|||
if ws_url then |
|||
Title = external_link (ws_url, Title .. ' ', 'ws link in title-link'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? |
|||
Title = substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], TitleLink, Title}); |
|||
Title = Title .. TransTitle .. TransError; |
|||
else |
|||
Title = make_wikilink (TitleLink, Title) .. TransTitle .. TransError; |
|||
end |
|||
else |
else |
||
local ws_url, ws_label; |
|||
Title = Title .. TransTitle .. TransError; |
|||
ws_url, ws_label, L = wikisource_url_make (Title); -- make ws url from |title= interwiki link; link portion L becomes tool tip label |
|||
if ws_url then |
|||
Title = Title:gsub ('%b[]', ws_label); -- replace interwiki link with ws_label to retain markup |
|||
Title = external_link (ws_url, Title .. ' ', 'ws link in title'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? |
|||
Title = substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, Title}); |
|||
Title = Title .. TransTitle .. TransError; |
|||
else |
|||
Title = Title .. TransTitle .. TransError; |
|||
end |
|||
end |
end |
||
else |
else |
||
Line 3,025: | Line 3,147: | ||
if is_set (Translators) then |
if is_set (Translators) then |
||
Others = sepc .. ' ' |
Others = safe_join ({sepc .. ' ', wrap_msg ('translated', Translators, use_lowercase), Others}, sepc); |
||
end |
end |
||
if is_set (Interviewers) then |
if is_set (Interviewers) then |
||
Others = sepc .. ' ' |
Others = safe_join ({sepc .. ' ', wrap_msg ('interview', Interviewers, use_lowercase), Others}, sepc); |
||
end |
end |
||
Line 3,209: | Line 3,331: | ||
if in_array(config.CitationClass, {"journal","citation"}) and is_set(Periodical) then |
if in_array(config.CitationClass, {"journal","citation"}) and is_set(Periodical) then |
||
if is_set(Others) then Others = Others |
if is_set(Others) then Others = safe_join ({Others, sepc .. " "}, sepc) end -- add terminal punctuation & space; check for dup sepc; TODO why do we need to do this here? |
||
tcommon = safe_join( {Others, Title, TitleNote, Conference, Periodical, Format, TitleType, Series, Language, Edition, Publisher, Agency, Volume}, sepc ); |
tcommon = safe_join( {Others, Title, TitleNote, Conference, Periodical, Format, TitleType, Series, Language, Edition, Publisher, Agency, Volume}, sepc ); |
||
elseif in_array(config.CitationClass, {"book","citation"}) and not is_set(Periodical) then -- special cases for book cites |
elseif in_array(config.CitationClass, {"book","citation"}) and not is_set(Periodical) then -- special cases for book cites |
||
Line 3,370: | Line 3,492: | ||
table.insert (render, substitute (cfg.presentation['ocins'], {OCinSoutput})); -- append metadata to the citation |
table.insert (render, substitute (cfg.presentation['ocins'], {OCinSoutput})); -- append metadata to the citation |
||
if |
if 0 ~= #z.message_tail then |
||
table.insert (render, ' '); |
table.insert (render, ' '); |
||
for i,v in ipairs( z.message_tail ) do |
for i,v in ipairs( z.message_tail ) do |
||
Line 3,383: | Line 3,505: | ||
end |
end |
||
if |
if 0 ~= #z.maintenance_cats then |
||
local maint_msgs = {}; -- here we collect all of the maint messages |
|||
table.insert (render, '<span class="citation-comment" style="display:none; color:#33aa33; margin-left:0.3em">'); |
|||
for _, v in ipairs( z.maintenance_cats ) do -- append maintenance categories |
for _, v in ipairs( z.maintenance_cats ) do -- append maintenance categories |
||
local maint = {}; -- here we assemble a maintenence message |
|||
table.insert (render, v); |
|||
table.insert ( |
table.insert (maint, v); -- maint msg is the category name |
||
table.insert ( |
table.insert (maint, ' ('); -- open the link text |
||
table.insert ( |
table.insert (maint, make_wikilink (':Category:' .. v, 'link')); -- add the link |
||
table.insert (maint, ')'); -- and close it |
|||
table.insert (maint_msgs, table.concat (maint)); -- assemble new maint message and add it to the maint_msgs table |
|||
end |
end |
||
table.insert (render, substitute (cfg.presentation['hidden-maint'], table.concat (maint_msgs, ' '))); -- wrap the group of maint message with proper presentation and save |
|||
table.insert (render, '</span>'); |
|||
end |
end |
||
Line 3,408: | Line 3,532: | ||
return table.concat (render); |
return table.concat (render); |
||
end |
|||
--[[--------------------------< V A L I D A T E >-------------------------------------------------------------- |
|||
Looks for a parameter's name in one of several whitelists. |
|||
Parameters in the whitelist can have three values: |
|||
true - active, supported parameters |
|||
false - deprecated, supported parameters |
|||
nil - unsupported parameters |
|||
]] |
|||
local function validate (name, cite_class) |
|||
local name = tostring (name); |
|||
local state; |
|||
if in_array (cite_class, {'arxiv', 'biorxiv', 'citeseerx'}) then -- limited parameter sets allowed for these templates |
|||
state = whitelist.limited_basic_arguments[name]; |
|||
if true == state then return true; end -- valid actively supported parameter |
|||
if false == state then |
|||
deprecated_parameter (name); -- parameter is deprecated but still supported |
|||
return true; |
|||
end |
|||
state = whitelist[cite_class .. '_basic_arguments'][name]; -- look in the parameter-list for the template identified by cite_class |
|||
if true == state then return true; end -- valid actively supported parameter |
|||
if false == state then |
|||
deprecated_parameter (name); -- parameter is deprecated but still supported |
|||
return true; |
|||
end |
|||
-- limited enumerated parameters list |
|||
name = name:gsub("%d+", "#" ); -- replace digit(s) with # (last25 becomes last#) (mw.ustring because non-Western 'local' digits) |
|||
state = whitelist.limited_numbered_arguments[name]; |
|||
if true == state then return true; end -- valid actively supported parameter |
|||
if false == state then |
|||
deprecated_parameter (name); -- parameter is deprecated but still supported |
|||
return true; |
|||
end |
|||
return false; -- not supported because not found or name is set to nil |
|||
end -- end limited parameter-set templates |
|||
state = whitelist.basic_arguments[name]; -- all other templates; all normal parameters allowed |
|||
if true == state then return true; end -- valid actively supported parameter |
|||
if false == state then |
|||
deprecated_parameter (name); -- parameter is deprecated but still supported |
|||
return true; |
|||
end |
|||
-- all enumerated parameters allowed |
|||
name = name:gsub("%d+", "#" ); -- replace digit(s) with # (last25 becomes last#) (mw.ustring because non-Western 'local' digits) |
|||
state = whitelist.numbered_arguments[name]; |
|||
if true == state then return true; end -- valid actively supported parameter |
|||
if false == state then |
|||
deprecated_parameter (name); -- parameter is deprecated but still supported |
|||
return true; |
|||
end |
|||
return false; -- not supported because not found or name is set to nil |
|||
end |
|||
--[[--------------------------< M I S S I N G _ P I P E _ C H E C K >------------------------------------------ |
|||
Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal |
|||
sign, compare the alphanumeric string to the list of cs1|2 parameters. If found, then the string is possibly a |
|||
parameter that is missing its pipe: |
|||
{{cite ... |title=Title access-date=2016-03-17}} |
|||
cs1|2 shares some parameter names with xml/html atributes: class=, title=, etc. To prevent false positives xml/html |
|||
tags are removed before the search. |
|||
If a missing pipe is detected, this function adds the missing pipe maintenance category. |
|||
]] |
|||
local function missing_pipe_check (value) |
|||
local capture; |
|||
value = value:gsub ('%b<>', ''); -- remove xml/html tags because attributes: class=, title=, etc |
|||
capture = value:match ('%s+(%a[%a%d]+)%s*=') or value:match ('^(%a[%a%d]+)%s*='); -- find and categorize parameters with possible missing pipes |
|||
if capture and validate (capture) then -- if the capture is a valid parameter name |
|||
add_maint_cat ('missing_pipe'); |
|||
end |
|||
end |
end |
||
Line 3,420: | Line 3,632: | ||
Frame = frame; -- save a copy incase we need to display an error message in preview mode |
Frame = frame; -- save a copy incase we need to display an error message in preview mode |
||
local pframe = frame:getParent() |
local pframe = frame:getParent() |
||
local validation, utilities, identifiers, metadata; |
local validation, utilities, identifiers, metadata, styles; |
||
if nil ~= string.find (frame:getTitle(), 'sandbox', 1, true) then -- did the {{#invoke:}} use sandbox version? |
if nil ~= string.find (frame:getTitle(), 'sandbox', 1, true) then -- did the {{#invoke:}} use sandbox version? |
||
Line 3,429: | Line 3,641: | ||
identifiers = require ('Module:Citation/CS1/Identifiers/sandbox'); |
identifiers = require ('Module:Citation/CS1/Identifiers/sandbox'); |
||
metadata = require ('Module:Citation/CS1/COinS/sandbox'); |
metadata = require ('Module:Citation/CS1/COinS/sandbox'); |
||
styles = 'Module:Citation/CS1/sandbox/styles.css'; |
|||
else -- otherwise |
else -- otherwise |
||
Line 3,437: | Line 3,650: | ||
identifiers = require ('Module:Citation/CS1/Identifiers'); |
identifiers = require ('Module:Citation/CS1/Identifiers'); |
||
metadata = require ('Module:Citation/CS1/COinS'); |
metadata = require ('Module:Citation/CS1/COinS'); |
||
styles = 'Module:Citation/CS1/styles.css'; |
|||
end |
end |
||
Line 3,486: | Line 3,701: | ||
for k, v in pairs( pframe.args ) do |
for k, v in pairs( pframe.args ) do |
||
if v ~= '' then |
if v ~= '' then |
||
if ('string' == type (k)) then |
|||
k = mw.ustring.gsub (k, '%d', cfg.date_names.local_digits); -- for enumerated parameters, translate 'local' digits to Western 0-9 |
|||
end |
|||
if not validate( k, config.CitationClass ) then |
if not validate( k, config.CitationClass ) then |
||
error_text = ""; |
error_text = ""; |
||
Line 3,494: | Line 3,712: | ||
end |
end |
||
elseif validate( k:lower(), config.CitationClass ) then |
elseif validate( k:lower(), config.CitationClass ) then |
||
error_text, error_state = set_error( 'parameter_ignored_suggest', {k, k:lower()}, true ); |
error_text, error_state = set_error( 'parameter_ignored_suggest', {k, k:lower()}, true ); -- suggest the lowercase version of the parameter |
||
else |
else |
||
if nil == suggestions.suggestions then -- if this table is nil then we need to load it |
if nil == suggestions.suggestions then -- if this table is nil then we need to load it |
||
Line 3,506: | Line 3,724: | ||
capture = k:match (pattern); -- the whole match if no caputre in pattern else the capture if a match |
capture = k:match (pattern); -- the whole match if no caputre in pattern else the capture if a match |
||
if capture then -- if the pattern matches |
if capture then -- if the pattern matches |
||
param = substitute( |
param = substitute (param, capture); -- add the capture to the suggested parameter (typically the enumerator) |
||
if validate (param, config.CitationClass) then -- validate the suggestion to make sure that the suggestion is supported by this template (necessary for limited parameter lists) |
|||
error_text, error_state = set_error( 'parameter_ignored_suggest', {k, param}, true ); -- set the error message |
|||
error_text, error_state = set_error ('parameter_ignored_suggest', {k, param}, true); -- set the suggestion error message |
|||
else |
|||
error_text, error_state = set_error( 'parameter_ignored', {param}, true ); -- suggested param not supported by this template |
|||
end |
|||
end |
end |
||
end |
end |
||
Line 3,524: | Line 3,746: | ||
end |
end |
||
missing_pipe_check (v); -- do we think that there is a parameter that is missing a pipe? |
missing_pipe_check (v); -- do we think that there is a parameter that is missing a pipe? |
||
-- TODO: is this the best place for this translation? |
|||
args[k] = v; |
|||
elseif args[k] ~= nil or (k == 'postscript') then |
|||
args[k] = v; |
args[k] = v; |
||
elseif args[k] ~= nil or (k == 'postscript') then -- here when v is empty string |
|||
args[k] = v; -- why do we do this? we don't support 'empty' parameters |
|||
end |
end |
||
end |
end |
||
Line 3,536: | Line 3,758: | ||
end |
end |
||
end |
end |
||
return citation0( config, args) |
return table.concat ({citation0( config, args), frame:extensionTag ('templatestyles', '', {src=styles})}); |
||
end |
end |
||