「モジュール:Authority control」の版間の差分

提供:TDR Wiki
削除された内容 追加された内容
en:Module:Authority control oldid=1026999867 より更新
 
(3人の利用者による、間の19版が非表示)
1行目: 1行目:
require('Module:No globals')
require('strict')

local p = {}
local p = {}
local configfile = 'Module:Authority control/config' -- default configuation module
local arg = mw.getCurrentFrame().args.config
if arg and arg~='' then
configfile = 'Module:Authority control/config/' .. arg
end
local config
if mw.title.new(configfile).exists then
config = mw.loadData(configfile)
else
return error('Invalid configuration file',0)
end
local title = mw.title.getCurrentTitle()
local title = mw.title.getCurrentTitle()
local namespace = title.namespace
local namespace = title.namespace
local testcases = (string.sub(title.subpageText,1,9) == 'testcases')
local testcases = title.subpageText == config.i18n.testcases


local function needsAttention(sortkey)
--[[==========================================================================]]
return '[[' .. config.i18n.category .. ':' .. config.i18n.attentioncat .. '|' .. sortkey .. title.text .. ']]'
--[[ Category functions ]]
--[[==========================================================================]]

function p.getCatForId( id )
local catName = ''
if namespace == 0 then
catName = id..'識別子が指定されている記事'
elseif namespace == 2 and not title.isSubpage then
catName = id..'識別子が指定されている利用者ページ'
else
catName = id..'識別子が指定されているその他のページ'
end
return '[[Category:'..catName..']]'..p.redCatLink(catName)
end
end


local function addCat(cat,sortkey)
function p.redCatLink( catName ) --catName == 'Blah' (not 'Category:Blah', not '[[Category:Blah]]')
if catName and catName ~= '' and
if cat and cat ~= '' and (namespace == 0 or namespace == 14 or testcases) then
local redlinkcat = ''
testcases == false and
mw.title.new(catName, 14).exists == false
if testcases == false and mw.title.new(cat, 14).exists == false then
redlinkcat = needsAttention('N')
then
return '[[Category:赤リンクの典拠情報カテゴリがあるページ]]'
end
return ''
end

function p.createRow( id, label, rawValues, link, links, withUid, specialCat )
local catName = '誤った'..(specialCat or id)..'識別子が指定されている記事'
if links then -- all links[] use withUid = false; no check needed
local row = '*<span class="nowrap">'..label
local totlen = 0
for i, l in ipairs( links ) do
if i == 1 then row = row..' '
else row = row..', ' end
if l then
row = row..'<span class="uid">'..l..'</span>'
else
row = row..'<span class="error">'..id..'識別子の値'..rawValues[i]..'は正しくありません。</span>[[Category:'..catName..']]'..p.redCatLink(catName)
end
totlen = totlen + #rawValues[i] + 3 -- 3 chars b/w links
end
end
if totlen > 79 then
if sortkey then
cat = '[[' .. config.i18n.category .. ':'..cat..'|' .. sortkey .. title.text .. ']]'
row = string.gsub(row, '"nowrap"', '""') -- avoid [[A–Z Series]]
else
cat = '[[' .. config.i18n.category .. ':'..cat..']]'
end
end
cat = cat .. redlinkcat
return row..'</span>\n'
return cat
elseif link then
else
if withUid then
return ''
return '*<span class="nowrap">'..label..' <span class="uid">'..link..'</span></span>\n'
end
return '*<span class="nowrap">'..label..' '..link..'</span>\n'
end
end

return '* <span class="error">'..id..'識別子の値'..rawValues..'は正しくありません。</span>[[Category:'..catName..']]'..p.redCatLink(catName)..'\n'
end
end


local function getCatForId(id,faulty)
--[[==========================================================================]]
local cat = string.format(
--[[ Property formatting functions ]]
config.i18n.cat,
--[[==========================================================================]]
faulty and config.i18n.faulty..id or id

)
-- If a link has a suitable entry in the global inter-wiki prefix table at [[:m:Interwiki_map]], please consider routing through this prefix rather than as external link URL. This will ease future maintenance as necessary updates to the link can be centrally carried out there rather than by updating this module. The "external link" icon would disappear for such entries.
return addCat(cat)

function p.aagLink( id )
--P3372's format regex: \d+ (e.g. 1)
if not id:match( '^%d+$' ) then
return false
end
return '[https://www.aucklandartgallery.com/explore-art-and-ideas/artist/'..id..'/ '..id..']'..p.getCatForId( 'AAG' )
end
end


function p.acmLink( id )
local function getIdsFromWikidata(qid,property)
local function getquals(statement,qualid)
--P864's format regex: \d{11} (e.g. 12345678901)
if statement.qualifiers and statement.qualifiers['P'..qualid] then
if not id:match( '^%d%d%d%d%d%d%d%d%d%d%d$' ) then
return mw.wikibase.renderSnak(statement.qualifiers['P'..qualid][1])
return false
else
return false
end
end
end
local ids = {}
return '[https://dl.acm.org/profile/'..id..' '..id..']'..p.getCatForId( 'ACM-DL' )
if qid then
end
for _, statement in ipairs(mw.wikibase.getBestStatements(qid,property)) do

if statement.mainsnak.datavalue then
function p.adbLink( id )
local val = statement.mainsnak.datavalue.value
--P1907's format regex: [a-z][-a-z]+-([1-2]\d|[1-9])\d{0,3} (e.g. barton-sir-edmund-toby-71)
if val then
if not id:match( '^[a-z][-a-z]+-[1-2]%d%d?%d?%d?$' ) and
local namedas = getquals(statement,1810) or getquals(statement,742) or ''
not id:match( '^[a-z][-a-z]+-[1-9]%d?%d?%d?$' ) then
table.insert(ids,{id=val,name=namedas})
return false
end
end
end
end
end
return ids
return '[http://adb.anu.edu.au/biography/'..id..' '..id..']'..p.getCatForId( 'ADB' )
end
end


local _makelink = function(conf,val,nextid,qid) --validate values and create a link
function p.agsaLink( id )
local function tooltip(text,label)
--P6804's format regex: [1-9]\d* (e.g. 3625)
if not id:match( '^[1-9]%d*$' ) then
if label and label~='' then
return mw.getCurrentFrame():expandTemplate{title = "Tooltip", args = {text,label}}
return false
else
return text
end
end
end
local link
return '[https://www.agsa.sa.gov.au/collection-publications/collection/creators/_/'..id..'/ '..id..']'..p.getCatForId( 'AGSA' )
if nextid==1 then
end
if conf.prefix then

link = '*' .. conf.prefix .. '\n**'
function p.autoresuyLink( id )
else
--P2558's format regex: [1-9]\d{0,4} (e.g. 12345)
link = '*'
if not id:match( '^[1-9]%d?%d?%d?%d?$' ) then
end
return false
else
link = '\n**'
end
end
local valid_value = false
return '[https://autores.uy/autor/'..id..' '..id..']'..p.getCatForId( 'autores.uy' )
if conf.customlink then -- use function to validate and generate link
end
local label = nextid>1 and nextid

local newlink= require(config.auxiliary)[conf.customlink](val.id,label)
function p.awrLink( id )
if newlink then
--P4186's format regex: (([A-Z]{3}\d{4})|([A-Z]{2}\d{5}))[a-z] (e.g. PR00768b)
link = link .. newlink
if not id:match( '^[A-Z][A-Z][A-Z]%d%d%d%d[a-z]$' ) and
valid_value = true
not id:match( '^[A-Z][A-Z]%d%d%d%d%d[a-z]$' ) then
end
return false
else
if conf.pattern then -- use pattern to determine validity if defined
valid_value = string.match(val.id,'^'..conf.pattern..'$')
elseif conf.patterns then
for _,pattern in ipairs(conf.patterns) do
valid_value = val.id:match('^'..pattern..'$')
if valid_value then break end
end
elseif conf.valid then -- otherwise use function to determine validity
valid_value = require(config.auxiliary)[conf.valid](val.id)
else -- no validation possible
valid_value = val.id
end
if valid_value then
local newlink
local label = conf.label
if not label or nextid>1 then
label = tostring(nextid)
end
if conf.link then
valid_value = valid_value:gsub('%%', '%%%%')
newlink = '[' .. mw.ustring.gsub(conf.link,'%$1',valid_value) .. ' ' .. label .. ']'
else
newlink = valid_value
end
link = link .. '<span class="uid">'..tooltip(newlink,val.name)..'</span>'
end
end
end
if valid_value then
return '[http://www.womenaustralia.info/biogs/'..id..'.htm '..id..']'..p.getCatForId( 'AWR' )
link = link .. getCatForId(conf.category or conf[1])
end
else

--local preview = require("Module:If preview")
function p.balatLink( id )
local wdlink = qid and '[[:wikidata:' .. qid .. '#P' .. conf.property .. ']]' or ''
--P3293's format regex: \d+ (e.g. 1)
local tooltip = string.format(
if not id:match( '^%d+$' ) then
config.i18n.idnotvalid,
return false
conf[1],
val.id
)
link = link .. '[[File:' .. config.i18n.warningicon .. '|20px|frameless|link=' .. wdlink .. '|' .. tooltip .. ']]'
if conf.errorcat then
link = link .. addCat(conf.errorcat)
else
link = link .. getCatForId(conf.category or conf[1],true)
end
link = link .. addCat(config.i18n.allfaultycat,conf[1])-- .. preview._warning({'The '..conf[1]..' id '..val..' is not valid.'})
end
end
return link
return '[http://balat.kikirpa.be/object/104257'..id..' '..id..']'..p.getCatForId( 'BALaT' ) --no https as of 9/2019
end
end


