Jump to content

Module:Cite IUCN and Module:Cite IUCN/sandbox: Difference between pages

(Difference between pages)
Page 1
Page 2
Content deleted Content added
Fix Linter errors. Close span tag in all circumstances. See "Vachellia hindsii" entry at User:Neb/sandbox for an example.
 
m Elli moved page Module:Cite iucn/sandbox to Module:Cite IUCN/sandbox without leaving a redirect: per RM
 
Line 1: Line 1:
require('strict');
require('strict');
local getArgs = require ('Module:Arguments').getArgs;
local getArgs = require ('Module:Arguments').getArgs;

local amendment_pattern = '%s*%(amended version of (%d%d%d%d) assessment%)';
local errata_pattern = '%s*%(errata version published in (%d%d%d%d)%)';
local green_status_pattern = '%s*%((Green Status assessment)%)';




Line 18: Line 14:
]]
]]


local function iucn_identifiers_get (args, error_msgs_t)
local function iucn_identifiers_get (args)
local doi_taxon_ID, doi_assesment_ID
local doi_taxon_ID, doi_assesment_ID
local page_taxon_ID, page_assesment_ID
local page_taxon_ID, page_assesment_ID
local id_taxon_ID, id_assesment_ID
local url_taxon_ID, url_assesment_ID
local url_taxon_ID, url_assesment_ID
local msg

if args.doi then
if args.doi then
doi_taxon_ID, doi_assesment_ID = args.doi:match ('[Tt](%d+)[Aa](%d+)%.en$')
local lang_tag
if not doi_taxon_ID then
doi_taxon_ID, doi_assesment_ID, lang_tag = args.doi:match ('[Tt](%d+)[Aa](%d+)%.(%l%l)$')
msg = 'malformed |doi= identifier'
if not doi_taxon_ID or not ({['en'] = true, ['es'] = true, ['fr'] = true, ['pt'] = true})[lang_tag] then
table.insert (error_msgs_t, 'malformed |doi= identifier');
end
end
end
end
Line 33: Line 30:
page_taxon_ID, page_assesment_ID = args.page:match ('^[eE]%.[Tt](%d+)[Aa](%d+)$')
page_taxon_ID, page_assesment_ID = args.page:match ('^[eE]%.[Tt](%d+)[Aa](%d+)$')
if not page_taxon_ID then
if not page_taxon_ID then
table.insert (error_msgs_t, 'malformed |page= identifier');
msg = 'malformed |page= identifier'
end
end
if args.id then
id_taxon_ID, id_assesment_ID = args.id:match ('^(%d+)/(%d+)$')
if not id_taxon_ID then
msg = 'malformed |id= identifier'
end
end
end
end
Line 40: Line 43:
url_taxon_ID, url_assesment_ID = args.url:match ('/species/(%d+)/(%d+)')
url_taxon_ID, url_assesment_ID = args.url:match ('/species/(%d+)/(%d+)')
if not url_taxon_ID then
if not url_taxon_ID then
table.insert (error_msgs_t, 'malformed |url= identifier');
msg = 'malformed |url= identifier'
end
end
end
end
end
end


if not error_msgs_t[1] then
if not msg then
if doi_taxon_ID and page_taxon_ID then
if doi_taxon_ID and page_taxon_ID then
if (doi_taxon_ID ~= page_taxon_ID or ((doi_assesment_ID ~= page_assesment_ID) and not args.errata)) then
if not (doi_taxon_ID == page_taxon_ID and doi_assesment_ID == page_assesment_ID) then
table.insert (error_msgs_t, '|doi= / |page= mismatch');
msg = '|doi= / |page= mismatch'
end
end
if doi_taxon_ID and id_taxon_ID then
if not (doi_taxon_ID == id_taxon_ID and doi_assesment_ID == id_assesment_ID) then
msg = '|doi= / |id= mismatch'
end
end
end
end
if doi_taxon_ID and url_taxon_ID then
if doi_taxon_ID and url_taxon_ID then
if (doi_taxon_ID ~= url_taxon_ID or ((doi_assesment_ID ~= url_assesment_ID) and not args.errata)) then
if not (doi_taxon_ID == url_taxon_ID and doi_assesment_ID == url_assesment_ID) then
table.insert (error_msgs_t, '|doi= / |url= mismatch');
msg = '|doi= / |url= mismatch'
end
end
end
end
if page_taxon_ID and id_taxon_ID then
if not (page_taxon_ID == id_taxon_ID and page_assesment_ID == id_assesment_ID) then
msg = '|page= / |id= mismatch'
end
end
if page_taxon_ID and url_taxon_ID then
if page_taxon_ID and url_taxon_ID then
if (page_taxon_ID ~= url_taxon_ID or ((page_assesment_ID ~= url_assesment_ID) and not args.errata)) then
if not (page_taxon_ID == url_taxon_ID and page_assesment_ID == url_assesment_ID) then
table.insert (error_msgs_t, '|page= / |url= mismatch');
msg = '|page= / |url= mismatch'
end
end

