Jump to content

Module:Category described in year/config/sandbox: Difference between revisions

From Wikipedia, the free encyclopedia
Content deleted Content added
m Sync
Line 1: Line 1:
require('strict')

--[[==========================================================================]]
--[[==========================================================================]]
--[[ Case sensitive conf/map table ]]
--[[ Local functions ]]
--[[==========================================================================]]
--[[==========================================================================]]


local function addOrd( i ) --12 -> 12th, etc.
local p = {
if tonumber(i) then
--[[============================================================================
local s = tostring(i)
local tens = string.match(s, '1%d$')
Any category group (e.g. Amphibians/Birds/etc.) NOT explicitly outlined here
local ones = string.match(s, '%d$')
in conf{} will follow the 'Default' tree for that group when the template is
if tens then return s..'th'
used on that cateogry.
elseif ones == '1' then return s..'st'
elseif ones == '2' then return s..'nd'
The default-style category tree is:
elseif ones == '3' then return s..'rd'
year -> century -> formal
elseif ones ~= nil then return s..'th'
year -> Animals:year -> Animals:century
end
Decadal categories are deprecated (see documentation).
end
return ''
To create a new tree, only if necessarily different from the default, copy
end
an existing tree and paste it in an appropriate spot in the table, following

the same general table format, and updating any group-specific values.
local function isNilOrEmpty( thing )
return (thing == nil or thing == '')
%year% and %century% are variables available for use in the description text,
end
and are evaluated based on the current category.

local p = {}
============================================================================]]--

--[[==========================================================================]]
['Default'] = { --"group" (Animals only; used for: Amphibians/Birds/Crustaceans/Fish/Mammals/Molluscs/Reptiles/Sponges)
--[[ External function ]]
['minyear'] = 1758, --integer; lowest possible year displayed in nav bars; defaults to 1758 per ICZN Art. 5
--[[==========================================================================]]
['year'] = { --[[Category:Birds described in 1901]]

['parent1'] = 'century', --[[Category:Birds described in the 20th century|1901]] --century or formal
function p.autodetect( frame )
['parent2'] = 'Animals', --[[Category:Animals described in 1901]]
local conf = require( 'Module:Category described in year/conf' ) --configuration module
['description'] = 'This category should only contain articles on [[species]] and notable [[subspecies]].', --adapted from [[Category:Species described in the 18th century]] & [[Category:Species described in the 21st century]]
local commonsLink = require('Module:Commons link')
},
local currentTitle = mw.title.getCurrentTitle()
['century'] = { --[[Category:Birds described in the 20th century]]
local parentArg = frame:getParent().args[1] --accept 1 unnamed category parameter if not in category namespace; required for testing/doc/etc. purposes
['parent1'] = 'formal', --[[Category:Birds by year of formal description|20th]]
local header = ' ' --header template(s), nav bar, and category description text; whitespace-initialized for convenience
['parent2'] = 'Animals', --[[Category:Animals described in the 20th century]]
local nav = nil
['description'] = '', --Century description tbd; container category, etc...
local portal = nil --for {{Portal|...}}
},
local commons = nil --for {{Commons|...}}
['formal'] = { --[[Category:Birds by year of formal description]]
local wikispecies = nil --for {{Wikispecies|...}}
['parent1'] = 'Group', --[[Category:Birds| Year]]
local description = nil
['parent2'] = 'Animals', --[[Category:Animals by year of formal description| ]]
local toc = nil
['description'] = '', --Formal description tbd; container category, etc...
local categories = {}
},
local trackingCats = {
},
[1] = '', --placeholder for [[Category:Described in year unknown category]]
[2] = '', --placeholder for [[Category:Described in year error]]
['Animals'] = { --"group"
}
['minyear'] = 1757, --integer; lowest possible year displayed in nav bars; defaults to 1758 per ICZN Art. 5
local outString = nil
['year'] = { --[[Category:Animals described in 1901]]
local bConfError = false
['parent1'] = 'century', --[[Category:Animals described in the 20th century|1901]]
['parent2'] = 'Species', --[[Category:Species described in 1901]]
['description'] = '', --Year description tbd; *not* a container cat
},
['century'] = { --[[Category:Animals described in the 20th century]]
['parent1'] = 'formal', --[[Category:Animals by year of formal description|20th]]
['parent2'] = 'Species', --[[Category:Species described in the 20th century]]
['description'] = '', --Century description tbd; container category, etc...
},
['formal'] = { --[[Category:Animals by year of formal description]]
['parent1'] = 'Group', --[[Category:Animals| Year]]
['parent2'] = 'Species', --[[Category:Species by year of formal description]]
['description'] = "Year that the taxon was first [[Species description|scientifically described]]. "..
"Most often the same year as in the [[Author citation (zoology)|author citation]], "..
"but this is not always the case (see ''[[nomen novum]]'', ''[[nomen conservandum]]'', ''[[nomen oblitum]]'').",
},
},
['Spiders'] = { --"group"; ICZN allows names in Clerck's Aranei Svecici of 1757, earliest date used in World Spider Catalog
['minyear'] = 1757, --integer; lowest possible year displayed in nav bars; defaults to 1758 per ICZN Art. 5
['year'] = { --[[Category:Spiders described in 1901]]
['parent1'] = 'century', --[[Category:Spiders described in the 20th century|1901]]
['parent2'] = 'Animals', --[[Category:Animals described in 1901]]
['description'] = 'Year that the species was first [[Species description|scientifically described]].', --Year description
},
['century'] = { --[[Category:Spiders described in the 20th century]]
['parent1'] = 'formal', --[[Category:Spiders by year of formal description|20th]]
['parent2'] = 'Animals', --[[Category:Animals described in the 20th century]]
['description'] = '', --Century description tbd; container category, etc...
},
['formal'] = { --[[Category:Spiders by year of formal description]]
['parent1'] = 'Group', --[[Category:Spiders| Year]]
['parent2'] = 'Animals', --[[Category:Animals by year of formal description| ]]
['description'] = 'This category serves only to [[WP:DIFFUSE|diffuse]] the lower level "Spiders described in YEAR" categories, thus reducing their size.',
},
},
--[[============================ Insects tree ============================]]
['Insects'] = { --"group"
['minyear'] = 1757, --integer; lowest possible year displayed in nav bars; defaults to 1758 per ICZN Art. 5
['year'] = { --[[Category:Insects described in 1901]]
['parent1'] = 'century', --[[Category:Insects described in the 20th century|1901]]
['parent2'] = 'Animals', --[[Category:Animals described in 1901]]
['description'] = '', --Year description tbd; Default-group's description doesn't apply
},
['century'] = { --[[Category:Insects described in the 20th century]]
['parent1'] = 'formal', --[[Category:Insects by year of formal description|20th]]
['parent2'] = 'Animals', --[[Category:Animals described in the 20th century]]
['description'] = '', --Century description tbd; container category, etc...
},
['formal'] = { --[[Category:Insects by year of formal description]]
['parent1'] = 'Group', --[[Category:Insects| Year]]
['parent2'] = 'Animals', --[[Category:Animals by year of formal description| ]]
['description'] = '', --Formal description tbd; container category, etc...
},
},
['Beetles'] = { --"subgroup" to Insects
['minyear'] = 1757, --integer; lowest possible year displayed in nav bars; defaults to 1758 per ICZN Art. 5
['year'] = { --[[Category:Beetles described in 1901]]
['parent1'] = 'century', --[[Category:Beetles described in the 20th century|1901]]
['parent2'] = 'Insects', --[[Category:Insects described in 1901]]
['description'] = '', --Year description tbd; 'This category should only contain species articles', etc...
},
['century'] = { --[[Category:Beetles described in the 20th century]]
['parent1'] = 'formal', --[[Category:Beetles by year of formal description|20th]]
['parent2'] = 'Insects', --[[Category:Insects described in the 20th century]]
['sortkey2'] = '*', --[[Category:Insects described in the 20th century|*]]
['description'] = '', --Century description tbd; container category, etc...
},
['formal'] = { --[[Category:Beetles by year of formal description]]
['parent1'] = 'Group', --[[Category:Beetles]]
['sortkey1'] = '*', --[[Category:Beetles|*]]
['parent2'] = 'Insects', --[[Category:Insects by year of formal description| ]]
['description'] = '', --Formal description tbd; container category, etc...
},
},
['Butterflies'] = { --"subgroup" to Insects
['minyear'] = 1757, --integer; lowest possible year displayed in nav bars; defaults to 1758 per ICZN Art. 5
['year'] = { --[[Category:Butterflies described in 1901]]
['parent1'] = 'century', --[[Category:Butterflies described in the 20th century|1901]]
['parent2'] = 'Insects', --[[Category:Insects described in 1901]]
['description'] = '', --Year description tbd; 'This category should only contain species articles', etc...
},
['century'] = { --[[Category:Butterflies described in the 20th century]]
['parent1'] = 'formal', --[[Category:Butterflies by year of formal description|20th]]
['parent2'] = 'Insects', --[[Category:Insects described in the 20th century]]
['sortkey2'] = '*', --[[Category:Insects described in the 20th century|*]]
['description'] = '', --Century description tbd; container category, etc...
},
['formal'] = { --[[Category:Butterflies by year of formal description]]
['parent1'] = 'Group', --[[Category:Butterflies| Year]]
['parent2'] = 'Insects', --[[Category:Insects by year of formal description| ]]
['description'] = '', --Formal description tbd; container category, etc...
},
},
['Moths'] = { --"subgroup" to Insects
['year'] = { --[[Category:Moths described in 1901]]
['parent1'] = 'century', --[[Category:Moths described in the 20th century|1901]]
['parent2'] = 'Insects', --[[Category:Insects described in 1901]]
['description'] = '', --Year description tbd; 'This category should only contain species articles', etc...
},
['century'] = { --[[Category:Moths described in the 20th century]]
['parent1'] = 'formal', --[[Category:Moths by year of formal description|20th]]
['parent2'] = 'Insects', --[[Category:Insects described in the 20th century]]
['sortkey2'] = '*', --[[Category:Insects described in the 20th century|*]]
['description'] = '', --Century description tbd; container category, etc...
},
['formal'] = { --[[Category:Moths by year of formal description]]
['parent1'] = 'Group', --[[Category:Moths| Year]]
['parent2'] = 'Insects', --[[Category:Insects by year of formal description| ]]
['description'] = '', --Formal description tbd; container category, etc...
},
},
--[[=========================== Molluscs tree ============================]]
['Bivalves'] = { --"subgroup" to Molluscs
['year'] = { --[[Category:Bivalves described in 1901]]
['parent1'] = 'century', --[[Category:Bivalves described in the 20th century|1901]]
['parent2'] = 'Molluscs', --[[Category:Molluscs described in 1901]]
['description'] = '', --Year description tbd; 'This category should only contain species articles', etc...
},
['century'] = { --[[Category:Bivalves described in the 20th century]]
['parent1'] = 'formal', --[[Category:Bivalves by year of formal description|20th]]
['parent2'] = 'Molluscs', --[[Category:Molluscs described in the 20th century]]
['sortkey2'] = '*', --[[Category:Molluscs described in the 20th century|*]]
['description'] = '', --Century description tbd; container category, etc...
},
['formal'] = { --[[Category:Bivalves by year of formal description]]
['parent1'] = 'Group', --[[Category:Bivalves| Year]]
['parent2'] = 'Molluscs', --[[Category:Molluscs by year of formal description| ]]
['description'] = '', --Formal description tbd; container category, etc...
},
},
['Cephalopods'] = { --"subgroup" to Molluscs
['year'] = { --[[Category:Cephalopods described in 1901]]
['parent1'] = 'century', --[[Category:Cephalopods described in the 20th century|1901]]
['parent2'] = 'Molluscs', --[[Category:Molluscs described in 1901]]
['description'] = '', --Year description tbd; 'This category should only contain species articles', etc...
},
['century'] = { --[[Category:Cephalopods described in the 20th century]]
['parent1'] = 'formal', --[[Category:Cephalopods by year of formal description|20th]]
['parent2'] = 'Molluscs', --[[Category:Molluscs described in the 20th century]]
['sortkey2'] = '*', --[[Category:Molluscs described in the 20th century|*]]
['description'] = '', --Century description tbd; container category, etc...
},
['formal'] = { --[[Category:Cephalopods by year of formal description]]
['parent1'] = 'Group', --[[Category:Cephalopods| Year]]
['parent2'] = 'Molluscs', --[[Category:Molluscs by year of formal description| ]]
['description'] = '', --Formal description tbd; container category, etc...
},
},
['Chitons'] = { --"subgroup" to Molluscs
['year'] = { --[[Category:Chitons described in 1901]]
['parent1'] = 'century', --[[Category:Chitons described in the 20th century|1901]]
['parent2'] = 'Molluscs', --[[Category:Molluscs described in 1901]]
['description'] = '', --Year description tbd; 'This category should only contain species articles', etc...
},
['century'] = { --[[Category:Chitons described in the 20th century]]
['parent1'] = 'formal', --[[Category:Chitons by year of formal description|20th]]
['parent2'] = 'Molluscs', --[[Category:Molluscs described in the 20th century]]
['sortkey2'] = '*', --[[Category:Molluscs described in the 20th century|*]]
['description'] = '', --Century description tbd; container category, etc...
},
['formal'] = { --[[Category:Chitons by year of formal description]]
['parent1'] = 'Group', --[[Category:Chitons| Year]]
['parent2'] = 'Molluscs', --[[Category:Molluscs by year of formal description| ]]
['description'] = '', --Formal description tbd; container category, etc...
},
},
['Gastropods'] = { --"subgroup" to Molluscs
['year'] = { --[[Category:Gastropods described in 1901]]
['parent1'] = 'century', --[[Category:Gastropods described in the 20th century|1901]]
['parent2'] = 'Molluscs', --[[Category:Molluscs described in 1901]]
['description'] = '', --Year description tbd; 'This category should only contain species articles', etc...
},
['century'] = { --[[Category:Gastropods described in the 20th century]]
['parent1'] = 'formal', --[[Category:Gastropods by year of formal description|20th]]
['parent2'] = 'Molluscs', --[[Category:Molluscs described in the 20th century]]
['sortkey2'] = '*', --[[Category:Molluscs described in the 20th century|*]]
['description'] = '', --Century description tbd; container category, etc...
},
['formal'] = { --[[Category:Gastropods by year of formal description]]
['parent1'] = 'Group', --[[Category:Gastropods| Year]]
['parent2'] = 'Molluscs', --[[Category:Molluscs by year of formal description| ]]
['description'] = '', --Formal description tbd; container category, etc...
},
},
--[[============================= Non-animals ============================]]
['Archaea'] = { --"group"
['year'] = { --[[Category:Archaea described in 1901]]
['parent1'] = 'century', --[[Category:Archaea described in the 20th century|1901]]
['parent2'] = 'Species', --[[Category:Species described in 1901]]
['description'] = '', --Year description tbd; 'This category should only contain species articles', etc...
},
['century'] = { --[[Category:Archaea described in the 20th century]]
['parent1'] = 'formal', --[[Category:Archaea by year of formal description|20th]]
['parent2'] = 'Species', --[[Category:Species described in the 20th century]]
['description'] = '', --Century description tbd; container category, etc...
},
['formal'] = { --[[Category:Archaea by year of formal description]]
['parent1'] = 'Group', --[[Category:Archaea| Year]]
['parent2'] = 'Species', --[[Category:Species by year of formal description]]
['description'] = '', --Formal description tbd; container category, etc...
},
},
['Bacteria'] = { --"group"
['minyear'] = 1753, --integer; lowest possible year displayed in nav bars; defaults to 1758 per ICZN Art. 5
['year'] = { --[[Category:Bacteria described in 1901]]
['parent1'] = 'century', --[[Category:Bacteria described in the 20th century|1901]]
['parent2'] = 'Species', --[[Category:Species described in 1901]]
['description'] = '', --Year description tbd; 'This category should only contain species articles', etc...
},
['century'] = { --[[Category:Bacteria described in the 20th century]]
['parent1'] = 'formal', --[[Category:Bacteria by year of formal description|20th]]
['parent2'] = 'Species', --[[Category:Species described in the 20th century]]
['description'] = '', --Century description tbd; container category, etc...
},
['formal'] = { --[[Category:Bacteria by year of formal description]]
['parent1'] = 'Group', --[[Category:Bacteria| Year]]
['parent2'] = 'Species', --[[Category:Species by year of formal description]]
['description'] = '', --Formal description tbd; container category, etc...
},
},
['Fungi'] = { --"group"
['minyear'] = 1753, --integer; lowest possible year displayed in nav bars; defaults to 1758 per ICZN Art. 5
['year'] = { --[[Category:Fungi described in 1901]]
['parent1'] = 'century', --[[Category:Fungi described in the 20th century|1901]]
['parent2'] = 'Species', --[[Category:Species described in 1901]]
['description'] = '', --Year description tbd; 'This category should only contain species articles', etc...
},
['century'] = { --[[Category:Fungi described in the 20th century]]
['parent1'] = 'formal', --[[Category:Fungi by year of formal description|20th]]
['parent2'] = 'Species', --[[Category:Species described in the 20th century]]
['description'] = '', --Century description tbd; container category, etc...
},
['formal'] = { --[[Category:Fungi by year of formal description]]
['parent1'] = 'Group', --[[Category:Fungi| Year]]
['parent2'] = 'Species', --[[Category:Species by year of formal description]]
['description'] = '', --Formal description tbd; container category, etc...
},
},
['Lichens'] = { --"subgroup" to Fungi
['minyear'] = 1753, --integer; lowest possible year displayed in nav bars; defaults to 1758 per ICZN Art. 5
['year'] = { --[[Category:Lichens described in 1901]]
['parent1'] = 'century', --[[Category:Lichens described in the 20th century|1901]]
['parent2'] = 'Fungi', --[[Category:Fungi described in 1901]]
['description'] = '', --Year description tbd; 'This category should only contain species articles', etc...
},
['century'] = { --[[Category:Lichens described in the 20th century]]
['parent1'] = 'formal', --[[Category:Lichens by year of formal description|20th]]
['parent2'] = 'Fungi', --[[Category:Fungi described in the 20th century]]
['description'] = '', --Century description tbd; container category, etc...
},
['formal'] = { --[[Category:Lichens by year of formal description]]
['parent1'] = 'Group', --[[Category:Lichens| Year]]
['parent2'] = 'Fungi', --[[Category:Fungi by year of formal description]]
['description'] = '', --Formal description tbd; container category, etc...
},
},
['Plants'] = { --"group"
['minyear'] = 1753, --integer; lowest possible year displayed in nav bars; defaults to 1758 per ICZN Art. 5
['year'] = { --[[Category:Plants described in 1901]]
['parent1'] = 'century', --[[Category:Plants described in the 20th century|1901]]
['parent2'] = 'Species', --[[Category:Species described in 1901]]
['description'] = "This category includes plant species that were ''first formally and validly described'' in %year% according to the rules of the [[International Code of Botanical Nomenclature]]. Use [[WP:RS|reliable sources]] like the [[International Plant Names Index]] to figure out the proper category. For examples see the [[Wikipedia:WikiProject Plants/Description in year categories|WikiProject Plants essay]] on this topic.", --taken from [[Category:Plants described in 1928]]
},
['century'] = { --[[Category:Plants described in the 20th century]]
['parent1'] = 'formal', --[[Category:Plants by year of formal description|20th]]
['parent2'] = 'Species', --[[Category:Species described in the 20th century]]
['description'] = 'For advice on using the subcategories of this category, see [[Wikipedia:WikiProject Plants/Description in year categories]].', --taken from [[Category:Plants described in the 21st century]]
},
['formal'] = { --[[Category:Plants by year of formal description]]
['parent1'] = 'Group', --[[Category:Plants| Year]]
['parent2'] = 'Species', --[[Category:Species by year of formal description]]
['description'] = 'For advice on using the subcategories of this category, see [[Wikipedia:WikiProject Plants/Description in year categories]].',
},
},
--prelim namespace/title determination
--[[==================== "Species described in"-level ====================]]
local currCat = nil
local currQID = nil
if currentTitle.namespace == 14 then --category namespace
currCat = currentTitle.text --without namespace nor interwiki prefixes
currQID = mw.wikibase.getEntityIdForCurrentPage()
else
if parentArg then
currCat = mw.ustring.gsub(parentArg, 'Category:', '')
currQID = mw.wikibase.getEntityIdForTitle('Category:'..currCat)
else --currQID & currCat both nil
if currentTitle.fullText ~= 'Template:Category described in year' then --ignore self...
trackingCats[2] = '[[Category:Described in year error|P]]' --missing a category parameter outside category namespace
end
end
end
--find commons & wikispecies link(s); produce {{Commons and category}} and/or {{Wikispecies}} template(s)
['Species'] = {
if currQID then
['minyear'] = 1753, --integer; lowest possible year displayed in nav bars; defaults to 1758 per ICZN Art. 5
if commonsLink._hasGallery(currQID) or commonsLink._hasCategory(currQID) then
['year'] = { --[[Category:Species described in 1901]]
commons = frame:expandTemplate{ title = 'Commons and category', args = { qid=currQID }}
['parent1'] = 'century', --[[Category:Species described in the 20th century]]
end
['sortkey1'] = ' ', --[[Category:Species described in the 20th century| ]]
local currEntity = mw.wikibase.getEntity(currQID)
['parent2'] = 'Taxa', --[[Category:Taxa described in 1901]]
if currEntity then
['parent3'] = 'environment', --[[Category:1901 in the environment]]
--check "Other sites" sitelinks for Wikispecies
['description'] = '', --Year description tbd
local currSiteLinks = currEntity.sitelinks
},
if currSiteLinks then
['century'] = { --[[Category:Species described in the 20th century]]
local currSpeciesWiki = currEntity.sitelinks.specieswiki
['parent1'] = 'formal', --[[Category:Species by year of formal description|20th]]
if currSpeciesWiki then
['parent2'] = 'Taxa', --[[Category:Taxa described in the 20th century]]
local currSpeciesWikiTitle = currSpeciesWiki.title
['parent3'] = 'environment', --[[Category:20th century in the environment]]
if currSpeciesWikiTitle then
['description'] = "This category should only contain '''[[species]]''' and notable [[subspecies]] of [[Biota (taxonomy)|biota]] described in the '''[[%century% century]]'''.", --adapted from all 4 Species-century cats (18th-21st)
wikispecies = frame:expandTemplate{ title = 'Wikispecies', args = { currSpeciesWikiTitle } }
},
end end end end end
['formal'] = { --[[Category:Species by year of formal description]]
['parent1'] = 'Group', --[[Category:Species]]
['sortkey1'] = 'Year', --[[Category:Species|Year]]
['parent2'] = 'Taxa', --[[Category:Taxa by year of formal description]]
['description'] = "See [[species description]].", --could be improved...
},
},
--[[===================== "Taxa described in"-level ======================]]
--[[======================================================================]]
--[[ Main ]]
--[[======================================================================]]
if currCat then
--determine current/related/adjacent cats' properties/vars/etc.
local currGroup = mw.ustring.match(currCat, '^([%w ]+) described in') --Bacteria/Plants/etc.
if isNilOrEmpty(currGroup) then currGroup = mw.ustring.match(currCat, '^([%w ]+) by year of formal description') end
if conf[currGroup] == nil then conf[currGroup] = conf['Default'] end --default to Default
local currYDCF = nil --possible future values: year/decade/century/formal
local currYear = mw.ustring.match(currCat, 'described in (%d%d%d%d)$')
local currDeca = mw.ustring.match(currCat, 'described in the (%d%d%d%d)s$') --deprecated
local currCent = mw.ustring.match(currCat, 'described in the (%d+)[snrt][tdh] century$')
local currFrml = mw.ustring.match(currCat, 'by year of (formal) description$')
local parentCent = nil --used with currYear
local minYear = tonumber(conf[currGroup].minyear)
if minYear == nil or
(minYear and (minYear <= 1700 or minYear >= 2000)) then
minYear = 1758 --default to 1758 per ICZN Art. 5
end
if currYear then
currYDCF = 'year'
if mw.ustring.match(currYear, '^%d%d00') then --1900 in 19th century
parentCent = mw.ustring.match(currYear, '^%d%d')
else --1901 in 20th century
parentCent = 1 + mw.ustring.match(currYear, '^%d%d')
end
elseif currDeca then
currYDCF = 'decade'
bConfError = true
trackingCats[2] = '[[Category:Described in year error|D]]' --invalid decade-parent (deprecated)
elseif currCent then
currYDCF = 'century'
elseif currFrml then
currYDCF = 'formal'
else
bConfError = true
trackingCats[2] = '[[Category:Described in year error|N]]' --invalid category name
end
--conf error checkng (missing keys)
--Numeric sortkeys are unfortunately grouped together under "0-9".
--Check phab T203355 (Magic word to force category number headings instead of 0-9).
if bConfError == false then
if conf[currGroup] == nil then
bConfError = true
trackingCats[2] = '[[Category:Described in year error|1]]' --group (Bacteria/Plants/etc.) key missing from conf
elseif conf[currGroup][currYDCF] == nil then
bConfError = true
trackingCats[2] = '[[Category:Described in year error|2]]' --year/century/formal key missing
else
if conf[currGroup][currYDCF].description == nil then
bConfError = true
trackingCats[2] = '[[Category:Described in year error|3]]' --description key missing
end
if conf[currGroup][currYDCF].parent1 == nil then
bConfError = true
trackingCats[2] = '[[Category:Described in year error|4]]' --parent key missing
end
end
end
if bConfError == false then
--produce portal
if currGroup == 'Fossil taxa' or currGroup == 'Fossil parataxa' then
portal = frame:expandTemplate{ title = 'Portal', args = { 'Paleontology' } }
end
--produce description, evaluate %variables%
description = conf[currGroup][currYDCF].description
if mw.ustring.match(description, '%%year%%') then
if currYear then description = mw.ustring.gsub(description, '%%year%%', currYear) --"2011"
else description = mw.ustring.gsub(description, '%%year%%', 'this year') end
end
if mw.ustring.match(description, '%%century%%') then
if currCent then description = mw.ustring.gsub(description, '%%century%%', addOrd(currCent)) --"21st"
else description = mw.ustring.gsub(description, '%%century%%', 'this century') end
end
--produce cats & navs
local iparent = 1
local parenti = 'parent'..iparent
local sortkeyi = 'sortkey'..iparent
while conf[currGroup][currYDCF][parenti] do
local parent = conf[currGroup][currYDCF][parenti]
local sortkey = conf[currGroup][currYDCF][sortkeyi]
--[[========================== Year ==========================]]
if currYDCF == 'year' then
if nav == nil then
local args = { min = minYear }
if parentArg and currentTitle.namespace ~= 14 then
args['testcase'] = parentArg
end
nav = frame:expandTemplate{ title = 'Navseasoncats', args = args }
end
if parent == 'century' then
if isNilOrEmpty(sortkey) then sortkey = currYear end --default to currYear
categories[iparent] = '[[Category:'..currGroup..' described in the '..addOrd(parentCent)..' century|'..sortkey..']]'
elseif parent == 'biology' then
if isNilOrEmpty(sortkey) then sortkey = '' --default to none
else sortkey = '|'..sortkey end
if tonumber(currYear) < 1865 then
categories[iparent] = '[[Category:'..currYear..' in science'..sortkey..']]' --biology cat structure doesn't exist pre-1865, as of 10/2018
else
categories[iparent] = '[[Category:'..currYear..' in biology'..sortkey..']]' --if/when all biology cats exists, merge this elseif with 'paleontology'
end
elseif parent == 'paleontology' then
if isNilOrEmpty(sortkey) then sortkey = '' --default to none
else sortkey = '|'..sortkey end
categories[iparent] = '[[Category:'..currYear..' in '..parent..sortkey..']]'
elseif parent == 'environment' then
if isNilOrEmpty(sortkey) then sortkey = '' --default to none
else sortkey = '|'..sortkey end
categories[iparent] = '[[Category:'..currYear..' in the environment'..sortkey..']]'
elseif mw.ustring.match(parent, '^%u[%l ]+') then --e.g. Animals/Insects/Fossil taxa
if isNilOrEmpty(sortkey) then sortkey = '' --default to none
else sortkey = '|'..sortkey end
categories[iparent] = '[[Category:'..parent..' described in '..currYear..sortkey..']]'
else
trackingCats[2] = '[[Category:Described in year error|Y]]' --invalid year-parent
end
--[[======================== Century =========================]]
elseif currYDCF == 'century' then
if nav == nil then
local args = {}
if parentArg and currentTitle.namespace ~= 14 then
args['testcase'] = parentArg
end
nav = frame:expandTemplate{ title = 'Container category' } ..
frame:expandTemplate{ title = 'Navseasoncats', args = args }
end
if parent == 'formal' then
if isNilOrEmpty(sortkey) then sortkey = addOrd(currCent) end --default to currCent
categories[iparent] = '[[Category:'..currGroup..' by year of formal description|'..sortkey..']]'
elseif parent == 'biology' then
if isNilOrEmpty(sortkey) then sortkey = '' --default to none
else sortkey = '|'..sortkey end
if tonumber(currCent) < 19 then
categories[iparent] = '[[Category:'..addOrd(currCent)..' century in science'..sortkey..']]' --biology cat structure doesn't exist pre-1865, as of 10/2018
else
categories[iparent] = '[[Category:'..addOrd(currCent)..' century in biology'..sortkey..']]' --if/when all biology cats exists, merge this elseif with 'paleontology'
end
elseif parent == 'paleontology' then
if isNilOrEmpty(sortkey) then sortkey = '' --default to none
else sortkey = '|'..sortkey end
categories[iparent] = '[[Category:'..addOrd(currCent)..' century in '..parent..sortkey..']]'
elseif parent == 'environment' then
if isNilOrEmpty(sortkey) then sortkey = '' --default to none
else sortkey = '|'..sortkey end
categories[iparent] = '[[Category:'..addOrd(currCent)..' century in the environment'..sortkey..']]'
elseif mw.ustring.match(parent, '^%u[%l ]+') then --e.g. Animals/Insects/Fossil taxa
if isNilOrEmpty(sortkey) then sortkey = '' --default to none
else sortkey = '|'..sortkey end
categories[iparent] = '[[Category:'..parent..' described in the '..addOrd(currCent)..' century'..sortkey..']]'
else
trackingCats[2] = '[[Category:Described in year error|C]]' --invalid century-parent
end
--[[======================== Formal ==========================]]
elseif currYDCF == 'formal' then
local formalParentsDefaultSortkey_Space = {
['Animals'] = true,
['Insects'] = true,
['Molluscs'] = true,
['Fungi'] = true,
}
local formalParentsDefaultSortkey_None = {
['Species'] = true,
['Taxa'] = true,
['Fossil taxa'] = true,
}
if nav == nil then
nav = frame:expandTemplate{ title = 'Container category' }
end
if parent == 'Group' then
if isNilOrEmpty(sortkey) then sortkey = ' Year' end --default to " Year"
categories[iparent] = '[[Category:'..currGroup..'|'..sortkey..']]'
elseif parent == 'paleontology' then
if isNilOrEmpty(sortkey) then sortkey = ' ' end --default to " "; special parent
categories[iparent] = '[[Category:Paleontology by year|'..sortkey..']]'
elseif formalParentsDefaultSortkey_Space[parent] then
if isNilOrEmpty(sortkey) then sortkey = ' ' end --default to " "; normal parent
categories[iparent] = '[[Category:'..parent..' by year of formal description|'..sortkey..']]'
elseif formalParentsDefaultSortkey_None[parent] then
if isNilOrEmpty(sortkey) then sortkey = '' --default to none; normal parent
else sortkey = '|'..sortkey end
categories[iparent] = '[[Category:'..parent..' by year of formal description'..sortkey..']]'
else
trackingCats[2] = '[[Category:Described in year error|F]]' --invalid formal-parent
end
--[[========================= Error ==========================]]
else
trackingCats[2] = '[[Category:Described in year error|U]]' --unknown configuration
end
iparent = iparent + 1
parenti = 'parent'..iparent
sortkeyi = 'sortkey'..iparent
end --while conf[currGroup][currYDCF][parenti] do
end --if bConfError == false then
--check for non-existent cats
for _, category in pairs(categories) do
local cat = mw.ustring.match(category, '%[%[Category:([%w%s]+)')
if mw.title.new(cat, 14).exists == false then
trackingCats[1] = '[[Category:Described in year unknown category]]'
break
end
end
end --if currCat then
--build header & rem surrounding whitespace
['Taxa'] = {
local br = '<br />'
['minyear'] = 1753, --integer; lowest possible year displayed in nav bars; defaults to 1758 per ICZN Art. 5
if nav then header = nav end
['year'] = { --[[Category:Taxa described in 1901]]
if portal then header = header..'\n'..portal end
['parent1'] = 'century', --[[Category:Taxa described in the 20th century|1901]]
if commons then header = header..'\n'..commons end
['parent2'] = 'biology', --[[Category:1901 in biology]]
if wikispecies then header = header..'\n'..wikispecies end
['description'] = '', --Year description tbd
if description and description ~= '' then
},
header = header..description
['century'] = { --[[Category:Taxa described in the 20th century]]
elseif portal or commons or wikispecies then
['parent1'] = 'formal', --[[Category:Taxa by year of formal description|20th]]
header = mw.ustring.gsub(header, '<br ?/?>', '')
['parent2'] = 'biology', --[[Category:20th century in biology]]
end
['description'] = '', --Century description tbd
if toc then header = header..br..toc end
},
header = mw.text.trim(header)
},
header = mw.ustring.gsub(header, '^<br />', '')
header = mw.ustring.gsub(header, '<br />$', '')
--append header to outString
--[[==================== "Fossil taxa described in"-level ====================]]
if outString then outString = outString..header
else outString = header end
--append cats to outString
['Fossil taxa'] = {
if currentTitle.namespace == 14 then --category namespace
['minyear'] = 1753, --integer; lowest possible year displayed in nav bars; defaults to 1758 per ICZN Art. 5
if table.maxn(categories) > 0 then outString = outString..table.concat(categories) end
['year'] = { --[[Category:Fossil taxa described in 1901]]
outString = outString..table.concat(trackingCats)
['parent1'] = 'century', --[[Category:Fossil taxa described in the 20th century]]
else
['parent2'] = 'Taxa', --[[Category:Taxa described in 1901]]
if table.maxn(categories) > 0 then --might be 0 if there's an error before setting cats
['parent3'] = 'paleontology', --[[Category:1901 in paleontology]]
outString = outString..br..mw.ustring.gsub(table.concat(categories, br), '%[%[', '[[:')
['description'] = 'This category should only contain articles on fossil [[genus|genera]] or lower.',
},
end
outString = outString..br..mw.ustring.gsub(table.concat(trackingCats, br), '%[%[', '[[:')
['century'] = { --[[Category:Fossil taxa described in the 20th century]]
outString = mw.ustring.gsub(outString, br..br, br) --produced by empty ('') first/consecutive tracking cat/s
['parent1'] = 'formal', --[[Category:Fossil taxa by year of formal description|20th]]
outString = mw.ustring.gsub(outString, br..br, br) --jic (use while loop if #trackingCats >= 3 or 4)
['parent2'] = 'Taxa', --[[Category:Taxa described in the 20th century]]
end
['parent3'] = 'paleontology', --[[Category:20th century in paleontology]]
['description'] = '', --Century description tbd
},
['formal'] = { --[[Category:Fossil taxa by year of formal description]]
['parent1'] = 'Group', --[[Category:Fossil taxa]]
['sortkey1'] = 'Year, by', --[[Category:Fossil taxa|Year, by]]
['parent2'] = 'Taxa', --[[Category:Taxa by year of formal description]]
['parent3'] = 'paleontology', --[[Category:Paleontology by year| ]]
['description'] = '', --Formal description tbd; container category, etc...
},
},
return outString
['Fossil parataxa'] = {
end
['year'] = { --[[Category:Fossil parataxa described in 1975]]
['parent1'] = 'century', --[[Category:Fossil parataxa described in the 20th century]]
['parent2'] = 'Fossil taxa', --[[Category:Fossil taxa described in 1975]]
['description'] = 'This category should only contain articles on [[genus|genera]] or lower.',
},
['century'] = { --[[Category:Fossil parataxa described in the 20th century]]
['parent1'] = 'formal', --[[Category:Fossil parataxa by year of formal description|20th]]
['parent2'] = 'Fossil taxa', --[[Category:Fossil taxa described in the 20th century]]
['sortkey2'] = '*', --[[Category:Fossil taxa described in the 20th century|*]]
['description'] = '', --Century description tbd
},
['formal'] = { --[[Category:Fossil parataxa by year of formal description]]
['parent1'] = 'Group', --[[Category:Fossil parataxa]]
['parent2'] = 'Fossil taxa', --[[Category:Fossil taxa by year of formal description]]
['description'] = '', --Formal description tbd; container category, etc...
},
},
}


return p
return p

Revision as of 12:04, 1 November 2023

require('strict')

--[[==========================================================================]]
--[[                             Local functions                              ]]
--[[==========================================================================]]

local function addOrd( i ) --12 -> 12th, etc.
	if tonumber(i) then
		local s = tostring(i)
		local  tens = string.match(s, '1%d$')
		local  ones = string.match(s,  '%d$')
		if     tens        then return s..'th'
		elseif ones == '1' then return s..'st'
		elseif ones == '2' then return s..'nd'
		elseif ones == '3' then return s..'rd'
		elseif ones ~= nil then return s..'th'
		end
	end
	return ''
end

local function isNilOrEmpty( thing )
	return (thing == nil or thing == '')
end

local p = {}

--[[==========================================================================]]
--[[                            External function                             ]]
--[[==========================================================================]]

function p.autodetect( frame )
	local conf = require( 'Module:Category described in year/conf' ) --configuration module
	local commonsLink = require('Module:Commons link')
	local currentTitle = mw.title.getCurrentTitle()
	local parentArg = frame:getParent().args[1] --accept 1 unnamed category parameter if not in category namespace; required for testing/doc/etc. purposes
	local header = ' ' --header template(s), nav bar, and category description text; whitespace-initialized for convenience
	local nav = nil
	local portal = nil --for {{Portal|...}}
	local commons = nil --for {{Commons|...}}
	local wikispecies = nil --for {{Wikispecies|...}}
	local description = nil
	local toc = nil
	local categories = {}
	local trackingCats = {
		[1] = '', --placeholder for [[Category:Described in year unknown category]]
		[2] = '', --placeholder for [[Category:Described in year error]]
	}
	local outString = nil
	local bConfError = false
	
	--prelim namespace/title determination
	local currCat = nil
	local currQID = nil
	if currentTitle.namespace == 14 then --category namespace
		currCat = currentTitle.text --without namespace nor interwiki prefixes
		currQID = mw.wikibase.getEntityIdForCurrentPage()
	else
		if parentArg then
			currCat = mw.ustring.gsub(parentArg, 'Category:', '')
			currQID = mw.wikibase.getEntityIdForTitle('Category:'..currCat)
		else --currQID & currCat both nil
			if currentTitle.fullText ~= 'Template:Category described in year' then --ignore self...
				trackingCats[2] = '[[Category:Described in year error|P]]' --missing a category parameter outside category namespace
			end
		end
	end
	
	--find commons & wikispecies link(s); produce {{Commons and category}} and/or {{Wikispecies}} template(s)
	if currQID then
		if commonsLink._hasGallery(currQID) or commonsLink._hasCategory(currQID) then
			commons = frame:expandTemplate{ title = 'Commons and category', args = { qid=currQID }}
		end
		local currEntity = mw.wikibase.getEntity(currQID)
		if currEntity then
			--check "Other sites" sitelinks for Wikispecies
			local currSiteLinks = currEntity.sitelinks
			if currSiteLinks then
				local currSpeciesWiki = currEntity.sitelinks.specieswiki
				if currSpeciesWiki then
					local currSpeciesWikiTitle = currSpeciesWiki.title
					if currSpeciesWikiTitle then
						wikispecies = frame:expandTemplate{ title = 'Wikispecies', args = { currSpeciesWikiTitle } }
	end	end	end	end	end
	
	--[[======================================================================]]
	--[[                                 Main                                 ]]
	--[[======================================================================]]
	if currCat then
		
		--determine current/related/adjacent cats' properties/vars/etc.
		local currGroup = mw.ustring.match(currCat, '^([%w ]+) described in') --Bacteria/Plants/etc.
		if isNilOrEmpty(currGroup) then currGroup = mw.ustring.match(currCat, '^([%w ]+) by year of formal description') end
		if conf[currGroup] == nil then conf[currGroup] = conf['Default'] end --default to Default
		local currYDCF = nil --possible future values: year/decade/century/formal
		local currYear = mw.ustring.match(currCat, 'described in (%d%d%d%d)$')
		local currDeca = mw.ustring.match(currCat, 'described in the (%d%d%d%d)s$') --deprecated
		local currCent = mw.ustring.match(currCat, 'described in the (%d+)[snrt][tdh] century$')
		local currFrml = mw.ustring.match(currCat, 'by year of (formal) description$')
		local parentCent = nil --used with currYear
		local minYear = tonumber(conf[currGroup].minyear)
		if minYear == nil or 
		  (minYear and (minYear <= 1700 or minYear >= 2000)) then
			minYear = 1758 --default to 1758 per ICZN Art. 5
		end
		if currYear then
			currYDCF = 'year'
			if mw.ustring.match(currYear, '^%d%d00') then --1900 in 19th century
				parentCent = mw.ustring.match(currYear, '^%d%d')
			else --1901 in 20th century
				parentCent = 1 + mw.ustring.match(currYear, '^%d%d')
			end
		elseif currDeca then
			currYDCF = 'decade'
			bConfError = true
			trackingCats[2] = '[[Category:Described in year error|D]]' --invalid decade-parent (deprecated)
		elseif currCent then
			currYDCF = 'century'
		elseif currFrml then
			currYDCF = 'formal'
		else
			bConfError = true
			trackingCats[2] = '[[Category:Described in year error|N]]' --invalid category name
		end
		
		--conf error checkng (missing keys)
		--Numeric sortkeys are unfortunately grouped together under "0-9".
		--Check phab T203355 (Magic word to force category number headings instead of 0-9).
		if bConfError == false then
			if conf[currGroup] == nil then
				bConfError = true
				trackingCats[2] = '[[Category:Described in year error|1]]' --group (Bacteria/Plants/etc.) key missing from conf
			elseif conf[currGroup][currYDCF] == nil then
				bConfError = true
				trackingCats[2] = '[[Category:Described in year error|2]]' --year/century/formal key missing
			else
				if conf[currGroup][currYDCF].description == nil then
					bConfError = true
					trackingCats[2] = '[[Category:Described in year error|3]]' --description key missing
				end
				if conf[currGroup][currYDCF].parent1 == nil then
					bConfError = true
					trackingCats[2] = '[[Category:Described in year error|4]]' --parent key missing
				end
			end
		end
		
		if bConfError == false then
			--produce portal
			if currGroup == 'Fossil taxa' or currGroup == 'Fossil parataxa' then
				portal = frame:expandTemplate{ title = 'Portal', args = { 'Paleontology' } }
			end
			
			--produce description, evaluate %variables%
			description = conf[currGroup][currYDCF].description
			if mw.ustring.match(description, '%%year%%') then
				if currYear then description = mw.ustring.gsub(description, '%%year%%', currYear) --"2011"
				else description = mw.ustring.gsub(description, '%%year%%', 'this year') end
			end
			if mw.ustring.match(description, '%%century%%') then
				if currCent then description = mw.ustring.gsub(description, '%%century%%', addOrd(currCent)) --"21st"
				else description = mw.ustring.gsub(description, '%%century%%', 'this century') end
			end
			
			--produce cats & navs
			local iparent = 1
			local parenti = 'parent'..iparent
			local sortkeyi = 'sortkey'..iparent
			while conf[currGroup][currYDCF][parenti] do
				local parent = conf[currGroup][currYDCF][parenti]
				local sortkey = conf[currGroup][currYDCF][sortkeyi]
				
				--[[========================== Year ==========================]]
				if currYDCF == 'year' then
					if nav == nil then
						local args = { min = minYear }
						if parentArg and currentTitle.namespace ~= 14 then
							args['testcase'] = parentArg
						end
						nav = frame:expandTemplate{ title = 'Navseasoncats', args = args }
					end
					if parent == 'century' then
						if isNilOrEmpty(sortkey) then sortkey = currYear end --default to currYear
						categories[iparent] = '[[Category:'..currGroup..' described in the '..addOrd(parentCent)..' century|'..sortkey..']]'
						
					elseif parent == 'biology' then
						if isNilOrEmpty(sortkey) then sortkey = '' --default to none
						else sortkey = '|'..sortkey end
						if tonumber(currYear) < 1865 then
							categories[iparent] = '[[Category:'..currYear..' in science'..sortkey..']]' --biology cat structure doesn't exist pre-1865, as of 10/2018
						else
							categories[iparent] = '[[Category:'..currYear..' in biology'..sortkey..']]' --if/when all biology cats exists, merge this elseif with 'paleontology'
						end
						
					elseif parent == 'paleontology' then
						if isNilOrEmpty(sortkey) then sortkey = '' --default to none
						else sortkey = '|'..sortkey end
						categories[iparent] = '[[Category:'..currYear..' in '..parent..sortkey..']]'
						
					elseif parent == 'environment' then
						if isNilOrEmpty(sortkey) then sortkey = '' --default to none
						else sortkey = '|'..sortkey end
						categories[iparent] = '[[Category:'..currYear..' in the environment'..sortkey..']]'
						
					elseif mw.ustring.match(parent, '^%u[%l ]+') then --e.g. Animals/Insects/Fossil taxa
						if isNilOrEmpty(sortkey) then sortkey = '' --default to none
						else sortkey = '|'..sortkey end
						categories[iparent] = '[[Category:'..parent..' described in '..currYear..sortkey..']]'
						
					else
						trackingCats[2] = '[[Category:Described in year error|Y]]' --invalid year-parent
					end
					
				--[[======================== Century =========================]]
				elseif currYDCF == 'century' then
					if nav == nil then
						local args = {}
						if parentArg and currentTitle.namespace ~= 14 then
							args['testcase'] = parentArg
						end
						nav = frame:expandTemplate{ title = 'Container category' } .. 
							  frame:expandTemplate{ title = 'Navseasoncats', args = args }
					end
					if parent == 'formal' then
						if isNilOrEmpty(sortkey) then sortkey = addOrd(currCent) end --default to currCent
						categories[iparent] = '[[Category:'..currGroup..' by year of formal description|'..sortkey..']]'
						
					elseif parent == 'biology' then
						if isNilOrEmpty(sortkey) then sortkey = '' --default to none
						else sortkey = '|'..sortkey end
						if tonumber(currCent) < 19 then
							categories[iparent] = '[[Category:'..addOrd(currCent)..' century in science'..sortkey..']]' --biology cat structure doesn't exist pre-1865, as of 10/2018
						else
							categories[iparent] = '[[Category:'..addOrd(currCent)..' century in biology'..sortkey..']]' --if/when all biology cats exists, merge this elseif with 'paleontology'
						end
						
					elseif parent == 'paleontology' then
						if isNilOrEmpty(sortkey) then sortkey = '' --default to none
						else sortkey = '|'..sortkey end
						categories[iparent] = '[[Category:'..addOrd(currCent)..' century in '..parent..sortkey..']]'
						
					elseif parent == 'environment' then
						if isNilOrEmpty(sortkey) then sortkey = '' --default to none
						else sortkey = '|'..sortkey end
						categories[iparent] = '[[Category:'..addOrd(currCent)..' century in the environment'..sortkey..']]'
						
					elseif mw.ustring.match(parent, '^%u[%l ]+') then --e.g. Animals/Insects/Fossil taxa
						if isNilOrEmpty(sortkey) then sortkey = '' --default to none
						else sortkey = '|'..sortkey end
						categories[iparent] = '[[Category:'..parent..' described in the '..addOrd(currCent)..' century'..sortkey..']]'
						
					else
						trackingCats[2] = '[[Category:Described in year error|C]]' --invalid century-parent
					end
					
				--[[======================== Formal ==========================]]
				elseif currYDCF == 'formal' then
					local formalParentsDefaultSortkey_Space = {
						['Animals'] = true,
						['Insects'] = true,
						['Molluscs'] = true,
						['Fungi'] = true,
					}
					local formalParentsDefaultSortkey_None = {
						['Species'] = true,
						['Taxa'] = true,
						['Fossil taxa'] = true,
					}
					if nav == nil then
						nav = frame:expandTemplate{ title = 'Container category' }
					end
					if parent == 'Group' then
						if isNilOrEmpty(sortkey) then sortkey = ' Year' end --default to " Year"
						categories[iparent] = '[[Category:'..currGroup..'|'..sortkey..']]'
						
					elseif parent == 'paleontology' then
						if isNilOrEmpty(sortkey) then sortkey = ' ' end --default to " "; special parent
						categories[iparent] = '[[Category:Paleontology by year|'..sortkey..']]'
						
					elseif formalParentsDefaultSortkey_Space[parent] then
						if isNilOrEmpty(sortkey) then sortkey = ' ' end --default to " "; normal parent
						categories[iparent] = '[[Category:'..parent..' by year of formal description|'..sortkey..']]'
						
					elseif formalParentsDefaultSortkey_None[parent] then
						if isNilOrEmpty(sortkey) then sortkey = '' --default to none; normal parent
						else sortkey = '|'..sortkey end
						categories[iparent] = '[[Category:'..parent..' by year of formal description'..sortkey..']]'
						
					else
						trackingCats[2] = '[[Category:Described in year error|F]]' --invalid formal-parent
					end
					
				--[[========================= Error ==========================]]
				else
					trackingCats[2] = '[[Category:Described in year error|U]]' --unknown configuration
				end
				
				iparent = iparent + 1
				parenti = 'parent'..iparent
				sortkeyi = 'sortkey'..iparent
			end --while conf[currGroup][currYDCF][parenti] do
		end --if bConfError == false then
		
		--check for non-existent cats
		for _, category in pairs(categories) do
			local cat = mw.ustring.match(category, '%[%[Category:([%w%s]+)')
			if mw.title.new(cat, 14).exists == false then
				trackingCats[1] = '[[Category:Described in year unknown category]]'
				break
			end
		end
		
	end --if currCat then
	
	--build header & rem surrounding whitespace
	local br = '<br />'
	if nav then header = nav end
	if portal then header = header..'\n'..portal end
	if commons then header = header..'\n'..commons end
	if wikispecies then header = header..'\n'..wikispecies end
	if description and description ~= '' then
		header = header..description
	elseif portal or commons or wikispecies then 
		header = mw.ustring.gsub(header, '<br ?/?>', '')
	end
	if toc then header = header..br..toc end
	header = mw.text.trim(header)
	header = mw.ustring.gsub(header, '^<br />', '')
	header = mw.ustring.gsub(header, '<br />$', '')
	
	--append header to outString
	if outString then outString = outString..header
	else outString = header end
	
	--append cats to outString
	if currentTitle.namespace == 14 then --category namespace
		if table.maxn(categories) > 0 then outString = outString..table.concat(categories) end
		outString = outString..table.concat(trackingCats)
	else
		if table.maxn(categories) > 0 then --might be 0 if there's an error before setting cats
			outString = outString..br..mw.ustring.gsub(table.concat(categories, br), '%[%[', '[[:')
		end
		outString = outString..br..mw.ustring.gsub(table.concat(trackingCats, br), '%[%[', '[[:')
		outString = mw.ustring.gsub(outString, br..br, br) --produced by empty ('') first/consecutive tracking cat/s
		outString = mw.ustring.gsub(outString, br..br, br) --jic (use while loop if #trackingCats >= 3 or 4)
	end
	
	return outString
end

return p