Module:Citation/CS1: Difference between revisions
sync from sandbox;
(synch from sandbox;) |
(sync from sandbox;) |
||
Line 1: | Line 1: | ||
--[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- | --[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- | ||
Line 133: | Line 131: | ||
the first character of the whole domain name including subdomains must be a letter or a digit | the first character of the whole domain name including subdomains must be a letter or a digit | ||
internationalized domain name (ascii characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the tld) see https://tools.ietf.org/html/rfc3490 | internationalized domain name (ascii characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the tld) see https://tools.ietf.org/html/rfc3490 | ||
single-letter/digit second-level domains in the .org and . | single-letter/digit second-level domains in the .org, .cash, and .today TLDs | ||
q, x, and z SL domains in the .com TLD | q, x, and z SL domains in the .com TLD | ||
i and q SL domains in the .net TLD | i and q SL domains in the .net TLD | ||
Line 165: | Line 163: | ||
return true; | return true; | ||
elseif domain:match ('%f[%a%d][%a%d]%.cash$') then -- one character/digit .cash hostname | elseif domain:match ('%f[%a%d][%a%d]%.cash$') then -- one character/digit .cash hostname | ||
return true; | |||
elseif domain:match ('%f[%a%d][%a%d]%.today') then -- one character/digit .today hostname | |||
return true; | return true; | ||
elseif domain:match ('%f[%a%d][%a%d]%.org$') then -- one character/digit .org hostname | elseif domain:match ('%f[%a%d][%a%d]%.org$') then -- one character/digit .org hostname | ||
Line 713: | Line 713: | ||
Detects but ignores nowiki and math stripmarkers. Also detects other named stripmarkers (gallery, math, pre, ref) | Detects but ignores nowiki and math stripmarkers. Also detects other named stripmarkers (gallery, math, pre, ref) | ||
and identifies them with a slightly different error message. See also coins_cleanup(). | and identifies them with a slightly different error message. See also coins_cleanup(). | ||
Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker | Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker | ||
Line 1,221: | Line 1,219: | ||
--[[--------------------------< N A M E _ H A S _ E T A L >---------------------------------------------------- | --[[--------------------------< N A M E _ H A S _ E T A L >---------------------------------------------------- | ||
Evaluates the content of author | Evaluates the content of name parameters (author, editor, etc) for variations on the theme of et al. If found, | ||
the et al. is removed, a flag is set to true and the function returns the modified name and the flag. | the et al. is removed, a flag is set to true and the function returns the modified name and the flag. | ||
This function never sets the flag to false but returns it's previous state because it may have been set by | This function never sets the flag to false but returns it's previous state because it may have been set by | ||
previous passes through this function or by the | previous passes through this function or by the associated |display-<names>=etal parameter | ||
]] | ]] | ||
local function name_has_etal (name, etal, nocat) | local function name_has_etal (name, etal, nocat, param) | ||
if is_set (name) then -- name can be nil in which case just return | if is_set (name) then -- name can be nil in which case just return | ||
local | local patterns = cfg.et_al_patterns; --get patterns from configuration | ||
for _, pattern in ipairs (patterns) do -- loop through all of the patterns | |||
if name:match (pattern) then -- if this 'et al' pattern is found in name | |||
name = name:gsub (pattern, ''); -- remove the offending text | |||
if | etal = true; -- set flag (may have been set previously here or by |display-<names>=etal) | ||
if not nocat then -- no categorization for |vauthors= | |||
table.insert( z.message_tail, {set_error ('etal', {param})}); -- and set an error if not added | |||
end | |||
end | end | ||
end | end | ||
end | end | ||
return name, etal; -- | return name, etal; -- | ||
end | end | ||
Line 1,263: | Line 1,257: | ||
local function name_has_ed_markup (name, list_name) | local function name_has_ed_markup (name, list_name) | ||
local _, pattern; | local _, pattern; | ||
local patterns = | local patterns = cfg.editor_markup_patterns; -- get patterns from configuration | ||
if is_set (name) then | if is_set (name) then | ||
Line 1,362: | Line 1,345: | ||
local etal=false; -- return value set to true when we find some form of et al. in an author parameter | local etal=false; -- return value set to true when we find some form of et al. in an author parameter | ||
local | local last_alias, first_alias; -- selected parameter aliases used in error messaging | ||
while true do | while true do | ||
last = select_one( args, cfg.aliases[list_name .. '-Last'], 'redundant_parameters', i ); -- search through args for name components beginning at 1 | last, last_alias = select_one( args, cfg.aliases[list_name .. '-Last'], 'redundant_parameters', i ); -- search through args for name components beginning at 1 | ||
first = select_one( args, cfg.aliases[list_name .. '-First'], 'redundant_parameters', i ); | first, first_alias = select_one( args, cfg.aliases[list_name .. '-First'], 'redundant_parameters', i ); | ||
link = select_one( args, cfg.aliases[list_name .. '-Link'], 'redundant_parameters', i ); | link = select_one( args, cfg.aliases[list_name .. '-Link'], 'redundant_parameters', i ); | ||
mask = select_one( args, cfg.aliases[list_name .. '-Mask'], 'redundant_parameters', i ); | mask = select_one( args, cfg.aliases[list_name .. '-Mask'], 'redundant_parameters', i ); | ||
last, etal = name_has_etal (last, etal, false); | last, etal = name_has_etal (last, etal, false, last_alias); -- find and remove variations on et al. | ||
first, etal = name_has_etal (first, etal, false); | first, etal = name_has_etal (first, etal, false, first_alias); -- find and remove variations on et al. | ||
last, first= name_checks (last, first, list_name); -- multiple names, extraneous annotation, etc checks | last, first= name_checks (last, first, list_name); -- multiple names, extraneous annotation, etc checks | ||
if first and not last then -- if there is a firstn without a matching lastn | if first and not last then -- if there is a firstn without a matching lastn | ||
table.insert( z.message_tail, { set_error( 'first_missing_last', { | table.insert( z.message_tail, { set_error( 'first_missing_last', {first_alias, first_alias:gsub('first', 'last')}, true ) } ); -- add this error message | ||
elseif not first and not last then -- if both firstn and lastn aren't found, are we done? | elseif not first and not last then -- if both firstn and lastn aren't found, are we done? | ||
count = count + 1; -- number of times we haven't found last and first | count = count + 1; -- number of times we haven't found last and first | ||
Line 1,386: | Line 1,369: | ||
n = n + 1; -- point to next location in the names table | n = n + 1; -- point to next location in the names table | ||
if 1 == count then -- if the previous name was missing | if 1 == count then -- if the previous name was missing | ||
table.insert( z.message_tail, { set_error( 'missing_name', { | table.insert( z.message_tail, { set_error( 'missing_name', {list_name:match ("(%w+)List"):lower(), i-1}, true ) } ); -- add this error message | ||
end | end | ||
count = 0; -- reset the counter, we're looking for two consecutive missing names | count = 0; -- reset the counter, we're looking for two consecutive missing names | ||
Line 1,624: | Line 1,607: | ||
local function is_pdf (url) | local function is_pdf (url) | ||
return url:match ('%.pdf$') or url:match ('%.PDF$') or url:match ('%.pdf[%?#]') or url:match ('%.PDF[%?#]'); | return url:match ('%.pdf$') or url:match ('%.PDF$') or | ||
url:match ('%.pdf[%?#]') or url:match ('%.PDF[%?#]') or | |||
url:match ('%.PDF#') or url:match ('%.pdf#'); | |||
end | end | ||
Line 1,652: | Line 1,637: | ||
--[[--------------------------< G E T _ D I S P L A Y _ A | --[[--------------------------< G E T _ D I S P L A Y _ N A M E S >-------------------------------------------- | ||
Returns a number that defines the number of names displayed for author and editor name lists and a boolean flag | Returns a number that defines the number of names displayed for author and editor name lists and a boolean flag | ||
Line 1,675: | Line 1,660: | ||
]] | ]] | ||
local function | local function get_display_names (max, count, list_name, etal) | ||
if is_set (max) then | if is_set (max) then | ||
if 'etal' == max:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings | if 'etal' == max:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings | ||
Line 1,683: | Line 1,668: | ||
max = tonumber (max); -- make it a number | max = tonumber (max); -- make it a number | ||
if max >= count then -- if |display-xxxxors= value greater than or equal to number of authors/editors | if max >= count then -- if |display-xxxxors= value greater than or equal to number of authors/editors | ||
add_maint_cat (' | add_maint_cat ('disp_name', cfg.special_case_translation [list_name]); | ||
end | end | ||
else -- not a valid keyword or number | else -- not a valid keyword or number | ||
Line 1,784: | Line 1,769: | ||
vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period) | vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period) | ||
v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); | v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); -- names are separated by commas | ||
for i, v_name in ipairs(v_name_table) do | for i, v_name in ipairs(v_name_table) do | ||
Line 2,216: | Line 2,201: | ||
end | end | ||
local translator_etal; | |||
local t = {}; -- translators list from |translator-lastn= / translator-firstn= pairs | local t = {}; -- translators list from |translator-lastn= / translator-firstn= pairs | ||
local Translators; -- assembled translators name list | local Translators; -- assembled translators name list | ||
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 interviewer_etal; | |||
local interviewers_list = {}; | local interviewers_list = {}; | ||
local Interviewers; -- used later | local Interviewers; -- used later | ||
interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters | interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters | ||
local contributor_etal; | |||
local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs | local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs | ||
local Contributors; -- assembled contributors name list | local Contributors; -- assembled contributors name list | ||
Line 2,250: | Line 2,238: | ||
NameListFormat = ''; -- anything else, set to empty string | NameListFormat = ''; -- anything else, set to empty string | ||
end | end | ||
if is_set (Others) then | |||
if 0 == #a and 0 == #e then -- add maint cat when |others= has value and used without |author=, |editor= | |||
add_maint_cat ('others'); | |||
end | |||
end | |||
local Year = A['Year']; | local Year = A['Year']; | ||
Line 2,408: | Line 2,402: | ||
if not is_valid_parameter_value (DF, 'df', cfg.keywords['date-format']) then -- validate reformatting keyword | if not is_valid_parameter_value (DF, 'df', cfg.keywords['date-format']) then -- validate reformatting keyword | ||
DF = ''; -- not valid, set to empty string | DF = ''; -- not valid, set to empty string | ||
end | |||
if not is_set (DF) then | |||
DF = cfg.global_df; | |||
end | end | ||
Line 2,856: | Line 2,853: | ||
do -- do editor name list first because the now unsupported coauthors used to modify control table | do -- do editor name list first because the now unsupported coauthors used to modify control table | ||
control.maximum , editor_etal = | control.maximum , editor_etal = get_display_names (A['DisplayEditors'], #e, 'editors', editor_etal); | ||
last_first_list, EditorCount = list_people(control, e, editor_etal); | last_first_list, EditorCount = list_people(control, e, editor_etal); | ||
if is_set (Editors) then | if is_set (Editors) then | ||
Editors, editor_etal = name_has_etal (Editors, editor_etal, false, 'editors'); -- find and remove variations on et al. | |||
if editor_etal then | if editor_etal then | ||
Editors = Editors .. ' ' .. cfg.messages['et al']; -- add et al. to editors parameter beause |display-editors=etal | Editors = Editors .. ' ' .. cfg.messages['et al']; -- add et al. to editors parameter beause |display-editors=etal | ||
Line 2,875: | Line 2,873: | ||
end | end | ||
do -- now do interviewers | do -- now do interviewers | ||
control.maximum = #interviewers_list; | control.maximum , interviewer_etal = get_display_names (A['DisplayInterviewers'], #interviewers_list, 'interviewers', interviewer_etal); | ||
Interviewers = list_people(control, interviewers_list, | Interviewers = list_people (control, interviewers_list, interviewer_etal); | ||
end | end | ||
do -- now do translators | do -- now do translators | ||
control.maximum = #t; | control.maximum , translator_etal = get_display_names (A['DisplayTranslators'], #t, 'translators', translator_etal); | ||
Translators = list_people(control, t, | Translators = list_people (control, t, translator_etal); | ||
end | end | ||
do -- now do contributors | do -- now do contributors | ||
control.maximum = #c; -- number of contributors | control.maximum , contributor_etal = get_display_names (A['DisplayContributors'], #c, 'contributors', contributor_etal); | ||
Contributors = list_people (control, c, contributor_etal); | |||
-- control.maximum = #c; -- number of contributors | |||
-- Contributors = list_people(control, c, false); -- et al not currently supported | |||
end | end | ||
do -- now do authors | do -- now do authors | ||
control.maximum , author_etal = | control.maximum , author_etal = get_display_names (A['DisplayAuthors'], #a, 'authors', author_etal); | ||
last_first_list = list_people(control, a, author_etal); | last_first_list = list_people(control, a, author_etal); | ||
if is_set (Authors) then | if is_set (Authors) then | ||
Authors, author_etal = name_has_etal (Authors, author_etal, false); -- find and remove variations on et al. | Authors, author_etal = name_has_etal (Authors, author_etal, false, 'authors'); -- find and remove variations on et al. | ||
if author_etal then | if author_etal then | ||
Authors = Authors .. ' ' .. cfg.messages['et al']; -- add et al. to authors parameter | Authors = Authors .. ' ' .. cfg.messages['et al']; -- add et al. to authors parameter | ||
Line 3,351: | Line 3,351: | ||
elseif 'episode' == config.CitationClass then -- special case for cite episode | elseif 'episode' == config.CitationClass then -- special case for cite episode | ||
tcommon = safe_join( {Title, TitleNote, TitleType, Series | tcommon = safe_join( {Title, TitleNote, TitleType, Series, Language, Edition, Publisher}, sepc ); | ||
else -- all other CS1 templates | else -- all other CS1 templates | ||
Line 3,364: | Line 3,364: | ||
end | end | ||
local idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, SubscriptionRequired, Lay, Quote }, sepc ); | local idcommon; | ||
if 'audio-visual' == config.CitationClass or 'episode' == config.CitationClass then -- special case for cite AV media & cite episode position transcript | |||
idcommon = safe_join( { ID_list, URL, Archived, Transcript, AccessDate, Via, SubscriptionRequired, Lay, Quote }, sepc ); | |||
else | |||
idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, SubscriptionRequired, Lay, Quote }, sepc ); | |||
end | |||
local text; | local text; | ||
local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; | local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; | ||
Line 3,390: | Line 3,396: | ||
if (sepc ~= '.') then | if (sepc ~= '.') then | ||
in_text = in_text:lower() -- lowercase for cs2 | in_text = in_text:lower() -- lowercase for cs2 | ||
end | |||
end | |||
if EditorCount <= 1 then | |||
post_text = " (" .. cfg.messages['editor'] .. ")"; -- be consistent with no-author, no-date case | |||
else | else | ||
post_text = " (" .. cfg.messages['editors'] .. ")"; | |||
end | |||
end | |||
Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space | Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space | ||
end | end | ||
Line 3,612: | Line 3,617: | ||
]] | ]] | ||
local function missing_pipe_check (value) | local function missing_pipe_check (parameter, value) | ||
local capture; | local capture; | ||
value = value:gsub ('%b<>', ''); -- remove xml/html tags because attributes: class=, title=, etc | value = value:gsub ('%b<>', ''); -- remove xml/html tags because attributes: class=, title=, etc | ||
Line 3,618: | Line 3,623: | ||
capture = value:match ('%s+(%a[%a%d]+)%s*=') or value:match ('^(%a[%a%d]+)%s*='); -- find and categorize parameters with possible missing pipes | 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 | if capture and validate (capture) then -- if the capture is a valid parameter name | ||
table.insert( z.message_tail, {set_error ('missing_pipe',parameter)}); | |||
end | end | ||
end | end | ||
Line 3,629: | Line 3,634: | ||
]] | ]] | ||
function | local function citation(frame) | ||
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() | ||
Line 3,745: | Line 3,750: | ||
end | end | ||
end | end | ||
missing_pipe_check (v); -- do we think that there is a parameter that is missing a pipe? | missing_pipe_check (k, v); -- do we think that there is a parameter that is missing a pipe? | ||
-- TODO: is this the best place for this translation? | -- TODO: is this the best place for this translation? | ||
args[k] = v; | args[k] = v; | ||
Line 3,761: | Line 3,766: | ||
end | end | ||
return | --[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------ | ||
]] | |||
return {citation = citation}; |