--[[==========================================================================]]
function p.bibsysLink( id )
--[[ Main ]]
--P1015's format regex: [1-9]\d* or [1-9](\d{0,8}|\d{12}) (e.g. 1234567890123)
--[[==========================================================================]]
--TODO: follow up @ [[d:Property talk:P1015#Discrepancy between the 2 regex constraints]] or escalate/investigate
function p.authorityControl(frame)
if not id:match( '^[1-9]%d?%d?%d?%d?%d?%d?%d?%d?$' ) and
local function resolveQID(qid)
not id:match( '^[1-9]%d%d%d%d%d%d%d%d%d%d%d%d$' ) then
if qid then
return false
qid = 'Q'..mw.ustring.gsub(qid, '^[Qq]', '')
if mw.wikibase.isValidEntityId(qid) and mw.wikibase.entityExists(qid) then
local sitelink = mw.wikibase.getSitelink(qid)
if sitelink then
return mw.wikibase.getEntityIdForTitle(sitelink) or mw.wikibase.getEntity(qid).id
end
return mw.wikibase.getEntity(qid).id
end
end
end
end
local conf = config.config
return '[https://authority.bibsys.no/authority/rest/authorities/html/'..id..' '..id..']'..p.getCatForId( 'BIBSYS' )
local parentArgs = frame:getParent().args
end
local auxCats = ''

local rct = false -- boolean to track if there are any links to be returned
function p.bildLink( id )
local qid,topic
--P2092's format regex: \d+ (e.g. 1)
local wikilink = function(qid,hideifequal)
if not id:match( '^%d+$' ) then
local label,sitelink = mw.wikibase.getLabel(qid),mw.wikibase.getSitelink(qid)
return false
if label then
if sitelink then
local target = mw.title.new(sitelink)
if target==title or (target.isRedirect and target.redirectTarget==title) then -- do not link
return label
else -- make wikilink to article
return '[[' .. sitelink .. '|' .. label .. ']]'
end
else
return label
end
else
auxCats = auxCats .. needsAttention('L')
return qid
end
end
end
if namespace == 0 then
return '[https://www.bildindex.de/document/obj'..id..' '..id..']'..p.getCatForId( 'Bildindex' )
qid = mw.wikibase.getEntityIdForCurrentPage()
end

function p.bncLink( id )
--P1890's format regex: \d{9} (e.g. 123456789)
if not id:match( '^%d%d%d%d%d%d%d%d%d$' ) then
return false
end
end
if qid then -- article is connected to Wikidata item
return '[http://www.bncatalogo.cl/F?func=direct&local_base=red10&doc_number='..id..' '..id..']'..p.getCatForId( 'BNC' )
if parentArgs.qid and (resolveQID(parentArgs.qid) ~= qid) then -- non-matching qid parameter
end
auxCats = auxCats .. needsAttention('D')

end
function p.bneLink( id )
else -- page is not connected to any Wikidata item
--P950's format regex: (XX|FF|a)\d{4,7}|(bima|bimo|bica|bis[eo]|bivi|Mise|Mimo|Mima)\d{10} (e.g. XX1234567)
qid = resolveQID(parentArgs.qid) -- check qid parameter if no wikidata item is connected
if not id:match( '^[XF][XF]%d%d%d%d%d?%d?%d?$' ) and
if qid then -- qid parameter is valid, set topic to display
not id:match( '^a%d%d%d%d%d?%d?%d?$' ) and
topic = mw.wikibase.getLabel(qid)
not id:match( '^bi[mcsv][aoei]%d%d%d%d%d%d%d%d%d%d$' ) and
if topic then
not id:match( '^Mi[sm][eoa]%d%d%d%d%d%d%d%d%d%d$' ) then
if mw.ustring.lower(title.subpageText) == mw.ustring.lower(topic) then -- suppress topic display if subpagename equals topic up to case change
return false
topic = nil
end
if topic and mw.wikibase.getSitelink(qid) then -- make wikilink to article
topic = '[[' .. mw.wikibase.getSitelink(qid) .. '|' .. topic .. ']]'
end
else
auxCats = auxCats .. needsAttention('L')
end
elseif parentArgs.qid and parentArgs.qid~='' then -- invalid qid has been supplied, add to tracking cat
auxCats = auxCats .. needsAttention('Q')
end
end
end
local qids = {} -- setup any additional QIDs
return '[http://catalogo.bne.es/uhtbin/authoritybrowse.cgi?action=display&authority_id='..id..' '..id..']'..p.getCatForId( 'BNE' ) --no https as of 9/2019
if parentArgs.additional=='auto' and qid then -- check P527 for parts to add additional qids
end
local checkparts = function(property)

local parts = mw.wikibase.getBestStatements(qid,property)
function p.bnfLink( id )
if parts then
--P268's format regex: \d{8}[0-9bcdfghjkmnpqrstvwxz] (e.g. 123456789)
for _,part in ipairs(parts) do
if not id:match( '^c?b?%d%d%d%d%d%d%d%d[0-9bcdfghjkmnpqrstvwxz]$' ) then
if part.mainsnak.datavalue and part.mainsnak.datavalue.value.id then
return false
local resolvedqid = resolveQID(part.mainsnak.datavalue.value.id)
end
if resolvedqid then
--Add cb prefix if it has been removed
table.insert(qids,resolvedqid)
if not id:match( '^cb.+$' ) then
end end end end end
id = 'cb'..id
for _,part in ipairs(config.auto_additional) do
end
checkparts('P'..tostring(part))
return '[https://catalogue.bnf.fr/ark:/12148/'..id..' '..id..'] [https://data.bnf.fr/ark:/12148/'..id..' (データ)]'..p.getCatForId( 'BNF' )
end
end
elseif parentArgs.additional and parentArgs.additional ~= '' then

for _,v in ipairs(mw.text.split(parentArgs.additional,"%s*,%s*")) do
function p.botanistLink( id )
v = resolveQID(v)
--P428's format regex: ('t )?(d')?(de )?(la )?(van (der )?)?(Ma?c)?(De)?(Di)?\p{Lu}?C?['\p{Ll}]*([-'. ]*(van )?(y )?(d[ae][nr]?[- ])?(Ma?c)?[\p{Lu}bht]?C?['\p{Ll}]*)*\.? ?f?\.? (e.g. L.)
if v then
--not easily/meaningfully implementable in Lua's regex since "(this)?" is not allowed...
if v == qid then -- duplicate of qid parameter
if not mw.ustring.match( id, "^[%u%l%d%. '-]+$" ) then --better than nothing
auxCats = auxCats .. needsAttention('R')
return false
end
end
table.insert(qids,v)
local id2 = id:gsub(' +', '%%20')
else -- invalid QID specified
return '[https://www.ipni.org/ipni/advAuthorSearch.do?find_abbreviation='..id2..' '..id..']'..p.getCatForId( 'Botanist' )
auxCats = auxCats .. needsAttention('A')
end

function p.bpnLink( id )
--P651's format regex: \d{6,8} (e.g. 00123456)
if not id:match( '^%d%d%d%d%d%d%d%d$' ) and --original format regex, changed 8/2019 to
not id:match( '^0?%d%d%d%d%d%d%d$' ) and --allow 1-2 leading 0s, allowed by the website
not id:match( '^0?0?%d%d%d%d%d%d$' ) then
return false
end
return '[http://www.biografischportaal.nl/en/persoon/'..id..' '..id..']'..p.getCatForId( 'BPN' ) --no https as of 9/2019
end

function p.canticLink( id )
--P1273's format regex: a\d{7}[0-9x] (e.g. a10640745)
if not id:match( '^a%d%d%d%d%d%d%d[%dx]$' ) then
return false
end
return '[http://cantic.bnc.cat/registres/CUCId/'..id..' '..id..']'..p.getCatForId( 'CANTIC' ) --no https as of 10/2019
end

function p.ciniiLink( id )
--P271's format regex: DA\d{7}[\dX] (e.g. DA12345678)
if not id:match( '^DA%d%d%d%d%d%d%d[%dX]$' ) then
return false
end
return '[https://ci.nii.ac.jp/author/'..id..'?l=en '..id..']'..p.getCatForId( 'CINII' )
end

function p.cwgcLink( id )
--P1908's format regex: [1-9]\d* (e.g. 75228351)
if not id:match( '^[1-9]%d*$' ) then
return false
end
return '[https://www.cwgc.org/find-war-dead/casualty/'..id..'/ '..id..']'..p.getCatForId( 'CWGC' )
end

function p.daaoLink( id )
--P1707's format regex: [a-z\-]+\d* (e.g. rolf-harris)
if not id:match( '^[a-z%-]+%d*$' ) then
return false
end
return '[https://www.daao.org.au/bio/'..id..' '..id..']'..p.getCatForId( 'DAAO' )
end

function p.dblpLink( id )
--P2456's format regex: \d{2,3} /\d+(-\d+)?|[a-z] /[a-zA-Z][0-9A-Za-z]*(-\d+)? (e.g. 123/123)
if not id:match( '^%d%d%d?/%d+$' ) and
not id:match( '^%d%d%d?/%d+%-%d+$' ) and
not id:match( '^[a-z]/[a-zA-Z][0-9A-Za-z]*$' ) and
not id:match( '^[a-z]/[a-zA-Z][0-9A-Za-z]*%-%d+$' ) then
return false
end
return '[https://dblp.org/pid/'..id..' '..id..']'..p.getCatForId( 'DBLP' )
end

function p.dibLink( id )
--P6829's format regex: a\d{4}\d?(-[A-D])? (e.g. a1953)
if not id:match( '^a%d%d%d%d%d?%-?[A-D]?$' ) then
return false
end
return '[https://dib.cambridge.org/viewReadPage.do?articleId='..id..' '..id..']'..p.getCatForId( 'DIB' )
end

function p.dsiLink( id )
--P2349's format regex: [1-9]\d* (e.g. 1538)
if not id:match( '^[1-9]%d*$' ) then
return false
end
return '[http://www.uni-stuttgart.de/hi/gnt/dsi2/index.php?table_name=dsi&function=details&where_field=id&where_value='..id..' '..id..']'..p.getCatForId( 'DSI' )
end

function p.fastLink( id )
--P2163's format regex: [1-9]\d{0,7} (e.g. 1916996)
if not id:match( '^[1-9]%d?%d?%d?%d?%d?%d?%d?$' ) then
return false
end
return '[http://id.worldcat.org/fast/'..id..'/ '..id..']'..p.getCatForId( 'FAST' )
end

function p.fnzaLink( id )
--P6792's format regex: [1-9]\d* (e.g. 9785)
if not id:match( '^[1-9]%d*$' ) then
return false
end
return '[https://findnzartists.org.nz/artist/'..id..'/ '..id..']'..p.getCatForId( 'FNZA' )
end

function p.gndLink( id )
--P227's format regex: 1[012]?\d{7}[0-9X]|[47]\d{6}-\d|[1-9]\d{0,7}-[0-9X]|3\d{7}[0-9X] (e.g. 4079154-3)
if not id:match( '^1[012]?%d%d%d%d%d%d%d[0-9X]$' ) and
not id:match( '^[47]%d%d%d%d%d%d%-%d$' ) and
not id:match( '^[1-9]%d?%d?%d?%d?%d?%d?%d?%-[0-9X]$' ) and
not id:match( '^3%d%d%d%d%d%d%d[0-9X]$' ) then
return false
end
return '[https://d-nb.info/gnd/'..id..' '..id..']'..p.getCatForId( 'GND' )
end

function p.hdsLink( id )
--P902's format regex: \d{6} (e.g. 050123)
if not id:match( '^%d%d%d%d%d%d$' ) then
return false
end
return '[https://hls-dhs-dss.ch/fr/articles/'..id..' '..id..']'..p.getCatForId( 'HDS' )
end

function p.iaafLink( id )
--P1146's format regex: [0-9][0-9]* (e.g. 012)
if not id:match( '^%d+$' ) then
return false
end
return '[https://www.iaaf.org/athletes/_/'..id..' '..id..']'..p.getCatForId( 'IAAF' )
end

function p.iciaLink( id )
--P1736's format regex: \d+ (e.g. 1)
if not id:match( '^%d+$' ) then
return false
end
return '[https://www.imj.org.il/artcenter/newsite/en/?artist='..id..' '..id..']'..p.getCatForId( 'ICIA' )
end

function p.ieuLink( id )
--P9070's format regex: [A-Z]\\[A-Z]\\[A-Za-z0-9]+ (e.g. K\Y\Kyiv)
if not id:match( '^[A-Z]\\[A-Z]\\%w+$' ) then
return false
end
return '[http://www.encyclopediaofukraine.com/display.asp?linkpath=pages\\'..id..' '..id..']'..p.getCatForId( 'IEU' )
end

function p.isniLink( id )
id = p.validateIsni( id ) --e.g. 0000-0000-6653-4145
if not id then
return false
end
return '[https://isni.org/isni/'..id..' '..id:sub( 1, 4 )..' '..id:sub( 5, 8 )..' '..id:sub( 9, 12 )..' '..id:sub( 13, 16 )..']'..p.getCatForId( 'ISNI' ) --no https as of 9/2019
end

function p.jocondeLink( id )
--P347's format regex: [\-0-9A-Za-z]{11} (e.g. 12345678901)
local regex = '^'..string.rep('[%-0-9A-Za-z]', 11)..'$'
if not id:match( regex ) then
return false
end
return '[https://www.pop.culture.gouv.fr/notice/joconde/'..id..' '..id..']'..p.getCatForId( 'Joconde' )
end

function p.kulturnavLink( id )
--P1248's format regex: [0-9a-f]{8}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{12} (e.g. 12345678-1234-1234-1234-1234567890AB)
if not id:match( '^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$' ) then
return false
end
return '[http://kulturnav.org/'..id..' '..id..']'..p.getCatForId( 'KULTURNAV' ) --no https as of 9/2019
end

function p.lccnLink( id )
local parts = p.splitLccn( id ) --e.g. n78039510
if not parts then
return false
end
local lccnType = parts[1] ~= 'sh' and 'names' or 'subjects'
id = parts[1] .. parts[2] .. p.append( parts[3], '0', 6 )
return '[https://id.loc.gov/authorities/'..lccnType..'/'..id..' '..id..']'..p.getCatForId( 'LCCN' )
end

function p.lirLink( id )
--P886's format regex: \d+ (e.g. 1)
if not id:match( '^%d+$' ) then
return false
end
return '[http://www.e-lir.ch/e-LIR___Lexicon.'..id..'.450.0.html '..id..']'..p.getCatForId( 'LIR' ) --no https as of 9/2019
end

function p.lnbLink( id )
--P1368's format regex: \d{9} (e.g. 123456789)
if not id:match( '^%d%d%d%d%d%d%d%d%d$' ) then
return false
end
return '[https://kopkatalogs.lv/F?func=direct&local_base=lnc10&doc_number='..id..'&P_CON_LNG=ENG '..id..']'..p.getCatForId( 'LNB' )
end

function p.leonoreLink( id )
--P640's format regex: LH/\d{1,4}/\d{1,3}|19800035/\d{1,4}/\d{1,5}(Bis)?|C/0/\d{1,2} (e.g. LH/2064/18)
if not id:match( '^LH/%d%d?%d?%d?/%d%d?%d?$' ) and --IDs from LH/1/1 to LH/2794/54 (legionaries)
not id:match( '^19800035/%d%d?%d?%d?/%d%d?%d?%d?%d?$' ) and --IDs from 19800035/1/1 to 19800035/385/51670 (legionnaires who died 1954-1977 & some who died < 1954)
not id:match( '^C/0/%d%d?$' ) then --IDs from C/0/1 to C/0/84 (84 famous legionaries)
return false
end
return '[http://www.culture.gouv.fr/public/mistral/leonore_fr?ACTION=CHERCHER&FIELD_1=COTE&VALUE_1='..id..' '..id..']'..p.getCatForId( 'Léonore' ) --no https as of 9/2019
end

function p.maLink( id )
--P6366's format regex: [1-9]\d{4,9} (e.g. 1498221862)
if not id:match( '^[1-9]%d%d%d%d%d?%d?%d?%d?%d?$' ) then
return false
end
return '[https://academic.microsoft.com/v2/detail/'..id..' '..id..']'..p.getCatForId( 'MA' )
end

function p.mbaLink( id )
--P434's format regex: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} (e.g. 12345678-1234-1234-1234-1234567890AB)
if not id:match( '^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$' ) then
return false
end
return '[https://musicbrainz.org/artist/'..id..' '..id..']'..p.getCatForId( 'MusicBrainz' ) --special cat name
end

function p.mbareaLink( id )
--P982's format regex: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} (e.g. 12345678-1234-1234-1234-1234567890AB)
if not id:match( '^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$' ) then
return false
end
return '[https://musicbrainz.org/area/'..id..' '..id..']'..p.getCatForId( 'MusicBrainz地域' ) --special cat name
end

function p.mbiLink( id )
--P1330's format regex: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} (e.g. 12345678-1234-1234-1234-1234567890AB)
if not id:match( '^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$' ) then
return false
end
return '[https://musicbrainz.org/instrument/'..id..' '..id..']'..p.getCatForId( 'MusicBrainz楽器' ) --special cat name
end

function p.mblLink( id )
--P966's format regex: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} (e.g. 12345678-1234-1234-1234-1234567890AB)
if not id:match( '^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$' ) then
return false
end
return '[https://musicbrainz.org/label/'..id..' '..id..']'..p.getCatForId( 'MusicBrainzレーベル' ) --special cat name
end

function p.mbpLink( id )
--P1004's format regex: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} (e.g. 12345678-1234-1234-1234-1234567890AB)
if not id:match( '^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$' ) then
return false
end
return '[https://musicbrainz.org/place/'..id..' '..id..']'..p.getCatForId( 'MusicBrainz場所' ) --special cat name
end

function p.mbrgLink( id )
--P436's format regex: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} (e.g. 12345678-1234-1234-1234-1234567890AB)
if not id:match( '^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$' ) then
return false
end
return '[https://musicbrainz.org/release-group/'..id..' '..id..']'..p.getCatForId( 'MusicBrainzリリース・グループ' ) --special cat name
end

function p.mbsLink( id )
--P1407's format regex: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} (e.g. 12345678-1234-1234-1234-1234567890AB)
if not id:match( '^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$' ) then
return false
end
return '[https://musicbrainz.org/series/'..id..' '..id..']'..p.getCatForId( 'MusicBrainzシリーズ' ) --special cat name
end

function p.mbwLink( id )
--P435's format regex: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} (e.g. 12345678-1234-1234-1234-1234567890AB)
if not id:match( '^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$' ) then
return false
end
return '[https://musicbrainz.org/work/'..id..' '..id..']'..p.getCatForId( 'MusicBrainz作品' ) --special cat name
end

function p.mgpLink( id )
--P549's format regex: \d{1,6} (e.g. 123456)
if not id:match( '^%d%d?%d?%d?%d?%d?$' ) then
return false
end
return '[https://genealogy.math.ndsu.nodak.edu/id.php?id='..id..' '..id..']'..p.getCatForId( 'MGP' )
end

function p.naraLink( id )
--P1225's format regex: ^([1-9]\d{0,8})$ (e.g. 123456789)
if not id:match( '^[1-9]%d?%d?%d?%d?%d?%d?%d?%d?$' ) then
return false
end
return '[https://catalog.archives.gov/id/'..id..' '..id..']'..p.getCatForId( 'NARA' )
end

function p.nclLink( id )
--P1048's format regex: \d+ (e.g. 1081436)
if not id:match( '^%d+$' ) then
return false
end
return '[http://aleweb.ncl.edu.tw/F/?func=accref&acc_sequence='..id..'&CON_LNG=ENG '..id..']'..p.getCatForId( 'NCL' ) --no https as of 9/2019
end

function p.ndlLink( id )
--P349's format regex: 0?\d{8} (e.g. 012345678)
if not id:match( '^0?%d%d%d%d%d%d%d%d$' ) then
return false
end
return '[https://id.ndl.go.jp/auth/ndlna/'..id..' '..id..']'..p.getCatForId( 'NDL' )
end

function p.ngvLink( id )
--P2041's format regex: \d+ (e.g. 12354)
if not id:match( '^%d+$' ) then
return false
end
return '[https://www.ngv.vic.gov.au/explore/collection/artist/'..id..'/ '..id..']'..p.getCatForId( 'NGV' )
end

function p.nkcLink( id )
--P691's format regex: [a-z]{2,4}[0-9]{2,14} (e.g. abcd12345678901234)
if not id:match( '^[a-z][a-z][a-z]?[a-z]?%d%d%d?%d?%d?%d?%d?%d?%d?%d?%d?%d?%d?%d?$' ) then
return false
end
return '[https://aleph.nkp.cz/F/?func=find-c&local_base=aut&ccl_term=ica='..id..'&CON_LNG=ENG '..id..']'..p.getCatForId( 'NKC' )
end

function p.nlaLink( id )
--P409's format regex: [1-9][0-9]{0,11} (e.g. 123456789012)
if not id:match( '^[1-9]%d?%d?%d?%d?%d?%d?%d?%d?%d?%d?%d?$' ) then
return false
end
return '[https://nla.gov.au/anbd.aut-an'..id..' '..id..']'..p.getCatForId( 'NLA' )
end

function p.nlgLink( id )
--P3348's format regex: [1-9]\d* (e.g. 1)
if not id:match( '^[1-9]%d*$' ) then
return false
end
return '[https://data.nlg.gr/resource/authority/record'..id..' '..id..']'..p.getCatForId( 'NLG' )
end

function p.nliLink( id )
--P949's format regex: \d{9} (e.g. 123456789)
if not id:match( '^%d%d%d%d%d%d%d%d%d$' ) then
return false
end
return '[http://uli.nli.org.il/F/?func=direct&doc_number='..id..'&local_base=nlx10'..' '..id..']'..p.getCatForId( 'NLI' )
end

function p.nlkLink( id )
--P5034's format regex: KA.(19|20).{7} (e.g. KAC201501465)
if not id:match( '^KA.19.......$' ) and
not id:match( '^KA.20.......$' ) then
return false
end
return '[https://nl.go.kr/authorities/resource/'..id..' '..id..']'..p.getCatForId( 'NLK' )
end

function p.nlpLink( id )
--P1695's format regex: 9810[0-9]\d* or A[0-9]{7}[0-9X] (e.g. 9810123456789012345 or A10414836)
if not id:match( '^9810%d+$' ) and
not id:match( '^A%d%d%d%d%d%d%d[%dX]$' ) then
return false
end
return '[https://tools.wmflabs.org/wikidata-externalid-url?p=1695&id='..id..' '..id..']'..p.getCatForId( 'NLP' )
end

function p.nlrLink( id )
--P1003's format regex: \d{9} (e.g. 123456789)
if not id:match( '^%d%d%d%d%d%d%d%d%d$' ) then
return false
end
return '[http://aleph.bibnat.ro:8991/F/?func=direct&local_base=NLR10&doc_number='..id..' '..id..']'..p.getCatForId( 'NLR' )
end

function p.nskLink( id )
--P1375's format regex: \d{9} (e.g. 123456789)
if not id:match( '^%d%d%d%d%d%d%d%d%d$' ) then
return false
end
return '[http://katalog.nsk.hr/F/?func=direct&doc_number='..id..'&local_base=nsk10 '..id..']'..p.getCatForId( 'NSK' ) --no https as of 9/2019
end

function p.ntaLink( id )
--P1006's format regex: \d{8}[\dX] (e.g. 12345678X)
if not id:match( '^%d%d%d%d%d%d%d%d[%dX]$' ) then
return false
end
return '[http://data.bibliotheken.nl/id/thes/p'..id..' '..id..']'..p.getCatForId( 'NTA' )
end

function p.orcidLink( id )
id = p.validateIsni( id ) --e.g. 0000-0002-7398-5483
if not id then
return false
end
id = id:sub( 1, 4 )..'-'..id:sub( 5, 8 )..'-'..id:sub( 9, 12 )..'-'..id:sub( 13, 16 )
return '[https://orcid.org/'..id..' '..id..']'..p.getCatForId( 'ORCID' )
end

function p.plwabnLink( id )
--P7293's format regex: 981[0-9]{8}05606 (e.g. 9810696457305606)
if not id:match( '^981%d%d%d%d%d%d%d%d05606*$' ) then
return false
end
return '[http://mak.bn.org.pl/cgi-bin/KHW/makwww.exe?BM=1&NU=1&IM=4&WI='..id..' '..id..']'..p.getCatForId( 'PLWABN' )
end

function p.publonsLink( id )
--P3829's format regex: \d+ (e.g. 654601)
if not id:match( '^%d+$' ) then
return false
end
return '[https://publons.com/author/'..id..'/ '..id..']'..p.getCatForId( 'Publons' )
end

function p.picLink( id )
--P2750's format regex: [1-9]\d* (e.g. 1)
if not id:match( '^[1-9]%d*$' ) then
return false
end
return '[https://pic.nypl.org/constituents/'..id..' '..id..']'..p.getCatForId( 'PIC' )
end

function p.ridLink( id )
--P1053's format regex: [A-Z]{1,3}-\d{4}-(19|20)\d\d (e.g. AAS-5150-2020)
if not id:match( '^[A-Z][A-Z]?[A-Z]?%-%d%d%d%d%-19%d%d$' ) and
not id:match( '^[A-Z][A-Z]?[A-Z]?%-%d%d%d%d%-20%d%d$' ) then
return false
end
return '[https://www.researcherid.com/rid/'..id..' '..id..']'..p.getCatForId( 'RID' )
end

function p.reroLink( id )
--P3065's format regex: 0[1-2]-[A-Z0-9]{1,10} (e.g. 02-A012345678)
if not id:match( '^0[1-2]%-[A-Z%d][A-Z%d]?[A-Z%d]?[A-Z%d]?[A-Z%d]?[A-Z%d]?[A-Z%d]?[A-Z%d]?[A-Z%d]?[A-Z%d]?$' ) then
return false
end
return '[http://data.rero.ch/'..id..' '..id..']'..p.getCatForId( 'RERO' )
end

function p.rismLink( id )
--P5504's format regex: (pe|ks)?\[1-9]d* (e.g. pe30006410)
if not id:match( '^pe[1-9]%d*$' ) and --99% start with 'pe'
not id:match( '^ks[1-9]%d*$' ) and
not id:match( '^[1-9]%d*$' ) then
return false
end
return '[https://opac.rism.info/search?id='..id..' '..id..']'..p.getCatForId( 'RISM' )
end

function p.rkdartistsLink( id )
--P650's format regex: [1-9]\d{0,5} (e.g. 123456)
if not id:match( '^[1-9]%d?%d?%d?%d?%d?$' ) then
return false
end
return '[https://rkd.nl/en/explore/artists/'..id..' '..id..']'..p.getCatForId( 'RKDartists' )
end

function p.rkdidLink( id )
--P350's format regex: [1-9]\d{0,5} (e.g. 123456)
if not id:match( '^[1-9]%d?%d?%d?%d?%d?$' ) then
return false
end
return '[https://rkd.nl/nl/explore/images/'..id..' '..id..']'..p.getCatForId( 'RKDID' )
end

function p.rslLink( id )
--P947's format regex: \d{1,9} (e.g. 123456789)
if not id:match( '^%d%d?%d?%d?%d?%d?%d?%d?%d?$' ) then
return false
end
return '[http://aleph.rsl.ru/F?func=find-b&find_code=SYS&adjacent=Y&local_base=RSL11&request='..id..'&CON_LNG=ENG '..id..']'..p.getCatForId( 'RSL' ) --no https as of 9/2019
end

function p.iccuLink( id )
--P396's format regex: IT\\ICCU\\(\d{10}|\D\D[\D\d]\D\\\d{6}) (e.g. IT\ICCU\CFIV\000163)
if not id:match( '^IT\\ICCU\\%d%d%d%d%d%d%d%d%d%d$' ) and
not id:match( '^IT\\ICCU\\%u%u[%u%d]%u\\%d%d%d%d%d%d$' ) then --legacy: %u used here instead of %D (but the faulty ID cat is empty, out of ~12k uses)
return false
end
return '[https://opac.sbn.it/opacsbn/opac/iccu/scheda_authority.jsp?bid='..id..' '..id..']'..p.getCatForId( 'ICCU' )
end

function p.selibrLink( id )
--P906's format regex: [1-9]\d{4,5} (e.g. 123456)
if not id:match( '^[1-9]%d%d%d%d%d?$' ) then
return false
end
return '[https://libris.kb.se/auth/'..id..' '..id..']'..p.getCatForId( 'SELIBR' )
end

function p.sikartLink( id )
--P781's format regex: \d{7,9} (e.g. 123456789)
if not id:match( '^%d%d%d%d%d%d%d%d?%d?$' ) then
return false
end
return '[http://www.sikart.ch/KuenstlerInnen.aspx?id='..id..'&lng=en '..id..']'..p.getCatForId( 'SIKART' ) --no https as of 9/2019
end

function p.snacLink( id )
--P3430's format regex: \d*[A-Za-z][0-9A-Za-z]* (e.g. A)
if not id:match( '^%d*[A-Za-z][0-9A-Za-z]*$' ) then
return false
end
return '[https://snaccooperative.org/ark:/99166/'..id..' '..id..']'..p.getCatForId( 'SNAC-ID' )
end

function p.sudocLink( id )
--P269's format regex: (\d{8}[\dX]|) (e.g. 026927608)
if not id:match( '^%d%d%d%d%d%d%d%d[%dxX]$' ) then --legacy: allow lowercase 'x'
return false
end
return '[https://www.idref.fr/'..id..' '..id..']'..p.getCatForId( 'SUDOC' )
end

function p.s2authoridLink( id )
--P4012's format regex: [1-9]\d* (e.g. 1796130)
if not id:match( '^[1-9]%d*$' ) then
return false
end
return '[https://www.semanticscholar.org/author/'..id..' '..id..']'..p.getCatForId( 'Semantic Scholar著者' ) --special cat name
end

function p.ta98Link( id )
--P1323's format regex: A\d{2}\.\d\.\d{2}\.\d{3}[FM]? (e.g. A12.3.45.678)
if not id:match( '^A%d%d%.%d%.%d%d%.%d%d%d[FM]?$' ) then
return false
end
return '[http://tools.wmflabs.org/wikidata-externalid-url/?p=1323&url_prefix=https:%2F%2Fwww.unifr.ch%2Fifaa%2FPublic%2FEntryPage%2FTA98%20Tree%2FEntity%20TA98%20EN%2F&url_suffix=%20Entity%20TA98%20EN.htm&id='..id..' '..id..']'..p.getCatForId( 'TA98' )
end

function p.tdviaLink( id )
--P7314's format regex: [a-z/-]+] (e.g. barkan-omer-lutfi)
if not id:match( '^[a-z/-]+$' ) then
return false
end
return '[https://islamansiklopedisi.org.tr/'..id..' '..id..']'..p.getCatForId( 'TDVİA' )
end

function p.teLink( id )
--P1693's format regex: E[1-8]\.\d{1,2}\.\d{1,2}\.\d{1,2}\.\d{1}\.\d{1}\.\d{1,3} (e.g. E1.23.45.67.8.9.0)
local e1, e2 = id:match( '^E([1-8])%.(%d%d?)%.%d%d?%.%d%d?%.%d%.%d%.%d%d?%d?$' )
if not e1 then
return false
end
local TEnum = 'TEe0'..e1 --no formatter URL in WD, probably due to this complexity
if e1 == '5' or e1 == '7' then
if #e2 == 1 then e2 = '0'..e2 end
TEnum = TEnum..e2
end
return '[http://www.unifr.ch/ifaa/Public/EntryPage/ViewTE/'..TEnum..'.html '..id..']'..p.getCatForId( 'TE' )
end

function p.tepapaLink( id )
--P3544's format regex: \d+ (e.g. 1)
if not id:match( '^%d+$' ) then
return false
end
return '[https://collections.tepapa.govt.nz/agent/'..id..' '..id..']'..p.getCatForId( 'TePapa' )
end

function p.thLink( id )
--P1694's format regex: H\d\.\d{2}\.\d{2}\.\d\.\d{5} (e.g. H1.23.45.6.78901)
local h1, h2 = id:match( '^H(%d)%.(%d%d)%.%d%d%.%d%.%d%d%d%d%d$' )
if not h1 then
return false
end
local THnum = 'THh'..h1..h2 --no formatter URL in WD, probably due to this complexity
return '[http://www.unifr.ch/ifaa/Public/EntryPage/ViewTH/'..THnum..'.html '..id..']'..p.getCatForId( 'TH' )
end

function p.tlsLink( id )
local id2 = id:gsub(' +', '_')
--P1362's format regex: \p{Lu}[\p{L}\d_',\.\-\(\)\*/–]{3,59} (e.g. Abcd)
local class = "[%a%d_',%.%-%(%)%*/–]"
local regex = "^%u"..string.rep(class, 3)..string.rep(class.."?", 56).."$"
if not mw.ustring.match( id2, regex ) then
return false
end
return '[http://tls.theaterwissenschaft.ch/wiki/'..id2..' '..id..']'..p.getCatForId( 'TLS' ) --no https as of 9/2019
end