if id_taxon_ID and url_taxon_ID then
if not (id_taxon_ID == url_taxon_ID and id_assesment_ID == url_assesment_ID) then
msg = '|id= / |url= mismatch'
end
end
end
end
end
end


if msg then
return doi_taxon_ID, doi_assesment_ID, page_taxon_ID, page_assesment_ID;
msg = '<span class="error" style="font-size:100%">{{cite iucn}}: error: ' .. msg .. ' ([[Template:Cite iucn|help]])</span>'
end
return doi_taxon_ID, doi_assesment_ID, page_taxon_ID, page_assesment_ID, id_taxon_ID, id_assesment_ID, msg
end
end


Line 76: Line 99:
]]
]]


local function iucn_volume_check (args, maint_msgs_t)
local function iucn_volume_check (args)
local vol = args.volume;
local vol = args.volume;
local date = args.date or args.year;
local date = args.date or args.year;
local doi = args.doi and args.doi:match ('[Ii][Uu][Cc][Nn]%.[Uu][Kk]%.(%d%d%d%d)')
local doi = args.doi and args.doi:match ('[Ii][Uu][Cc][Nn]%.[Uu][Kk]%.(%d%d%d%d)')
local msg

if vol and date and (vol ~= date) then
if vol and date then
table.insert (maint_msgs_t, '|volume= / |date= mismatch');
msg = (vol ~= date) and '|volume= / |date= mismatch' or msg
end
end
if vol and doi then

if vol and doi and ((vol ~= doi) and not args.amends) then
msg = (vol ~= doi) and '|volume= / |doi= mismatch' or msg
table.insert (maint_msgs_t, '|volume= / |doi= mismatch');
end
end
if date and doi then

if date and doi and ((doi ~= date) and not args.amends) then
msg = (doi ~= date) and '|date= / |doi= mismatch' or msg
table.insert (maint_msgs_t, '|date= / |doi= mismatch');
end
end
return msg
end
end


Line 109: Line 133:


local function cite (frame)
local function cite (frame)
local error_msgs_t = {}; -- holds error messages for rendering
local error_msgs = {}; -- holds error messages for rendering
local maint_msgs_t = {}; -- holds hidden maint messages for rendering
local maint_msgs = {}; -- holds hidden maint messages for rendering
local namespace = mw.title.getCurrentTitle().namespace; -- used for categorization
local namespace = mw.title.getCurrentTitle().namespace; -- used for categorization
local args = getArgs (frame); -- local copy of template arguments
local args = getArgs (frame); -- local copy of template arguments


local missing_title = not args.title -- special case that results from script writing {{cite iucn}} template from bare iucn url
if args.title and (args.title:match (errata_pattern) or args.title:match (amendment_pattern)) then
-- don't duplicate cs1|2 error message; don't duplicate {{cite iucn}} error cat
table.insert (error_msgs_t, 'title has extraneous text'); -- announce that this template has has errata or amendment text
-- TODO: remove this when the error category has been cleared of missing title errors
end


local doi_taxon_ID, doi_assesment_ID; -- all of these contain the same identifying info in slightly
local doi_taxon_ID, doi_assesment_ID -- all of these contain the same identifying info in slightly
local page_taxon_ID, page_assesment_ID; -- different forms. when any combination of these is present,
local page_taxon_ID, page_assesment_ID -- different forms. when any combination of these is present,
local id_taxon_ID, id_assesment_ID -- they must all agree
local msg -- this holds error messages; nil on success


