Difference between revisions of "Module:Cite iucn"
test>Trappist the monk (added make_cite_iucn() and supporting functions from Module:Sandbox/trappist the monk/make cite iucn; deleted p{} and data{};) |
m (64 revisions imported) |
||
| (15 intermediate revisions by 7 users not shown) | |||
| Line 1: | Line 1: | ||
require('Module:No globals'); | require('Module:No globals'); | ||
| − | + | local getArgs = require ('Module:Arguments').getArgs; | |
| − | local | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| Line 40: | Line 22: | ||
if args.doi then | if args.doi then | ||
| − | doi_taxon_ID, doi_assesment_ID = args.doi:match (' | + | doi_taxon_ID, doi_assesment_ID = args.doi:match ('[Tt](%d+)[Aa](%d+)%.en$') |
if not doi_taxon_ID then | if not doi_taxon_ID then | ||
msg = 'malformed |doi= identifier' | msg = 'malformed |doi= identifier' | ||
| Line 46: | Line 28: | ||
end | end | ||
if args.page then | if args.page then | ||
| − | page_taxon_ID, page_assesment_ID = args.page:match ('^ | + | 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 | ||
msg = 'malformed |page= identifier' | msg = 'malformed |page= identifier' | ||
| Line 120: | Line 102: | ||
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 (' | + | local doi = args.doi and args.doi:match ('[Ii][Uu][Cc][Nn]%.[Uu][Kk]%.(%d%d%d%d)') |
local msg | local msg | ||
| Line 154: | Line 136: | ||
local maint_msgs = {}; -- 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 | + | local args = getArgs (frame); -- local copy of template arguments |
| − | |||
| − | |||
| − | local missing_title = not | + | local missing_title = not args.title -- special case that results from script writing {{cite iucn}} template from bare iucn url |
-- don't duplicate cs1|2 error message; don't duplicate {{cite iucn}} error cat | -- don't duplicate cs1|2 error message; don't duplicate {{cite iucn}} error cat | ||
| + | -- TODO: remove this when the error category has been cleared of missing title errors | ||
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 | ||
| Line 166: | Line 147: | ||
local msg -- this holds error messages; nil on success | local msg -- this holds error messages; nil on success | ||
| − | doi_taxon_ID, doi_assesment_ID, page_taxon_ID, page_assesment_ID, id_taxon_ID, id_assesment_ID, msg = iucn_identifiers_get ( | + | 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 | if msg then | ||
table.insert (error_msgs, msg); -- malformed or mismatched identifiers | table.insert (error_msgs, msg); -- malformed or mismatched identifiers | ||
end | end | ||
| − | + | args.id = nil -- unset; no longer needed if it was set | |
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_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 id_assesment_ID or doi_assesment_ID | local url_assesment_ID = page_assesment_ID or id_assesment_ID or doi_assesment_ID | ||
| − | local 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 181: | Line 162: | ||
url = nil -- unset; we'll create new url below | url = nil -- unset; we'll create new url below | ||
else -- here when old-form but no identifier that we can use to create new url | else -- here when old-form but no identifier that we can use to create new url | ||
| − | + | args.url = args.url:gsub ("http:", "https:") -- sometimes works with redirect on iucn site | |
end | end | ||
table.insert (maint_msgs, '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 | ||
| Line 193: | Line 174: | ||
if not url then -- when no url or unset old-form url | if not url then -- when no url or unset old-form url | ||
if url_taxon_ID then | if url_taxon_ID then | ||
| − | + | args.url = "https://www.iucnredlist.org/species/" .. url_taxon_ID .. '/' .. url_assesment_ID | |
else | else | ||
table.insert (maint_msgs, 'no identifier') -- TODO: raise this to error status? | table.insert (maint_msgs, 'no identifier') -- TODO: raise this to error status? | ||
| Line 200: | Line 181: | ||
-- add journal if not provided (TODO decide if this should override provided value) | -- add journal if not provided (TODO decide if this should override provided value) | ||
| − | if not | + | if not args['journal'] and not args['work'] then |
| − | + | args['journal'] = "[[IUCN Red List|IUCN Red List of Threatened Species]]" | |
end | end | ||
| − | |||
| − | |||
| − | msg = iucn_volume_check ( | + | msg = iucn_volume_check (args); -- |volume=, |year= (|date=), |doi= must all refer to the same volume |
if msg then | if msg then | ||
table.insert (maint_msgs, msg); | table.insert (maint_msgs, msg); | ||
end | end | ||
| − | if not | + | if not args.volume and (args.year or args.date) then |
| − | + | args.volume = args.year or args.date | |
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+%.[Ee][Nn]') and 'free' or nil | |
| − | return frame:expandTemplate{ title = 'cite journal', args = | + | 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 | (((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 | ||
((0 < #error_msgs) and table.concat (error_msgs, ', ') or '') .. -- the error messages | ((0 < #error_msgs) and table.concat (error_msgs, ', ') or '') .. -- the error messages | ||
| Line 230: | Line 209: | ||
creates a list of individual |authorn= parameters from the list of names provided in the raw iucn citation. names | creates a list of individual |authorn= parameters from the list of names provided in the raw iucn citation. names | ||
must have the form: Surname, I. (more than one 'I.' pair allowed but no spaces between I. pairs) | must have the form: Surname, I. (more than one 'I.' pair allowed but no spaces between I. pairs) | ||
| + | |||
| + | assumes that parenthetical text at the end of the author-name-list is a collaboration | ||
| + | Name, I.I., & Name, I.I. (Colaboration name) | ||
]] | ]] | ||
| Line 236: | Line 218: | ||
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 | ||
| + | local collaboration = author_names:match ('%s*(%b())$'); -- get collaboration name if it exists | ||
| − | local names = author_names:gsub ('%.,?%s+&%s+', '.|'):gsub ('%.,%s+', '.|'); -- replace 'separators' (<dot><comma><space> and <dot><opt. comma><space><ampersand><space>) with <dot><pipe> | + | if collaboration then -- when there is a colaboration |
| + | collaboration = collaboration:gsub ('[%(%)]', ''); -- remove bounding parentheses | ||
| + | author_names = author_names:gsub ('%s*(%b())$', ''); -- and remove collaboration from author-name-list | ||
| + | end | ||
| + | |||
| + | 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> | ||
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{} | ||
| Line 244: | Line 232: | ||
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}); | + | -- list[i] = table.concat ({'|author', i, '=', name}); -- add |authorn= parameter names |
| + | list[i] = table.concat ({'|author', (i == 1) and '' or i, '=', name}); -- add |authorn= parameter names; create |author= instead of |author1= | ||
| + | end | ||
| + | if collaboration then | ||
| + | table.insert (list, table.concat ({'|collaboration', '=', collaboration})); -- add |collaboration= parameter | ||
end | end | ||
return table.concat (list, ' '); -- make a big string and return that | return table.concat (list, ' '); -- make a big string and return that | ||
| Line 298: | Line 290: | ||
parses apart an iucn-format citation copied from their webpage and reformats that into a {{cite iucn}} template for substing | parses apart an iucn-format citation copied from their webpage and reformats that into a {{cite iucn}} template for substing | ||
| + | |||
| + | automatic substing by User:AnomieBOT/docs/TemplateSubster | ||
]] | ]] | ||
local function make_cite_iucn (frame) | local function make_cite_iucn (frame) | ||
| − | local raw_iucn_cite = | + | local args = getArgs (frame); |
| + | local raw_iucn_cite = args[1]; | ||
local template = {'{{cite iucn '}; -- table that holds the {{cite iucn}} template as it is being assembled | local template = {'{{cite iucn '}; -- table that holds the {{cite iucn}} template as it is being assembled | ||
| Line 310: | Line 305: | ||
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+%.en'); | doi = raw_iucn_cite:match ('10%.2305/IUCN%.UK%.[%d%-]+%.RLTS%.T%d+A%d+%.en'); | ||
| − | accessdate = raw_iucn_cite:match ('Downloaded on ( | + | |
| − | + | accessdate = raw_iucn_cite:match ('Downloaded on (.-)%.?$'):gsub ('^0', ''); -- strips leading 0 in day 01 January 2020 -> 1 January 2020 | |
| + | |||
table.insert (template, author_names_get (raw_iucn_cite)); -- add string of author name parameters | 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, table.concat ({' |year=', year})); -- add formatted year | ||
| Line 321: | Line 317: | ||
table.insert (template, '}}'); -- close the template | table.insert (template, '}}'); -- close the template | ||
| − | return table.concat (template); | + | if args[2] then -- if anything in args[2], write a nowiki'd version that editors can copy into <ref> tags |
| + | return table.concat ({'<code>', frame:callParserFunction ('#tag:nowiki', table.concat (template)), '</code>'}) | ||
| + | end | ||
| + | if args['ref'] then -- enable subst of ref tags with name | ||
| + | return '<ref name=' .. args['ref'] .. '>' .. table.concat (template) .. '</ref>' | ||
| + | end | ||
| + | return table.concat (template); -- the subst'd version | ||
end | end | ||
Latest revision as of 12:16, 6 September 2020
{{Module rating }}
Contents
Usage
{{#invoke:Cite iucn|cite}} – for {{cite iucn}}
{{#invoke:Cite iucn|make_cite_iucn}} – for {{make cite iucn}}
Background information
Old-style and new-style IUCN urls
Until late 2018, the IUCN assessments used urls of form
http://www.iucnredlist.org/details/15955/0- where 15955 is the taxon ID and the “0” suffix indicates a global assessment (other single digit numbers code for various regional assessments).
From around September 2018, the IUCN switched to a new format for the url, of the form
https://www.iucnredlist.org/species/15955/50659951- where the 15955 is the taxon ID and a unique suffix identies a version of an assessment. This left all Wikipedia links to IUCN assesssments as dead links.
Shortly afterwards the IUCN produced a backup of the old system with links of the form
http://oldredlist.iucnredlist.org/details/15955/0- which uses an old-style url form on the oldredlist subdomain. Many citations were switched over to this url. However, this subdomain was shut down near the end of 2019, leaving many dead links generating 502 Bad Gateway errors.
Current IUCN citations
A typical IUCN citation, as given on their assessment pages, is now of the form:
- Goodrich, J., Lynam, A., Miquelle, D., Wibisono, H., Kawanishi, K., Pattanavibool, A., Htun, S., Tempa, T., Karki, J., Jhala, Y. & Karanth, U. 2015. Panthera tigris. The IUCN Red List of Threatened Species 2015: e.T15955A50659951. http://dx.doi.org/10.2305/IUCN.UK.2015-2.RLTS.T15955A50659951.en. Downloaded on 19 December 2019.
- where the electronic page number
e.T15955A50659951contains the taxon ID (between the T and A) and the assessment ID (after the A). These two identifying numbers are also contained in the doi.
When there is an amendment to an assessment, a new assessment number is assigned, which causes a change in the electronic page number and the url of the page.
The behaviour of the doi is unusual. A new assessment does not cause a new doi, it retains the original assessment number. If this is used by a template to construct a url, it will be to the original version of the assessment. However, if the url of the doi is followed, the IUCN doi resolver redirects to the latest assessment. The target of the doi has changed to the revised version of the IUCN assessment. Thus if the template uses the doi url the linked page will change from the one seen by the editor who added the citation.
Therefore this module will create a url with the following order of precedence:
- Use the electronic page number set by the
|page=parameter to generate the url. - Use the
|id=to generate the url if it is of the two new-style two part form, i.e.TAXON_ID/ASSESSMENT_ID(e.g.15955/50659951) - Use the
|doi=parameter to generate the url. This is last choice because it uses the number of the original assessment even when the assessment has been amended.
When none of the above options are available, and when |url= has the old form, this module will change the scheme from http:// to https:// in an attempt to make a working link (see next section).
Legacy issue with old-style urls
There is still a legacy issue with old-style IUCN urls, which are still used in many Wikipedia citations.
Some months after the change to the new-style urls, the IUCN introduced redirects for the old-style urls that link to the appropriate pages addressed by the new style url. In most cases these redirects will work. So the oldstyle url for the tiger https://www.iucnredlist.org/details/15955/0 correctly links to the assessment at https://www.iucnredlist.org/species/15955/50659951 (see tiger).
However, not all assessments redirect. For instance, the oldstyle url for the Bengal mud eel http://www.iucnredlist.org/details/166410/0 links to the home page (see Bengal mud eel).
This failure of some old style url to be redirected is unexpected, as the redirect function of the IUCN API does link to the correct page. A url of the form
https://apiv3.iucnredlist.org/api/v3/taxonredirect/166410- will link to the correct page, even in cases where the automatic redirect faile, e.g. the Bengal mud eel.
However, redirects are not available when the taxon id has been replaced and an error in JSON format is returned (e.g. for house sparrow).
New taxon IDs
There is another case where the old style urls gives dead links, when the taxon ID has changed. For instance, the Italian sparrow was split off from the house sparrow as a new species and both assigned new taxon IDs. This left any old style urls to the original assessment as dead links.
- Old-style url
http://www.iucnredlist.org/details/149100/0for house sparrow (dead link on old taxon id149100) - New-style url
https://www.iucnredlist.org/species/103818789/155522130for house sparrow (Passer domesticus), using new taxon id and assessment number103818789/155522130. - New-style url
https://www.iucnredlist.org/species/103819014/132196181for Italian sparrow (Passer italiae), using new taxon id and assessment number103819014/132196181.
In this case there is no action the template/module can take to resolve the issue. Active intervention of an editor is required.
require('Module:No globals');
local getArgs = require ('Module:Arguments').getArgs;
--[[--------------------------< I U C N _ I D E N T I F I E R S _ G E T >--------------------------------------
cs1|2 templates cite single sources; when the identifiers in |doi=, |id=, and |page= are different from each other
then the template is attempting to cite multiple sources. This function evaluates the identifier portions of these
parameters. returns seven values: identifyier parts (or nil when parameter not used) and a message (nil on success,
error message else)
the identifier portions of the several parameters must be properly formed
]]
local function iucn_identifiers_get (args)
local doi_taxon_ID, doi_assesment_ID
local page_taxon_ID, page_assesment_ID
local id_taxon_ID, id_assesment_ID
local url_taxon_ID, url_assesment_ID
local msg
if args.doi then
doi_taxon_ID, doi_assesment_ID = args.doi:match ('[Tt](%d+)[Aa](%d+)%.en$')
if not doi_taxon_ID then
msg = 'malformed |doi= identifier'
end
end
if args.page then
page_taxon_ID, page_assesment_ID = args.page:match ('^[eE]%.[Tt](%d+)[Aa](%d+)$')
if not page_taxon_ID then
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
if args.url then
if args.url:match ('https://www.iucnredlist.org/species/') then -- must be a 'new-form' url
url_taxon_ID, url_assesment_ID = args.url:match ('/species/(%d+)/(%d+)')
if not url_taxon_ID then
msg = 'malformed |url= identifier'
end
end
end
if not msg then
if doi_taxon_ID and page_taxon_ID then
if not (doi_taxon_ID == page_taxon_ID and doi_assesment_ID == page_assesment_ID) then
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
if doi_taxon_ID and url_taxon_ID then
if not (doi_taxon_ID == url_taxon_ID and doi_assesment_ID == url_assesment_ID) then
msg = '|doi= / |url= mismatch'
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 not (page_taxon_ID == url_taxon_ID and page_assesment_ID == url_assesment_ID) then
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
if msg then
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
--[[--------------------------< I U C N _ V O L U M E _ C H E C K >--------------------------------------------
compares volume in |volume= (if present) against year in |date= or |year= (if present) against volume in |doi= (if present)
returns nil if all that are present are correct; message else
]]
local function iucn_volume_check (args)
local vol = args.volume;
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 msg
if vol and date then
msg = (vol ~= date) and '|volume= / |date= mismatch' or msg
end
if vol and doi then
msg = (vol ~= doi) and '|volume= / |doi= mismatch' or msg
end
if date and doi then
msg = (doi ~= date) and '|date= / |doi= mismatch' or msg
end
return msg
end
--[[--------------------------< C I T E >----------------------------------------------------------------------
Wraps {{cite journal}}:
takes cite journal parameters but updates old style url using electronic page number
page should be in format e.T13922A45199653
the url uses 13922/45199653
so we need to extract the number between T and A (taxon ID) and the number after A (assessment ID)
the target url is https://www.iucnredlist.org/species/13922/45199653
usage: {{#invoke:iucn|cite}}
template: {{Template:Cite iucn}}
]]
local function cite (frame)
local error_msgs = {}; -- holds error messages for rendering
local maint_msgs = {}; -- holds hidden maint messages for rendering
local namespace = mw.title.getCurrentTitle().namespace; -- used for categorization
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
-- don't duplicate cs1|2 error message; don't duplicate {{cite iucn}} error cat
-- TODO: remove this when the error category has been cleared of missing title errors
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 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, id_taxon_ID, id_assesment_ID, msg = iucn_identifiers_get (args);
if msg then
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 id_taxon_ID or doi_taxon_ID; -- select for use in url that we will create
local url_assesment_ID = page_assesment_ID or id_assesment_ID or doi_assesment_ID
local url = args.url
if url then
if url:find ('iucnredlist.org/details/', 1, true) then -- old-form url
if url_taxon_ID then -- when there is an identifier
url = nil -- unset; we'll create new url below
else -- here when old-form but no identifier that we can use to create new url
args.url = args.url:gsub ("http:", "https:") -- sometimes works with redirect on iucn site
end
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
-- 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
table.insert (maint_msgs, 'unknown url') -- announce that this template has has some sort of url we don't recognize
end
end
if not url then -- when no url or unset old-form url
if url_taxon_ID then
args.url = "https://www.iucnredlist.org/species/" .. url_taxon_ID .. '/' .. url_assesment_ID
else
table.insert (maint_msgs, 'no identifier') -- TODO: raise this to error status?
end
end
-- add journal if not provided (TODO decide if this should override provided value)
if not args['journal'] and not args['work'] then
args['journal'] = "[[IUCN Red List|IUCN Red List of Threatened Species]]"
end
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
args.volume = args.year or args.date
end
-- 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+%.[Ee][Nn]') and 'free' or nil
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
((0 < #error_msgs) and table.concat (error_msgs, ', ') or '') .. -- the error messages
(((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
end
--[[--------------------------< A U T H O R _ L I S T _ M A K E >----------------------------------------------
creates a list of individual |authorn= parameters from the list of names provided in the raw iucn citation. names
must have the form: Surname, I. (more than one 'I.' pair allowed but no spaces between I. pairs)
assumes that parenthetical text at the end of the author-name-list is a collaboration
Name, I.I., & Name, I.I. (Colaboration name)
]]
local function author_names_get (raw_iucn_cite)
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 collaboration = author_names:match ('%s*(%b())$'); -- get collaboration name if it exists
if collaboration then -- when there is a colaboration
collaboration = collaboration:gsub ('[%(%)]', ''); -- remove bounding parentheses
author_names = author_names:gsub ('%s*(%b())$', ''); -- and remove collaboration from author-name-list
end
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>
list = mw.text.split (names, '|'); -- split the string on the pipes into entries in list{}
if 0 == #list then
return table.concat ({'|author=', author_names}) -- no 'names' of the proper form; return the original as a single |author= parameter
else
for i, name in ipairs (list) do -- spin through the list and
-- list[i] = table.concat ({'|author', i, '=', name}); -- add |authorn= parameter names
list[i] = table.concat ({'|author', (i == 1) and '' or i, '=', name}); -- add |authorn= parameter names; create |author= instead of |author1=
end
if collaboration then
table.insert (list, table.concat ({'|collaboration', '=', collaboration})); -- add |collaboration= parameter
end
return table.concat (list, ' '); -- make a big string and return that
end
end
--[[--------------------------< T I T L E _ G E T >------------------------------------------------------------
extract and format citation title; attempts to get the italic right
''binomen'' (amended or errata title)
''binomen''
''binomen'' ssp. ''subspecies''
''binomen'' subsp. ''subspecies''
''binomen'' var. ''variety''
''binomen'' subvar. ''subvariety''
all of the above may have trailing amended or errata text in parentheses
TODO: are there others?
]]
local function title_get (raw_iucn_cite)
local title = raw_iucn_cite:match ('%d%d%d%d%.%s+(.-)%s*%. The IUCN Red List of Threatened Species');
local patterns = { -- tables of string.match patterns [1] and string.gsub patterns [2]
{'(.-)%sssp%.%s+(.-)%s(%b())$', "''%1'' ssp. ''%2'' %3"}, -- binomen ssp. subspecies (zoology) with errata or amended text
{'(.-)%sssp%.%s+(.+)', "''%1'' ssp. ''%2''"}, -- binomen ssp. subspecies (zoology)
{'(.-)%ssubsp%.%s+(.-)%s(%b())$', "''%1'' subsp. ''%2'' %3"}, -- binomen subsp. subspecies (botany) with errata or amended text
{'(.-)%ssubsp%.%s+(.+)', "''%1'' subsp. ''%2''"}, -- binomen subsp. subspecies (botany)
{'(.-)%svar%.%s+(.-)%s+(%b())$', "''%1'' var. ''%2'' %3"}, -- binomen var. variety (botany) with errata or amended text
{'(.-)%svar%.%s+(.+)', "''%1'' var. ''%2''"}, -- binomen var. variety (botany)
{'(.-)%ssubvar%.%s+(.-)%s(%b())$', "''%1'' subvar. ''%2'' %3"}, -- binomen subvar. subvariety (botany) with errata or amended text
{'(.-)%ssubvar%.%s+(.+)', "''%1'' subvar. ''%2''"}, -- binomen subvar. subvariety (botany)
{'(.-)%s*(%b())$', "''%1'' %2"}, -- binomen with errata or amended text
{'(.+)', "''%1''"}, -- binomen
}
for i, v in ipairs (patterns) do -- spin through the patterns
if title:match (v[1]) then -- when a match
title = title:gsub (v[1], v[2]); -- add italics
break; -- and done
end
end
return table.concat ({' |title=', title}); -- return the |title= parameter
end
--[[--------------------------< M A K E _ C I T E _ I U C N >--------------------------------------------------
parses apart an iucn-format citation copied from their webpage and reformats that into a {{cite iucn}} template for substing
automatic substing by User:AnomieBOT/docs/TemplateSubster
]]
local function make_cite_iucn (frame)
local args = getArgs (frame);
local raw_iucn_cite = args[1];
local template = {'{{cite iucn '}; -- table that holds the {{cite iucn}} template as it is being assembled
local year, volume, page, doi, accessdate;
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');
doi = raw_iucn_cite:match ('10%.2305/IUCN%.UK%.[%d%-]+%.RLTS%.T%d+A%d+%.en');
accessdate = raw_iucn_cite:match ('Downloaded on (.-)%.?$'):gsub ('^0', ''); -- strips leading 0 in day 01 January 2020 -> 1 January 2020
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
return table.concat ({'<code>', frame:callParserFunction ('#tag:nowiki', table.concat (template)), '</code>'})
end
if args['ref'] then -- enable subst of ref tags with name
return '<ref name=' .. args['ref'] .. '>' .. table.concat (template) .. '</ref>'
end
return table.concat (template); -- the subst'd version
end
--[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------
]]
return {
cite = cite,
make_cite_iucn = make_cite_iucn,
}