function p.troveLink( id )
--P1315's format regex: [1-9]\d{5,7} (e.g. 12345678)
if not id:match( '^[1-9]%d%d%d%d%d%d?%d?$' ) then
return false
end
return '[https://trove.nla.gov.au/people/'..id..' '..id..']'..p.getCatForId( 'Trove' )
end

function p.ukparlLink( id )
--P6213's format regex: [a-zA-Z\d]{8} (e.g. AQUupyiR)
if not id:match( '^[a-zA-Z%d][a-zA-Z%d][a-zA-Z%d][a-zA-Z%d][a-zA-Z%d][a-zA-Z%d][a-zA-Z%d][a-zA-Z%d]$' ) then
return false
end
return '[https://id.parliament.uk/'..id..' '..id..']'..p.getCatForId( 'UKPARL' )
end

function p.ulanLink( id )
--P245's format regex: 500\d{6} (e.g. 500123456)
if not id:match( '^500%d%d%d%d%d%d$' ) then
return false
end
return '[https://www.getty.edu/vow/ULANFullDisplay?find=&role=&nation=&subjectid='..id..' '..id..']'..p.getCatForId( 'ULAN' )
end

function p.uscongressLink( id )
--P1157's format regex: [A-Z]00[01]\d{3} (e.g. A000123)
if not id:match( '^[A-Z]00[01]%d%d%d$' ) then
return false
end
return '[http://bioguide.congress.gov/scripts/biodisplay.pl?index='..id..' '..id..']'..p.getCatForId( 'USCongress' ) --no https as of 9/2019
end