doi_taxon_ID, doi_assesment_ID, page_taxon_ID, page_assesment_ID = iucn_identifiers_get (args, error_msgs_t);
doi_taxon_ID, doi_assesment_ID, page_taxon_ID, page_assesment_ID, id_taxon_ID, id_assesment_ID, msg = iucn_identifiers_get (args);
if msg then

args.id = nil -- unset; not supported
table.insert (error_msgs, msg); -- malformed or mismatched identifiers
end
args.id = nil -- unset; no longer needed if it was set


local url_taxon_ID = page_taxon_ID or doi_taxon_ID; -- select for use in url that we will create
local url_taxon_ID = page_taxon_ID or id_taxon_ID or doi_taxon_ID; -- select for use in url that we will create
local url_assesment_ID = page_assesment_ID or doi_assesment_ID;
local url_assesment_ID = page_assesment_ID or id_assesment_ID or doi_assesment_ID
local url = args.url;
local url = args.url
if url then
if url then
if url:find ('iucnredlist.org/details/', 1, true) then -- old-form url
if url:find ('iucnredlist.org/details/', 1, true) then -- old-form url
Line 136: Line 164:
args.url = args.url:gsub ("http:", "https:") -- sometimes works with redirect on iucn site
args.url = args.url:gsub ("http:", "https:") -- sometimes works with redirect on iucn site
end
end
table.insert (maint_msgs_t, 'old-form url') -- announce that this template has has an old-form url
table.insert (maint_msgs, 'old-form url') -- announce that this template has has an old-form url
elseif url:find ('iucnredlist.org/species/', 1, true) then -- new-form url
elseif url:find ('iucnredlist.org/species/', 1, true) then -- new-form url
-- table.insert (maint_msgs_t, 'new-form url') --TODO: restore this line when most new-form urls have been removed from article space -- announce that this template has has an new-form url
-- table.insert (maint_msgs, 'new-form url') --TODO: restore this line when most new-form urls have been removed from article space -- announce that this template has has an new-form url
else
else
table.insert (error_msgs_t, 'unknown url') -- emit error message
table.insert (maint_msgs, 'unknown url') -- announce that this template has has some sort of url we don't recognize
end
end
end
end
Line 148: Line 176:
args.url = "https://www.iucnredlist.org/species/" .. url_taxon_ID .. '/' .. url_assesment_ID
args.url = "https://www.iucnredlist.org/species/" .. url_taxon_ID .. '/' .. url_assesment_ID
else
else
table.insert (error_msgs_t, 'no identifier') -- emit error message
table.insert (maint_msgs, 'no identifier') -- TODO: raise this to error status?
end
end
end
end
Line 157: Line 185:
end
end
iucn_volume_check (args, maint_msgs_t); -- |volume=, |year= (|date=), |doi= must all refer to the same volume
msg = iucn_volume_check (args); -- |volume=, |year= (|date=), |doi= must all refer to the same volume
if msg then
table.insert (maint_msgs, msg);
end


if not args.volume and (args.year or args.date) then
if not args.volume and (args.year or args.date) then
args.volume = args.year or args.date
args.volume = args.year or args.date
end
if args.errata then
args['orig-date'] = 'errata version of ' .. (args.year or args.date or args.volume) .. ' assessment';
args.date = args.errata; -- update publication data to errata year
args.year = nil; -- unset these as no longer needed
args.errata = nil;
elseif args.amends then
args['orig-date'] = 'amended version of ' .. args.amends .. ' assessment';
args.amends = nil; -- unset as no longer needed
end
end
-- add free-to-read icon to mark a correctly formed doi
-- add free-to-read icon to mark a correctly formed doi
args['doi-access'] = args.doi and args.doi:match ('10%.2305/[Ii][Uu][Cc][Nn].+[Tt]%d+[Aa]%d+%.%a%a') and 'free' or nil
args['doi-access'] = args.doi and args.doi:match ('10%.2305/[Ii][Uu][Cc][Nn].+[Tt]%d+[Aa]%d+%.[Ee][Nn]') and 'free' or nil
local out_t = {};
if error_msgs_t[1] then
table.insert (out_t, ' <span class="error" style="font-size:100%">{{[[Template:cite iucn|cite iucn]]}}: error: ');
table.insert (out_t, table.concat (error_msgs_t, ', '));
table.insert (out_t, ' ([[Template:Cite iucn#Error messages|help]])');
if (0 == namespace) then
table.insert (out_t, '[[Category:cite IUCN errors]]');
end
table.insert (out_t, '</span>');
end