function p.vcbaLink( id )
--P8034's format regex: \d{3}\/[1-9]\d{0,5} (e.g. 494/9793)
if not id:match( '^%d%d%d\/[1-9]%d?%d?%d?%d?%d?$' ) then
return false
end
local id2 = id:gsub('\/', '_')
return '[https://opac.vatlib.it/auth/detail/'..id2..' '..id..']'..p.getCatForId( 'VcBA' )
end

function p.viafLink( id )
--P214's format regex: [1-9]\d(\d{0,7}|\d{17,20}) (e.g. 123456789, 1234567890123456789012)
if not id:match( '^[1-9]%d%d?%d?%d?%d?%d?%d?%d?$' ) and
not id:match( '^[1-9]%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d?%d?%d?$' ) then
return false
end
-- If the "VIAF" entry at [[:m:Interwiki map]] would resolve to "https://viaf.org/viaf/$1" (rather than "http://viaf.org/viaf/$1", as it currently still does), the code below could change from '[https://viaf.org/viaf/'..id..' '..id..']' to '[[:VIAF:'..id..'|'..id..']]'.
return '[https://viaf.org/viaf/'..id..' '..id..']'..p.getCatForId( 'VIAF' )
end

--[[=========================== Helper functions =============================]]

function p.append(str, c, length)
while str:len() < length do
str = c .. str
end
return str
end

--Returns the ISNI check digit isni must be a string where the 15 first elements are digits, e.g. 0000000066534145
function p.getIsniCheckDigit( isni )
local total = 0
for i = 1, 15 do
local digit = isni:byte( i ) - 48 --Get integer value
total = (total + digit) * 2
end
local remainder = total % 11
local result = (12 - remainder) % 11
if result == 10 then
return "X"
end
return tostring( result )
end

--Validate ISNI (and ORCID) and retuns it as a 16 characters string or returns false if it's invalid
--See http://support.orcid.org/knowledgebase/articles/116780-structure-of-the-orcid-identifier
function p.validateIsni( id )
--P213 (ISNI) format regex: [0-9]{4} [0-9]{4} [0-9]{4} [0-9]{3}[0-9X] (e.g. 0000-0000-6653-4145)
--P496 (ORCID) format regex: 0000-000(1-[5-9]|2-[0-9]|3-[0-4])\d{3}-\d{3}[\dX] (e.g. 0000-0002-7398-5483)
id = id:gsub( '[ %-]', '' ):upper()
if not id:match( '^%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d[%dX]$' ) then
return false
end
if p.getIsniCheckDigit( id ) ~= string.char( id:byte( 16 ) ) then
return false
end
return id
end

function p.splitLccn( id )
--P244's format regex: (n|nb|nr|no|ns|sh)([4-9][0-9]|00|20[0-1][0-9])[0-9]{6} (e.g. n78039510)
if id:match( '^%l%l?%l?%d%d%d%d%d%d%d%d%d?%d?$' ) then
id = id:gsub( '^(%l+)(%d+)(%d%d%d%d%d%d)$', '%1/%2/%3' )
end
if id:match( '^%l%l?%l?/%d%d%d?%d?/%d+$' ) then
return mw.text.split( id, '/' )
end
return false
end

--[[==========================================================================]]
--[[ Wikidata & documentation functions ]]
--[[==========================================================================]]

function p.getIdsFromWikidata( itemId, property )
local ids = {}
local statements = mw.wikibase.getBestStatements( itemId, property )
if statements then
for _, statement in ipairs( statements ) do
if statement.mainsnak.datavalue then
table.insert( ids, statement.mainsnak.datavalue.value )
end
end
end
end
end
end
return ids
end


local sections = {}
-- Creates a human-readable standalone wikitable version of p.conf, and tracking categories with page counts, for use in the documentation
local localparams = false
function p.docConfTable( frame )
local numsections = 0
local wikiTable = '{| class="wikitable sortable"\n'..
for _,_ in ipairs(config.sections) do numsections = numsections + 1 end
'! rowspan=2 | 識別子\n'..
for _ = 1,#qids+numsections do table.insert(sections,{}) end
'! rowspan=2 | 識別子表示名\n'..
local qslink = '' -- setup link to add using QuickStatements
'! rowspan=2; data-sort-type=number | ウィキデータのプロパティ\n'..
'! colspan=4 | 追跡カテゴリのページ数\n'..
'|-\n'..
'! [[:Category:典拠管理情報がある記事|'.. '記事]]\n'..
'! [[:Category:典拠管理情報がある利用者ページ|'.. '利用者ページ]]\n'..
'! [[:Category:典拠管理情報があるその他のページ|'.. 'その他のページ]]\n'..
'! [[:Category:誤った典拠管理情報が指定されている記事|'..'誤った識別子]]\n'..
'|-\n'
local lang = mw.getContentLanguage()
for _, conf in pairs( p.conf ) do
local param, link, pid = conf[1], conf[2], conf[3]
local category = conf.category or param
local args = { id = 'f', pid }
local wpl = frame:expandTemplate{ title = 'Wikidata property link', args = args }
--cats
local articleCat = category..'識別子が指定されている記事'
local userCat = category..'識別子が指定されている利用者ページ'
local miscCat = category..'識別子が指定されているその他のページ'
local faultyCat = '誤った'..category..'識別子が指定されている記事'
--counts
local articleCount = lang:formatNum( mw.site.stats.pagesInCategory(articleCat, 'pages') )
local userCount = lang:formatNum( mw.site.stats.pagesInCategory(userCat, 'pages') )
local miscCount = lang:formatNum( mw.site.stats.pagesInCategory(miscCat, 'pages') )
local faultyCount = lang:formatNum( mw.site.stats.pagesInCategory(faultyCat, 'pages') )
--concat
wikiTable = wikiTable..'\n'..
'|-\n'..
'||'..param..
'||'..link..
'||data-sort-value='..pid..'|'..wpl..
'||style="text-align: right;"|[[:Category:'..articleCat..'|'..articleCount..']]'..
'||style="text-align: right;"|[[:Category:'.. userCat..'|'.. userCount..']]'..
'||style="text-align: right;"|[[:Category:'.. miscCat..'|'.. miscCount..']]'..
'||style="text-align: right;"|[[:Category:'.. faultyCat..'|'.. faultyCount..']]'
end
--append derivative WorldCat cats
local wcd = { 'WorldCat-LCCN', 'WorldCat-VIAF' }
for _, w in pairs(wcd) do
local articleCat = w..'識別子が指定されている記事'
local articleCount = lang:formatNum( mw.site.stats.pagesInCategory(articleCat, 'pages') )
wikiTable = wikiTable..'\n'..
'|-\n'..
'||'..'—'..
'||'..w..
'||data-sort-value='..w..'|'..'—'..
'||style="text-align: right;"|[[:Category:'..articleCat..'|'..articleCount..']]'..
'||style="text-align: right;"|—'..
'||style="text-align: right;"|—'..
'||style="text-align: right;"|—'
end
return wikiTable..'\n|}'
end


-- check which identifiers to show/suppress in template
--[[==========================================================================]]
local show = {} -- setup list
--[[ Configuration ]]
local showall = true
--[[==========================================================================]]
local function stripP(pid)

if pid:match("^[Pp]%d+$") then
-- If a specific "(identifier) redirect" exists for an identifier, please route through this particular redirect rather than linking directly to the target page. This reduces clutter in "What links here" and improves reverse lookup of articles where a manifestation of this particular identifier is used.
pid = mw.ustring.gsub(pid,'[Pp]','') --strip P from property number