if maint_msgs_t[1] then
table.insert (out_t, '<span class="citation-comment" style="display: none; color: #33aa33; margin-left: 0.3em;">');
if not error_msgs_t[1] then
table.insert (out_t, '{{[[Template:cite iucn|cite iucn]]}}: ')
table.insert (out_t, table.concat (maint_msgs_t, ', '));
table.insert (out_t, ' ([[Template:Cite iucn#Maintenance messages|help]])');
if (0 == namespace) then
table.insert (out_t, '[[Category:cite IUCN maint]]');
end
end
table.insert (out_t, '</span>');
end

if (not args['doi-access']) and (0 == namespace) then
table.insert (out_t, '[[Category:cite IUCN without doi]]');
end
return frame:expandTemplate{ title = 'cite journal', args = args } .. -- the template
return frame:expandTemplate{ title = 'cite journal', args = args } .. -- the template
(((0 == #error_msgs) and missing_title) and ('[[Category:cite iucn errors]]') or '') .. -- special case to not duplicate cs1|2 err msg or cite iucn error cat
table.concat (out_t); -- error and maint messages and categories
((0 < #error_msgs) and table.concat (error_msgs, ', ') or '') .. -- the error messages
end
(((0 < #error_msgs) and (0 == namespace)) and ('[[Category:cite iucn errors]]') or '') .. -- error category when in mainspace

((0 < #maint_msgs) and ('<span class="citation-comment" style="display: none; color: #33aa33; margin-left: 0.3em;">' .. table.concat (maint_msgs, ', ') .. '</span>') or '') .. -- the maint messages

(((0 < #maint_msgs) and (0 == namespace)) and ('[[Category:cite iucn maint]]') or '') -- maint category when in mainspace
--[=[-------------------------< E T _ A L _ P A T T E R N S >--------------------------------------------------

This adapted from Module:Citation/CS1/Configuration

This table provides Lua patterns for the phrase "et al" and variants in a name.

]=]

local et_al_patterns = {
"[;,]? *[\"']*%f[%a][Ee][Tt]%.? *[Aa][Ll][%.;,\"']*$", -- variations on the 'et al' theme
"[;,]? *[\"']*%f[%a][Ee][Tt]%.? *[Aa][Ll][Ii][AaIi][Ee]?[%.;,\"']*$", -- variations on the 'et alia', 'et alii' and 'et aliae' themes (false positive 'et aliie' unlikely to match)
"[;,]? *%f[%a]and [Oo]thers", -- an alternative to et al.
}


--[[---------------------< N A M E _ H A S _ E T A L >--------------------------

This adapted from Module:Citation/CS1

Evaluates the content of a name for variations on the theme of et al. If found,
returns true; nil else

]]

local function name_has_etal (name)
local etal;

if name then -- name can be nil in which case just return
name = name:gsub ('%b<>', ''); -- remove any html markup (typically <i>...</i>)
for _, pattern in ipairs (et_al_patterns) do -- loop through all of the patterns
if name:match (pattern) then -- if this 'et al' pattern is found in name
return true; -- has etal, so return true
end
end
end
end
end


Line 253: Line 212:
assumes that parenthetical text at the end of the author-name-list is a collaboration
assumes that parenthetical text at the end of the author-name-list is a collaboration
Name, I.I., & Name, I.I. (Colaboration name)
Name, I.I., & Name, I.I. (Colaboration name)

assumes that <i>et al.</i> is the last name in a list of names


]]
]]


--local function author_names_get (raw_iucn_cite)
local function author_names_get (raw_iucn_cite)
local function author_names_get (raw_iucn_cite, params_t) -- EXPERIMENT
local list = {}; -- table that holds name list parts
local list = {}; -- table that holds name list parts
local author_names = raw_iucn_cite:match ('^([^%d]-)%s+%d%d%d%d'); -- extract author name-list from raw iucn citation
local author_names = raw_iucn_cite:match ('^([^%d]-)%s+%d%d%d%d'); -- extract author name-list from raw iucn citation
Line 269: Line 225:
end
end
local names = author_names:gsub ('%.?,?%s+&%s+', '.|'); -- replace 'separators' (<optional dot><optional comma><space><ampersand><space>) with <dot><pipe>
local names = author_names:gsub ('%.?,?%s+&%s+', '.|'):gsub ('%.,%s+', '.|'); -- replace 'separators' (<dot><comma><space> and <opt. dot><opt. comma><space><ampersand><space>) with <dot><pipe>
names = names:gsub ('%.,%s*', '.|'); -- replace 'separators' (<dot><comma><optional space>) with <dot><pipe>
names = names:gsub ('(%.%u),', '%1.|'); -- special case for when last initial is missing its trailing dot
list = mw.text.split (names, '|'); -- split the string on the pipes into entries in list{}
list = mw.text.split (names, '|'); -- split the string on the pipes into entries in list{}
if 0 == #list then
if 0 == #list then
params_t['author'] = author_names; -- EXPERIMENT
return table.concat ({'|author=', author_names}) -- no 'names' of the proper form; return the original as a single |author= parameter
return table.concat ({'|author=', author_names}), params_t; -- EXPERIMENT -- no 'names' of the proper form; return the original as a single |author= parameter
-- return table.concat ({'|author=', author_names}) -- no 'names' of the proper form; return the original as a single |author= parameter
else
else
for i, name in ipairs (list) do -- spin through the list and
for i, name in ipairs (list) do -- spin through the list and
-- list[i] = table.concat ({'|author', i, '=', name}); -- add |authorn= parameter names
if name_has_etal (name) then -- if this name has some form of 'et al'
list[i] = table.concat ({'|author', (i == 1) and '' or i, '=', name}); -- add |authorn= parameter names; create |author= instead of |author1=
params_t['display-authors'] = 'etal'; -- EXPERIMENT
list[i] = '|display-authors=etal'; -- add |dispaly-authors=etal parameter and
break; -- assume that the etal was the last 'name' so stop processing names
else
params_t['author' .. i] = name; -- EXPERIMENT
list[i] = table.concat ({'|author', (i == 1) and '' or i, '=', name}); -- add |authorn= parameter names; create |author= instead of |author1=
end
end
end
if collaboration then
if collaboration then
params_t['collaboration'] = collaboration; -- EXPERIMENT
table.insert (list, table.concat ({'|collaboration', '=', collaboration})); -- add |collaboration= parameter
table.insert (list, table.concat ({'|collaboration', '=', collaboration})); -- add |collaboration= parameter
end
end
Line 338: Line 283:
end
end


-- return table.concat ({' |title=', title}); -- return the |title= parameter
return table.concat ({' |title=', title}); -- return the |title= parameter
return title; -- return the formatted title
end
end


Line 352: Line 296:


local function make_cite_iucn (frame)
local function make_cite_iucn (frame)
local args_t = getArgs (frame);
local args = getArgs (frame);
local raw_iucn_cite = args_t[1];
local raw_iucn_cite = args[1];

local template_t = {'{{cite iucn '}; -- sequence that holds the {{cite iucn}} template as it is being assembled; for nowiki'd output
local params_t = {}; -- table of parameter/value pairs for substing
local template = {'{{cite iucn '}; -- table that holds the {{cite iucn}} template as it is being assembled
local year, volume, page, doi, accessdate;
local year, volume, page, doi, accessdate;


year = raw_iucn_cite:match ('^%D+(%d%d%d%d)');
year = raw_iucn_cite:match ('^%D+(%d%d%d%d)');
volume, page = raw_iucn_cite:match ('(%d%d%d%d):%s+(e%.T%d+A+%d+)%.%s?');
volume, page = raw_iucn_cite:match ('(%d%d%d%d):%s+(e%.T%d+A+%d+)%.%s');
doi = raw_iucn_cite:match ('10%.2305/IUCN%.UK%.[%d%-]+%.RLTS%.T%d+A%d+%.%a%a');
doi = raw_iucn_cite:match ('10%.2305/IUCN%.UK%.[%d%-]+%.RLTS%.T%d+A%d+%.en');


accessdate = raw_iucn_cite:match ('Accessed on (.-)%.?$') or raw_iucn_cite:match ('Downloaded on (.-)%.?$'); -- 'Downloaded' 'Accessed' change occured December 2021;
accessdate = raw_iucn_cite:match ('Downloaded on (.-)%.?$'):gsub ('^0', ''); -- strips leading 0 in day 01 January 2020 -> 1 January 2020
accessdate = accessdate:gsub ('^0', ''); -- strips leading 0 in day 01 January 2020 -> 1 January 2020


table.insert (template_t, author_names_get (raw_iucn_cite, params_t)); -- add author name parameters; as a single string to <template_t>; as individual entries to <params_t>
table.insert (template, author_names_get (raw_iucn_cite)); -- add string of author name parameters
table.insert (template, table.concat ({' |year=', year})); -- add formatted year
table.insert (template, title_get (raw_iucn_cite)); -- add formatted title
table.insert (template, table.concat ({' |volume=', volume})); -- add formatted volume
table.insert (template, table.concat ({' |page=', page})); -- add formatted page
table.insert (template, table.concat ({' |doi=', doi})); -- add formatted doi
table.insert (template, table.concat ({' |access-date=', accessdate})); -- add formatted access-date
table.insert (template, '}}'); -- close the template


if args[2] then -- if anything in args[2], write a nowiki'd version that editors can copy into <ref> tags
table.insert (template_t, table.concat ({' |year=', year})); -- add formatted year
return table.concat ({'<code>', frame:callParserFunction ('#tag:nowiki', table.concat (template)), '</code>'})
params_t.year = year;
local title = title_get (raw_iucn_cite);
local type_p = title:match (green_status_pattern);
if type_p then
title = title:match ('^([^%(]+)%s*%(');
table.insert (template_t, table.concat ({' |type=', type_p})); -- add formatted errata
params_t.type = type_p;
end
end
if args['ref'] then

return '<ref name=' .. args['ref'] .. '>' .. table.concat (template) .. '</ref>'
local errata = title:match (errata_pattern); -- nil unless IUCN citation has errata annotation; else year that this errata published (|date=)
if errata then
table.insert (template_t, table.concat ({' |errata=', errata})); -- add formatted errata
params_t.errata = errata;
title = title:gsub (errata_pattern, ''); -- remove errata annotation
end
end
return table.concat (template); -- the subst'd version
local amends = title:match (amendment_pattern); -- nil unless IUCN citation has amendment annotation; else year that this assessment amends (|orig-date=)
if amends then
table.insert (template_t, table.concat ({' |amends=', amends})); -- add year of assessment that this assessment amends
params_t.amends = amends;
title = title:gsub (amendment_pattern, ''); -- remove amendment annotation
end

table.insert (template_t, table.concat ({' |title=', title})); -- add formatted title
params_t.title = title;
table.insert (template_t, table.concat ({' |volume=', volume})); -- add formatted volume
params_t.volume = volume;
table.insert (template_t, table.concat ({' |page=', page})); -- add formatted page
params_t.page = page;
table.insert (template_t, table.concat ({' |doi=', doi})); -- add formatted doi
params_t.doi = doi;

table.insert (template_t, table.concat ({' |access-date=', accessdate})); -- add formatted access-date
params_t['access-date'] = accessdate;

table.insert (template_t, '}}'); -- close the template

if args_t[2] then -- if anything in args_t[2], write a nowiki'd version that editors can copy into <ref> tags
return frame:preprocess (table.concat ({'<syntaxhighlight lang="wikitext" inline="1">', table.concat (template_t), '</syntaxhighlight>'})); -- caveat lector: if left long enough anomiebot will subst this
end

if args_t['ref'] then -- enable subst of ref tags with name
return frame:preprocess ('<ref name=' .. args_t['ref'] .. '>' .. table.concat (template_t) .. '</ref>')
end

return frame:preprocess (table.concat (template_t)); -- render {{cite iucn}} template; substable
end
end