end
-- Parameter format: { 'parameter name', 'label', propertyId # in Wikidata, formatting/validation function }
if pid:match("^%d+$") then
p.conf = {
return tonumber(pid)
{ 'AAG', '[[:en:AAG (identifier)|AAG]]', 3372, p.aagLink },
{ 'ACM-DL', '[[ACM DL (識別子)|ACM DL]]', 864, p.acmLink },
{ 'ADB', '[[:en:ADB (identifier)|ADB]]', 1907, p.adbLink },
{ 'AGSA', '[[AGSA (識別子)|AGSA]]', 6804, p.agsaLink },
{ 'autores.uy', '[[autores.uy (識別子)|autores.uy]]', 2558, p.autoresuyLink },
{ 'AWR', '[[:en:AWR (identifier)|AWR]]', 4186, p.awrLink },
{ 'BALaT', '[[:en:BALaT (identifier)|BALaT]]', 3293, p.balatLink },
{ 'BIBSYS', '[[:en:BIBSYS (identifier)|BIBSYS]]', 1015, p.bibsysLink },
{ 'Bildindex', '[[:en:Bildindex (identifier)|Bildindex]]', 2092, p.bildLink },
{ 'BNC', '[[:en:BNC (identifier)|BNC]]', 1890, p.bncLink },
{ 'BNE', '[[BNE (識別子)|BNE]]', 950, p.bneLink },
{ 'BNF', '[[BNF (識別子)|BNF]]', 268, p.bnfLink },
{ 'Botanist', '[[Botanist (識別子)|植物学者]]', 428, p.botanistLink },
{ 'BPN', '[[:en:BPN (identifier)|BPN]]', 651, p.bpnLink },
{ 'CANTIC', '[[:en:CANTIC (identifier)|CANTIC]]', 1273, p.canticLink },
{ 'CINII', '[[CiNii (識別子)|CiNii]]', 271, p.ciniiLink },
{ 'CWGC', '[[CWGC (識別子)|CWGC]]', 1908, p.cwgcLink },
{ 'DAAO', '[[:en:DAAO (identifier)|DAAO]]', 1707, p.daaoLink },
{ 'DBLP', '[[DBLP (識別子)|DBLP]]', 2456, p.dblpLink },
{ 'DIB', '[[:en:DIB (identifier)|DIB]]', 6829, p.dibLink },
{ 'DSI', '[[:en:DSI (identifier)|DSI]]', 2349, p.dsiLink },
{ 'FAST', '[[:en:FAST (identifier)|FAST]]', 2163, p.fastLink },
{ 'FNZA', '[[:en:FNZA (identifier)|FNZA]]', 6792, p.fnzaLink },
{ 'GND', '[[GND (識別子)|GND]]', 227, p.gndLink },
{ 'HDS', '[[HDS (識別子)|HDS]]', 902, p.hdsLink },
{ 'IAAF', '[[IAAF (識別子)|IAAF]]', 1146, p.iaafLink },
{ 'ICCU', '[[:en:ICCU (identifier)|ICCU]]', 396, p.iccuLink }, --formerly SBN
{ 'ICIA', '[[:en:ICIA (identifier)|ICIA]]', 1736, p.iciaLink },
{ 'IEU', '[[:en:IEU (identifier)|IEU]]', 9070, p.ieuLink },
{ 'ISNI', '[[ISNI (識別子)|ISNI]]', 213, p.isniLink },
{ 'Joconde', '[[:en:Joconde (identifier)|Joconde]]' , 347, p.jocondeLink },
{ 'KULTURNAV', '[[:en:KulturNav (identifier)|KulturNav]]', 1248, p.kulturnavLink },
{ 'LCCN', '[[LCCN (識別子)|LCCN]]', 244, p.lccnLink },
{ 'LIR', '[[LIR (識別子)|LIR]]', 886, p.lirLink },
{ 'LNB', '[[:en:LNB (identifier)|LNB]]', 1368, p.lnbLink },
{ 'Léonore', '[[:en:Léonore (identifier)|Léonore]]', 640, p.leonoreLink },
{ 'MA', '[[:en:MA (identifier)|MA]]', 6366, p.maLink },
{ 'MBA', '[[MBA (識別子)|MBA]]', 434, p.mbaLink, category = 'MusicBrainz' }, --special cat name
{ 'MBAREA', '[[MBAREA (識別子)|MBAREA]]', 982, p.mbareaLink, category = 'MusicBrainz地域' }, --special cat name
{ 'MBI', '[[MBI (識別子)|MBI]]', 1330, p.mbiLink, category = 'MusicBrainz楽器' }, --special cat name
{ 'MBL', '[[MBL (識別子)|MBL]]', 966, p.mblLink, category = 'MusicBrainzレーベル' }, --special cat name
{ 'MBP', '[[MBP (識別子)|MBP]]', 1004, p.mbpLink, category = 'MusicBrainz場所' }, --special cat name
{ 'MBRG', '[[MBRG (識別子)|MBRG]]', 436, p.mbrgLink, category = 'MusicBrainzリリース・グループ' }, --special cat name
{ 'MBS', '[[MBS (識別子)|MBS]]', 1407, p.mbsLink, category = 'MusicBrainzシリーズ' }, --special cat name
{ 'MBW', '[[MBW (識別子)|MBW]]', 435, p.mbwLink, category = 'MusicBrainz作品' }, --special cat name
{ 'MGP', '[[MGP (識別子)|MGP]]', 549, p.mgpLink },
{ 'NARA', '[[NARA (識別子)|NARA]]', 1225, p.naraLink },
{ 'NCL', '[[NCL (識別子)|NCL]]', 1048, p.nclLink },
{ 'NDL', '[[NDL (識別子)|NDL]]', 349, p.ndlLink },
{ 'NGV', '[[NGV (識別子)|NGV]]', 2041, p.ngvLink },
{ 'NKC', '[[:en:NKC (identifier)|NKC]]', 691, p.nkcLink },
{ 'NLA', '[[NLA (識別子)|NLA]]', 409, p.nlaLink },
{ 'NLG', '[[:en:NLG (identifier)|NLG]]', 3348, p.nlgLink },
{ 'NLI', '[[NLI (識別子)|NLI]]', 949, p.nliLink },
{ 'NLK', '[[NLK (識別子)|NLK]]', 5034, p.nlkLink },
{ 'NLP', '[[NLP (識別子)|NLP]]', 1695, p.nlpLink },
{ 'NLR', '[[NLR (識別子)|NLR]]', 1003, p.nlrLink },
{ 'NSK', '[[:en:NSK (identifier)|NSK]]', 1375, p.nskLink },
{ 'NTA', '[[:en:NTA (identifier)|NTA]]', 1006, p.ntaLink },
{ 'ORCID', '[[ORCID (識別子)|ORCID]]', 496, p.orcidLink },
{ 'PIC', '[[:en:PIC (identifier)|PIC]]', 2750, p.picLink },
{ 'Publons', '[[:en:Publons (identifier)|Publons]]', 3829, p.publonsLink },
{ 'RERO', '[[:en:RERO (identifier)|RERO]]', 3065, p.reroLink },
{ 'RID', '[[RID (識別子)|ResearcherID]]', 1053, p.ridLink },
{ 'RISM', '[[:en:RISM (identifier)|RISM]]', 5504, p.rismLink },
{ 'RKDartists', '[[RKDartists (識別子)|RKD]]', 650, p.rkdartistsLink },
{ 'RKDID', '[[RKDID (識別子)|RKDimages ID]]', 350, p.rkdidLink },
{ 'RSL', '[[RSL (識別子)|RSL]]', 947, p.rslLink },
{ 'SELIBR', '[[:en:SELIBR (identifier)|SELIBR]]', 906, p.selibrLink },
{ 'SIKART', '[[:en:SIKART (identifier)|SIKART]]', 781, p.sikartLink },
{ 'SNAC-ID', '[[SNAC-ID (識別子)|SNAC]]', 3430, p.snacLink },
{ 'SUDOC', '[[SUDOC (識別子)|SUDOC]]', 269, p.sudocLink },
{ 'S2AuthorId', '[[:en:S2AuthorId (identifier)|S2AuthorId]]', 4012, p.s2authoridLink, category = 'Semantic Scholar著者' }, --special cat name
{ 'TA98', '[[:en:TA98 (identifier)|TA98]]', 1323, p.ta98Link },
{ 'TDVİA', '[[:en:TDVİA (identifier)|TDVİA]]', 7314, p.tdviaLink },
{ 'TE', '[[:en:TE (identifier)|TE]]', 1693, p.teLink },
{ 'TePapa', '[[TePapa (識別子)|TePapa]]', 3544, p.tepapaLink },
{ 'TH', '[[:en:TH (identifier)|TH]]', 1694, p.thLink },
{ 'TLS', '[[:en:TLS (identifier)|TLS]]', 1362, p.tlsLink },
{ 'Trove', '[[:en:Trove (identifier)|Trove]]', 1315, p.troveLink }, --formerly NLA-person
{ 'UKPARL', '[[UKPARL (識別子)|英議会]]', 6213, p.ukparlLink },
{ 'ULAN', '[[:en:ULAN (identifier)|ULAN]]', 245, p.ulanLink },
{ 'USCongress', '[[:en:US Congress (identifier)|米議会]]', 1157, p.uscongressLink },
{ 'VcBA', '[[VcBA (識別子)|VcBA]]', 8034, p.vcbaLink },
{ 'VIAF', '[[VIAF (識別子)|VIAF]]', 214, p.viafLink },
{ 'WORLDCATID', '[[WorldCat Identities (識別子)|WorldCat Identities]]', 7859, nil },
}

-- Legitimate aliases to p.conf, for convenience
-- Format: { 'alias', 'parameter name in p.conf' }
p.aliases = {
{ 'DNB', 'GND' }, --Deutsche Nationalbibliothek -> Gemeinsame Normdatei
{ 'Leonore', 'Léonore' }, --alias name without diacritics
{ 'leonore', 'Léonore' }, --lowercase variant without diacritics
{ 'MusicBrainz', 'MBA' },
{ 'MusicBrainz artist', 'MBA' },
{ 'MusicBrainz label', 'MBL' },
{ 'MusicBrainz release group', 'MBRG' },
{ 'MusicBrainz work', 'MBW' },
{ 'SBN', 'ICCU' }, --SBN alias to be deprecated at a later stage
{ 'TDVIA', 'TDVİA' }, --alias name without diacritics
{ 'tdvia', 'TDVİA' }, --lowercase variant without diacritics
}

-- Deprecated aliases to p.conf; tracked in [[Category:Wikipedia articles with deprecated authority control identifiers]]
-- Format: { 'deprecated parameter name', 'replacement parameter name in p.conf' }
p.deprecated = {
{ 'GKD', 'GND' },
{ 'PND', 'GND' },
{ 'RLS', 'RSL' },
{ 'SWD', 'GND' },
{ 'NARA-organization', 'NARA' },
{ 'NARA-person', 'NARA' },
}

--[[==========================================================================]]
--[[ Main ]]
--[[==========================================================================]]

function p.authorityControl( frame )
local resolveEntity = require( "Module:ResolveEntityId" )
local parentArgs = frame:getParent().args --WD IDs added here later
local iParentArgs = 0 --count original/manual parent args only later
local elements = {} --create/insert rows later
local worldcatCat = ''
local multipleIdCat = ''
local suppressedIdCat = ''
local deprecatedIdCat = ''
local differentOnWDCat = ''
local sameOnWDCat = ''
--Redirect aliases to proper parameter names
for _, a in pairs( p.aliases ) do
local alias, param = a[1], a[2]
if (parentArgs[param] == nil or parentArgs[param] == '') and parentArgs[alias] then
parentArgs[param] = parentArgs[alias]
end
end
end
end
local function addshowlist(list)
if list and list ~= '' then
--Redirect deprecated parameters to proper parameter names, and assign tracking cat
for _, d in pairs( p.deprecated ) do
for _,v in ipairs(mw.text.split(string.lower(list),"%s*,%s*")) do
local dep, param = d[1], d[2]
local vprop = stripP(v)
if vprop then -- e.g. show=P214 to show one particular property
if (parentArgs[param] == nil or parentArgs[param] == '') and parentArgs[dep] then
parentArgs[param] = parentArgs[dep]
show[vprop] = true
else -- e.g. show=arts to use whitelist
if namespace == 0 then
if config.whitelists[v] then
deprecatedIdCat = '[[Category:非推奨の典拠管理識別子が指定されている記事|'..dep..']]'
for _,w in ipairs(config.whitelists[v].properties) do
show[w] = true
end
end
end
end
end
showall = false
end
end
end
end
addshowlist(frame.args.show) -- check show= parameter on wrapper template
addshowlist(parentArgs.show or parentArgs.country) -- check show parameter on article template
--Use QID= parameter for testing/example purposes only
if parentArgs.suppress then
local itemId = nil
local suppresslist = mw.text.split(parentArgs.suppress,"%s*,%s*") -- split parameter by comma
if namespace ~= 0 then
for _,v in ipairs(suppresslist) do
local qid = parentArgs['qid'] or parentArgs['QID']
v = stripP(string.upper(v))
if qid then
if v then
itemId = 'Q'..mw.ustring.gsub(qid, '^[Qq]', '')
show[v] = false
itemId = resolveEntity._id(itemId) --nil if unresolvable
auxCats = auxCats .. '[[' .. config.i18n.category .. ':' .. config.i18n.suppressedcat .. ']]'
else
auxCats = auxCats .. needsAttention('P')
end
end
end
else
itemId = mw.wikibase.getEntityIdForCurrentPage()
end
end
local function makeSections(qid,addit)
--Wikidata fallback if available
local tval = {}
if itemId then
local iMatches = 0
local function parameter_is_used(property)
local used = false
for _, params in ipairs( p.conf ) do
if params[3] > 0 then
if property then
if tval[property] then
if tval[property][1] then
used = true
end
elseif tval[property] == false then -- property has been manually suppressed
used = true
end
end
return used
end
for _, params in ipairs(conf) do
tval[params.property] = getIdsFromWikidata(qid, 'P' .. params.property) -- setup table for values with property number as key
local showb = true
if (show[params.property] == nil) and (show[string.upper(params[1])] == nil ) then
showb = showall -- if not specified then depends on showall
elseif (show[params.property] == false) or (show[string.upper(params[1])] == false) then -- if either are false then id will be suppressed
showb = false
end
if not showb then
tval[params.property] = false -- indicates the identifier is suppressed
elseif not addit then
local val = parentArgs[mw.ustring.lower(params[1])] or parentArgs[params[1]]
local val = parentArgs[mw.ustring.lower(params[1])] or parentArgs[params[1]]
if val == nil or val == '' then
if val and val~='' then -- add local parameter to list if not already in
localparams = true
local wikidataIds = p.getIdsFromWikidata( itemId, 'P'..params[3] )
if wikidataIds[1] then
local bnew = true
for _, w in pairs(tval[params.property]) do
if val == '' and (namespace == 0 or testcases) then
if val == w.id then
suppressedIdCat = '[[Category:抑制された典拠管理識別子がある記事|'..params[1]..']]'
else
bnew = false
parentArgs[params[1]] = wikidataIds[1] --add ID from WD
end
end
end
end
if bnew then -- add new value to table
else
if qid then
iParentArgs = iParentArgs + 1
-- 末尾はQ328(英語版ウィキペディア)ではなくQ177837(日本語版ウィキペディア)とする
local wikidataIds = p.getIdsFromWikidata( itemId, 'P'..params[3] )
qslink = qslink .. '%7C%7C' .. qid .. '%7CP' .. params.property .. '%7C%22' .. mw.uri.encode(val,"PATH") .. '%22%7CS143%7CQ177837'
if wikidataIds[1] and differentOnWDCat == '' then
local bMatch = false
for _, wd in pairs( wikidataIds ) do
if val == wd then
iMatches = iMatches + 1
bMatch = true
end
end
end
table.insert(tval[params.property],{id=val,name=''})
if bMatch == false then
end
differentOnWDCat = '[[Category:ウィキデータと異なる典拠管理識別子をパラメータで指定しているページ|'..params[1]..']]'
end end end end end
end
end
if iMatches > 0 and iMatches == iParentArgs then
local suppress = false
sameOnWDCat = '[[Category:ウィキデータと同じ典拠管理識別子をパラメータで指定しているページ]]'
if params.suppressedbyproperty then
for _,sc in ipairs(params.suppressedbyproperty) do
if parameter_is_used(sc) then
suppress = true
end
end
end
if tval[params.property] ~= false and not suppress then
local tlinks = {} -- setup table for links
local nextIdVal = 1
local row = ''
for _,val in ipairs(tval[params.property]) do
local link = _makelink(params,val,nextIdVal,qid)
row = row .. link
table.insert(tlinks,link)
nextIdVal = nextIdVal + 1
end
if nextIdVal>=2 then
row = row .. '\n'
table.insert(sections[addit or params.section],row)
rct = true
end
end
end
end
end
end
local function pencil(qid)
if not qid then
--Configured rows
return ''
local rct = 0
for _, params in ipairs( p.conf ) do
local val = parentArgs[mw.ustring.lower(params[1])] or parentArgs[params[1]]
local tval, tlinks = {}, {} --init tables
if val and val ~= '' and type(params[4]) == 'function' then
table.insert( tval, val )
table.insert( tlinks, params[4]( val ) )
end
end
local args = { pid = 'identifiers' } -- #target the list of identifiers
--collect other unique vals (IDs) from WD, if present
args.qid = qid
if itemId and tval[1] then
return require('Module:EditAtWikidata')._showMessage(args)
local wikidataIds = p.getIdsFromWikidata( itemId, 'P'..params[3] )
end
for _, v in pairs( wikidataIds ) do

local bnew = true
makeSections(qid,false)
for _, w in pairs( tval ) do
for c = 1,#qids do
if v == w then bnew = false end
makeSections(qids[c],numsections+c)
end
end
if bnew then

table.insert( tval, v )
--configure Navbox
table.insert( tlinks, params[4]( v ) )
local outString = ''
if rct or localparams then -- there is at least one link to display
local Navbox = require('Module:Navbox')
local sect,lastsect = 0,0
local navboxArgs = {
name = 'Authority control',
navboxclass = 'authority-control',
bodyclass = 'hlist',
state = parentArgs.state or config.i18n.autocollapse,
navbar = 'off'
}
for c=1,numsections+#qids do
if #sections[c] ~= 0 then -- section is non-empty
sect = sect + 1
lastsect = c
local sectname
if c <= numsections then -- regular section
sectname = config.sections[c].name
else -- section from additional qid
local qid = qids[c-numsections]
sectname = wikilink(qid) .. pencil(qid)
end
end
navboxArgs['group' .. c] = sectname
navboxArgs['list' .. c] = table.concat(sections[c])
end
end
end
end
if localparams then
--assemble
lastsect = lastsect + 1
if tval[1] then
sect = sect + 1
table.insert( elements, p.createRow( params[1], params[2]..':', tval, nil, tlinks, true, params.category ) )
navboxArgs['group' .. lastsect] = config.i18n.warning
rct = rct + 1
local warning = frame:expandTemplate{title = config.i18n.errortemplate, args = {config.i18n.localparams}}
if tval[2] then
if qslink ~= '' then
--multipleIdCat = p.getCatForId( 'multiple' ) -- 日本語版でのカテゴリ導入は様子を見てから
warning = warning .. ' ' .. config.i18n.movetowd .. '<span class="qs autoconfirmed-show">&#32;[[File:Commons to Wikidata QuickStatements.svg|20px|link=https://quickstatements.toolforge.org/#/v1=' .. qslink .. '|' .. config.i18n.addtowd .. ']]</span>'
elseif not qid then
if namespace == 0 then
warning = warning .. ' ' .. config.i18n.connecttowd
elseif namespace==14 or namespace==2 or namespace==118 then
warning = warning .. ' ' .. config.i18n.qidcode
end
end
end
navboxArgs['list' .. lastsect] = warning
end
end
if topic then -- display in expanded form with topic
end
navboxArgs.title = config.i18n.aclink .. ' &ndash; ' .. topic .. pencil(qid)
elseif sect == 1 then -- special display when only one section
--WorldCat
if lastsect <= numsections then
local worldcatId = parentArgs['worldcatid'] or parentArgs['WORLDCATID']
if config.sections[lastsect].hidelabelwhenalone then -- no special label when only general or other IDs are present
if worldcatId and worldcatId ~= '' then --if WORLDCATID present & unsuppressed
navboxArgs['group' .. lastsect] = config.i18n.aclink .. pencil(qid)
table.insert( elements, p.createRow( 'WORLDCATID', '', worldcatId, '[[WorldCat Identities (識別子)|WorldCat Identities]]: [https://www.worldcat.org/identities/'..worldcatId..' '..worldcatId..']', nil, false ) ) --Validation?
else -- other regular section
worldcatCat = p.getCatForId( 'WORLDCATID' )
navboxArgs['group' .. lastsect] = config.i18n.aclink .. ': ' .. navboxArgs['group' .. lastsect] .. pencil(qid)
elseif worldcatId == nil then --if WORLDCATID absent but unsuppressed
local viafId = parentArgs['viaf'] or parentArgs['VIAF']
local lccnId = parentArgs['lccn'] or parentArgs['LCCN']
if viafId and viafId ~= '' and p.viafLink( viafId ) then --VIAF must be present, unsuppressed, & validated
table.insert( elements, p.createRow( 'VIAF', '', viafId, '[[WorldCat Identities (識別子)|WorldCat Identities]](VIAF経由): [https://www.worldcat.org/identities/containsVIAFID/'..viafId..' '..viafId..']', nil, false ) )
if namespace == 0 then
worldcatCat = '[[Category:WorldCat-VIAF識別子が指定されている記事]]'
end
elseif lccnId and lccnId ~= '' and p.lccnLink( lccnId ) then --LCCN must be present, unsuppressed, & validated
local lccnParts = p.splitLccn( lccnId )
if lccnParts and lccnParts[1] ~= 'sh' then
local lccnIdFmtd = lccnParts[1]..lccnParts[2]..'-'..lccnParts[3]
table.insert( elements, p.createRow( 'LCCN', '', lccnId, '[[WorldCat Identities (識別子)|WorldCat Identities]](LCCN経由): [https://www.worldcat.org/identities/lccn-'..lccnIdFmtd..' '..lccnIdFmtd..']', nil, false ) )
if namespace == 0 then
worldcatCat = '[[Category:WorldCat-LCCN識別子が指定されている記事]]'
end
end
else -- section from additional qid
navboxArgs['group' .. lastsect] = config.i18n.aclink .. ': ' .. navboxArgs['group' .. lastsect]
end
end
else -- add title to navbox
navboxArgs.title = config.i18n.aclink .. pencil(qid)
end
outString = Navbox._navbox(navboxArgs)
else -- 典拠管理識別子が1つもない
if namespace == 0 or testcases then
auxCats = auxCats .. addCat('典拠管理識別子が1つもない記事')
end
end
elseif worldcatId == '' then --if WORLDCATID suppressed
suppressedIdCat = '[[Category:抑制された典拠管理識別子がある記事|WORLDCATID]]'
end
end
if parentArgs.state
local Navbox = require('Module:Navbox')
and parentArgs.state~=''
local elementsCat = ''
and parentArgs.state~=config.i18n.collapsed
if rct == 0 or rct >= 25 then
and parentArgs.state~=config.i18n.expanded
--local eCat = rct..'種類以上の識別子があるページ'
and parentArgs.state~=config.i18n.autocollapse then --invalid state parameter
--elementsCat = '[[Category:'..eCat..']]'..p.redCatLink(eCat)
auxCats = auxCats .. needsAttention('S')
elementsCat = '' --25種類以上の識別子が指定された場合、追跡カテゴリをつけるという機能は日本語版では導入されていない
end
end
local outString = ''
if #elements > 0 then
local args = { pid = 'identifiers' } -- #target the list of identifiers
if testcases and itemId then args = { pid = 'identifiers', qid = itemId } end --expensive
local pencil = frame:expandTemplate{ title = 'EditAtWikidata', args = args}
outString = Navbox._navbox( {
name = 'Normdaten',
navboxclass = 'authority-control',
bodyclass = 'hlist',
group1 = '[[Help:典拠管理|典拠管理]]'..pencil,
list1 = table.concat( elements )
} )
end
local auxCats = worldcatCat .. elementsCat .. multipleIdCat .. suppressedIdCat ..
deprecatedIdCat .. differentOnWDCat .. sameOnWDCat
if testcases then
if testcases then
auxCats = mw.ustring.gsub(auxCats, '(%[%[)(Category)', '%1:%2') --for easier checking
auxCats = mw.ustring.gsub(auxCats, '(%[%[)(' .. config.i18n.category .. ')', '%1:%2') --for easier checking
end
end

outString = outString .. auxCats
--out
outString = outString..auxCats
if namespace ~= 0 then
if namespace ~= 0 then
-- 日本語版独自の変更あり
outString = mw.ustring.gsub(outString, '(%[%[)(Category:[^%]]*記事)', '%1:%2') --by definition
outString = mw.ustring.gsub(outString,'(%[%[)(' .. config.i18n.category .. ':)([^%|%]]+' .. config.i18n.Articles .. ')%|?[^%|%]]*(%]%])','%1:%2%3%4')
end
end
local check = require('Module:Check for unknown parameters')._check
local sortkey
if namespace == 0 then
sortkey = '*' .. title.text
else
sortkey = title.fullText
end
outString = outString .. check({
['unknown'] = '[[' .. config.i18n.category .. ':' .. config.i18n.pageswithparams .. '|' .. sortkey .. ']]',
['preview'] = config.i18n.previewwarning, 'show', 'country', 'suppress', 'additional', 'qid', 'state'
}, parentArgs)
return outString
return outString
end

p.makelink = function(conf,val,nextid,qid)
return _makelink(conf,val,nextid,qid)
end
end



2023年8月31日 (木) 12:46時点における最新版

このモジュールについての説明文ページを モジュール:Authority control/doc に作成できます

require('strict')
local p = {}
local configfile = 'Module:Authority control/config' -- default configuation module
local arg = mw.getCurrentFrame().args.config
if arg and arg~='' then
	configfile = 'Module:Authority control/config/' .. arg
end
local config
if mw.title.new(configfile).exists then
	config = mw.loadData(configfile)
else
	return error('Invalid configuration file',0)
end
local title = mw.title.getCurrentTitle()
local namespace = title.namespace
local testcases = title.subpageText == config.i18n.testcases

local function needsAttention(sortkey)
	return '[[' .. config.i18n.category .. ':' .. config.i18n.attentioncat .. '|' .. sortkey .. title.text .. ']]'
end

local function addCat(cat,sortkey)
	if cat and cat ~= '' and (namespace == 0 or namespace == 14 or testcases) then
		local redlinkcat = ''
		if testcases == false and mw.title.new(cat, 14).exists == false then
			redlinkcat = needsAttention('N')
		end
		if sortkey then
			cat = '[[' .. config.i18n.category .. ':'..cat..'|' .. sortkey .. title.text .. ']]'
		else
			cat = '[[' .. config.i18n.category .. ':'..cat..']]'
		end
		cat = cat .. redlinkcat
		return cat
	else
		return ''
	end
end

local function getCatForId(id,faulty)
	local cat = string.format(
		config.i18n.cat,
		faulty and config.i18n.faulty..id or id
	)
	return addCat(cat)
end

local function getIdsFromWikidata(qid,property)
	local function getquals(statement,qualid)
		if statement.qualifiers and statement.qualifiers['P'..qualid] then
			return mw.wikibase.renderSnak(statement.qualifiers['P'..qualid][1])
		else
			return false
		end
	end
	local ids = {}
	if qid then
		for _, statement in ipairs(mw.wikibase.getBestStatements(qid,property)) do
			if statement.mainsnak.datavalue then
				local val = statement.mainsnak.datavalue.value
				if val then
					local namedas = getquals(statement,1810) or getquals(statement,742) or ''
					table.insert(ids,{id=val,name=namedas})
				end
			end
		end
	end
	return ids
end

local _makelink = function(conf,val,nextid,qid) --validate values and create a link
	local function tooltip(text,label)
		if label and label~='' then
			return mw.getCurrentFrame():expandTemplate{title = "Tooltip", args = {text,label}}
		else
			return text
		end
	end
	local link
	if nextid==1 then
		if conf.prefix then
			link = '*' .. conf.prefix .. '\n**'
		else
			link = '*'
		end
	else
		link = '\n**'
	end
	local valid_value = false
	if conf.customlink then -- use function to validate and generate link
		local label = nextid>1 and nextid
		local newlink= require(config.auxiliary)[conf.customlink](val.id,label)
		if newlink then
			link = link .. newlink
			valid_value = true
		end
	else
		if conf.pattern then -- use pattern to determine validity if defined
			valid_value = string.match(val.id,'^'..conf.pattern..'$')
		elseif conf.patterns then
			for _,pattern in ipairs(conf.patterns) do
				valid_value = val.id:match('^'..pattern..'$')
				if valid_value then break end
			end
		elseif conf.valid then -- otherwise use function to determine validity
			valid_value = require(config.auxiliary)[conf.valid](val.id)
		else -- no validation possible
			valid_value = val.id
		end
		if valid_value then
			local newlink
			local label = conf.label
			if not label or nextid>1 then
				label = tostring(nextid)
			end
			if conf.link then
				valid_value = valid_value:gsub('%%', '%%%%')
				newlink = '[' .. mw.ustring.gsub(conf.link,'%$1',valid_value) .. ' ' .. label .. ']'
			else
				newlink = valid_value
			end
			link = link .. '<span class="uid">'..tooltip(newlink,val.name)..'</span>'
		end
	end
	if valid_value then
		link = link .. getCatForId(conf.category or conf[1])
	else
		--local preview = require("Module:If preview")
		local wdlink = qid and '[[:wikidata:' .. qid .. '#P' .. conf.property .. ']]' or ''
		local tooltip = string.format(
			config.i18n.idnotvalid,
			conf[1],
			val.id
		)
		link = link .. '[[File:' .. config.i18n.warningicon .. '|20px|frameless|link=' .. wdlink .. '|' .. tooltip .. ']]'
		if conf.errorcat then
			link = link .. addCat(conf.errorcat)
		else
			link = link .. getCatForId(conf.category or conf[1],true)
		end
		link = link .. addCat(config.i18n.allfaultycat,conf[1])-- .. preview._warning({'The '..conf[1]..' id '..val..' is not valid.'})
	end
	return link
end

--[[==========================================================================]]
--[[                                   Main                                   ]]
--[[==========================================================================]]
function p.authorityControl(frame)
	local function resolveQID(qid)
		if qid then
			qid = 'Q'..mw.ustring.gsub(qid, '^[Qq]', '')
			if mw.wikibase.isValidEntityId(qid) and mw.wikibase.entityExists(qid) then
				local sitelink = mw.wikibase.getSitelink(qid)
				if sitelink then
					return mw.wikibase.getEntityIdForTitle(sitelink) or mw.wikibase.getEntity(qid).id
				end
				return mw.wikibase.getEntity(qid).id
			end
		end
	end
	local conf = config.config
	local parentArgs = frame:getParent().args
	local auxCats = ''
	local rct = false -- boolean to track if there are any links to be returned
	local qid,topic
	local wikilink = function(qid,hideifequal)
		local label,sitelink = mw.wikibase.getLabel(qid),mw.wikibase.getSitelink(qid)
		if label then
			if sitelink then
				local target = mw.title.new(sitelink)
				if target==title or (target.isRedirect and target.redirectTarget==title) then -- do not link
					return label
				else -- make wikilink to article
					return '[[' .. sitelink .. '|' .. label .. ']]'
				end
			else
				return label
			end
		else
			auxCats = auxCats .. needsAttention('L')
			return qid
		end
	end
	if namespace == 0 then
		qid = mw.wikibase.getEntityIdForCurrentPage()
	end
	if qid then -- article is connected to Wikidata item
		if parentArgs.qid and (resolveQID(parentArgs.qid) ~= qid) then -- non-matching qid parameter
			auxCats = auxCats .. needsAttention('D')
		end
	else -- page is not connected to any Wikidata item
		qid = resolveQID(parentArgs.qid) -- check qid parameter if no wikidata item is connected
		if qid then -- qid parameter is valid, set topic to display
			topic = mw.wikibase.getLabel(qid)
			if topic then
				if mw.ustring.lower(title.subpageText) == mw.ustring.lower(topic) then -- suppress topic display if subpagename equals topic up to case change
					topic = nil
				end
				if topic and mw.wikibase.getSitelink(qid) then -- make wikilink to article
					topic = '[[' .. mw.wikibase.getSitelink(qid) .. '|' .. topic .. ']]'
				end
			else
				auxCats = auxCats .. needsAttention('L')
			end
		elseif parentArgs.qid and parentArgs.qid~='' then -- invalid qid has been supplied, add to tracking cat
			auxCats = auxCats .. needsAttention('Q')
		end
	end
	local qids = {} -- setup any additional QIDs
	if parentArgs.additional=='auto' and qid then  -- check P527 for parts to add additional qids
		local checkparts = function(property)
			local parts = mw.wikibase.getBestStatements(qid,property)
			if parts then
				for _,part in ipairs(parts) do
					if part.mainsnak.datavalue and part.mainsnak.datavalue.value.id then
						local resolvedqid = resolveQID(part.mainsnak.datavalue.value.id)
						if resolvedqid then
							table.insert(qids,resolvedqid)
		end end end end end
		for _,part in ipairs(config.auto_additional) do
			checkparts('P'..tostring(part))
		end
	elseif parentArgs.additional and parentArgs.additional ~= '' then
		for _,v in ipairs(mw.text.split(parentArgs.additional,"%s*,%s*")) do
			v = resolveQID(v)
			if v then
				if v == qid then -- duplicate of qid parameter
					auxCats = auxCats .. needsAttention('R')
				end
				table.insert(qids,v)
			else -- invalid QID specified
				auxCats = auxCats .. needsAttention('A')
			end
		end
	end

	local sections = {}
	local localparams = false
	local numsections = 0
	for _,_ in ipairs(config.sections) do numsections = numsections + 1 end
	for _ = 1,#qids+numsections do table.insert(sections,{}) end
	local qslink = '' -- setup link to add using QuickStatements

	-- check which identifiers to show/suppress in template
	local show = {} -- setup list
	local showall = true
	local function stripP(pid)
		if pid:match("^[Pp]%d+$") then
			pid = mw.ustring.gsub(pid,'[Pp]','') --strip P from property number
		end
		if pid:match("^%d+$") then
			return tonumber(pid)
		end
	end
	local function addshowlist(list)
		if list and list ~= '' then
			for _,v in ipairs(mw.text.split(string.lower(list),"%s*,%s*")) do
				local vprop = stripP(v)
				if vprop then -- e.g. show=P214 to show one particular property
					show[vprop] = true
				else -- e.g. show=arts to use whitelist
					if config.whitelists[v] then
						for _,w in ipairs(config.whitelists[v].properties) do
							show[w] = true
						end
					end
				end
			end
			showall = false
		end
	end
	addshowlist(frame.args.show) -- check show= parameter on wrapper template
	addshowlist(parentArgs.show or parentArgs.country) -- check show parameter on article template
	if parentArgs.suppress then
		local suppresslist = mw.text.split(parentArgs.suppress,"%s*,%s*") -- split parameter by comma
		for _,v in ipairs(suppresslist) do
			v = stripP(string.upper(v))
			if v then
				show[v] = false
				auxCats = auxCats .. '[[' .. config.i18n.category .. ':' .. config.i18n.suppressedcat .. ']]'
			else
				auxCats = auxCats .. needsAttention('P')
			end
		end
	end
	
	local function makeSections(qid,addit)
		local tval = {}
		local function parameter_is_used(property)
			local used = false
			if property then
				if tval[property] then
					if tval[property][1] then
						used = true
					end
				elseif tval[property] == false then -- property has been manually suppressed
					used = true
				end
			end
			return used
		end
		for _, params in ipairs(conf) do
			tval[params.property] = getIdsFromWikidata(qid, 'P' .. params.property) -- setup table for values with property number as key
			local showb = true
			if (show[params.property] == nil) and (show[string.upper(params[1])] == nil ) then
				showb = showall -- if not specified then depends on showall
			elseif (show[params.property] == false) or (show[string.upper(params[1])] == false) then -- if either are false then id will be suppressed
				showb = false
			end
			if not showb then
				tval[params.property] = false -- indicates the identifier is suppressed
			elseif not addit then
				local val = parentArgs[mw.ustring.lower(params[1])] or parentArgs[params[1]]
				if val and val~='' then -- add local parameter to list if not already in
					localparams = true
					local bnew = true
					for _, w in pairs(tval[params.property]) do
						if val == w.id then
							bnew = false
						end
					end
					if bnew then -- add new value to table
						if qid then
							-- 末尾はQ328(英語版ウィキペディア)ではなくQ177837(日本語版ウィキペディア)とする
							qslink = qslink .. '%7C%7C' .. qid .. '%7CP' .. params.property .. '%7C%22' .. mw.uri.encode(val,"PATH") .. '%22%7CS143%7CQ177837'
						end
						table.insert(tval[params.property],{id=val,name=''})
					end
				end
			end
			local suppress = false
			if params.suppressedbyproperty then
				for _,sc in ipairs(params.suppressedbyproperty) do
					if parameter_is_used(sc) then
						suppress = true
					end
				end
			end
			if tval[params.property] ~= false and not suppress then
				local tlinks = {} -- setup table for links
				local nextIdVal = 1
				local row = ''
				for _,val in ipairs(tval[params.property]) do
					local link = _makelink(params,val,nextIdVal,qid)
					row = row .. link
					table.insert(tlinks,link)
					nextIdVal = nextIdVal + 1
				end
				if nextIdVal>=2 then
					row = row .. '\n'
					table.insert(sections[addit or params.section],row)
					rct = true
				end
			end
		end
	end
	local function pencil(qid)
		if not qid then
			return ''
		end
		local args = { pid = 'identifiers' } -- #target the list of identifiers
		args.qid = qid
		return require('Module:EditAtWikidata')._showMessage(args)
	end

	makeSections(qid,false)
	for c = 1,#qids do
		makeSections(qids[c],numsections+c)
	end

	--configure Navbox
	local outString = ''
	if rct or localparams then -- there is at least one link to display
		local Navbox = require('Module:Navbox')
		local sect,lastsect = 0,0
		local navboxArgs = {
			name  = 'Authority control',
			navboxclass = 'authority-control',
			bodyclass = 'hlist',
			state = parentArgs.state or config.i18n.autocollapse,
			navbar = 'off'
		}
		for c=1,numsections+#qids do
			if #sections[c] ~= 0 then -- section is non-empty
				sect = sect + 1
				lastsect = c
				local sectname
				if c <= numsections then -- regular section
					sectname = config.sections[c].name
				else -- section from additional qid
					local qid = qids[c-numsections]
					sectname = wikilink(qid) .. pencil(qid)
				end
				navboxArgs['group' .. c] = sectname
				navboxArgs['list' .. c] = table.concat(sections[c])
			end
		end
		if localparams then
			lastsect = lastsect + 1
			sect = sect + 1
			navboxArgs['group' .. lastsect] = config.i18n.warning
			local warning = frame:expandTemplate{title = config.i18n.errortemplate, args = {config.i18n.localparams}}
			if qslink ~= '' then
				warning = warning .. ' ' .. config.i18n.movetowd .. '<span class="qs autoconfirmed-show">&#32;[[File:Commons to Wikidata QuickStatements.svg|20px|link=https://quickstatements.toolforge.org/#/v1=' .. qslink .. '|' .. config.i18n.addtowd .. ']]</span>'
			elseif not qid then
				if namespace == 0 then
					warning = warning .. ' ' .. config.i18n.connecttowd
				elseif namespace==14 or namespace==2 or namespace==118 then
					warning = warning .. ' ' .. config.i18n.qidcode
				end
			end
			navboxArgs['list' .. lastsect] = warning
		end
		if topic then -- display in expanded form with topic
			navboxArgs.title = config.i18n.aclink .. ' &ndash; ' .. topic .. pencil(qid)
		elseif sect == 1 then -- special display when only one section
			if lastsect <= numsections then
				if config.sections[lastsect].hidelabelwhenalone then -- no special label when only general or other IDs are present
					navboxArgs['group' .. lastsect] = config.i18n.aclink .. pencil(qid)
				else -- other regular section
					navboxArgs['group' .. lastsect] = config.i18n.aclink .. ': ' .. navboxArgs['group' .. lastsect] .. pencil(qid)
				end
			else -- section from additional qid
				navboxArgs['group' .. lastsect] = config.i18n.aclink .. ': ' .. navboxArgs['group' .. lastsect]
			end
		else -- add title to navbox
			navboxArgs.title = config.i18n.aclink .. pencil(qid)
		end
		outString = Navbox._navbox(navboxArgs)
	else -- 典拠管理識別子が1つもない
		if namespace == 0 or testcases then
			auxCats = auxCats .. addCat('典拠管理識別子が1つもない記事')
		end
	end
	
	if parentArgs.state
		and parentArgs.state~=''
		and parentArgs.state~=config.i18n.collapsed
		and parentArgs.state~=config.i18n.expanded
		and parentArgs.state~=config.i18n.autocollapse then --invalid state parameter
		auxCats = auxCats .. needsAttention('S')
	end
	if testcases then
		auxCats = mw.ustring.gsub(auxCats, '(%[%[)(' .. config.i18n.category .. ')', '%1:%2') --for easier checking
	end

	--out
	outString = outString..auxCats
	if namespace ~= 0 then
		-- 日本語版独自の変更あり
		outString = mw.ustring.gsub(outString,'(%[%[)(' .. config.i18n.category .. ':)([^%|%]]+' .. config.i18n.Articles .. ')%|?[^%|%]]*(%]%])','%1:%2%3%4')
	end
	local check = require('Module:Check for unknown parameters')._check
	local sortkey
	if namespace == 0 then
		sortkey = '*' .. title.text
	else
		sortkey = title.fullText
	end
	outString = outString .. check({
		['unknown'] = '[[' .. config.i18n.category .. ':' .. config.i18n.pageswithparams .. '|' .. sortkey .. ']]',
		['preview'] = config.i18n.previewwarning, 'show', 'country', 'suppress', 'additional', 'qid', 'state'
		}, parentArgs)
	return outString
end

p.makelink = function(conf,val,nextid,qid)
	return _makelink(conf,val,nextid,qid)
end

return p