Module:Wikidata Infobox/sandbox
CodeDiscussionEditHistoryLinksLink count Subpages:DocumentationTestsResultsSandboxLive code All modules
This module provides following functions:
main
to implement {{Wikidata Infobox/sandbox}}doc
to generate Template:Wikidata Infobox/doc/properties
How to contribute
[edit]Adding new properties
[edit]- Add the new property to
property_groups
. Properties are displayed in the order they appear in this table, so please look at Template:Wikidata Infobox/doc/properties to find a suitable place for the new property. - If the property needs custom formatting, add it to
property_logic
Testing your changes
[edit]Apart from saving your edits to the sandbox module, there are two ways to test your changes. You can preview the sandbox module on any Commons page by adding following lines to meta:Special:MyPage/global.js:
// [[w:User:Jackmcbarn/advancedtemplatesandbox.js]]
mw.loader.load( 'https://en.wikipedia.org/w/index.php?title=User:Jackmcbarn/advancedtemplatesandbox.js&action=raw&ctype=text/javascript' );
Then you can edit the sandbox module. Under "Preview page with this template", enter a page name. If the page uses {{Wikidata Infobox}}, you need to change the template name to "Module:Wikidata Infobox". Click "Show preview".
Another option is to use the Lua debug console: enter e.g. =p.debug'Q42'
and paste the generated wikitext somewhere to preview it. Note that custom CSS is not applied and the images may not be switchable if you use this method.
Dependencies
[edit]This module depends on:
- Module:WikidataIB/sandbox
- Module:Taxontree/sandbox
- Template:VNNoDisplay for vernacular names of taxons
- Module:Coordinates or Template:Coord
- subpages of Translations:Template:Wikidata Infobox/i18n for internationalization
- Template:Unbulleted list
See also
[edit]- d:Module:Databox – much simpler Wikidata infobox
- pages with Wikidata Infobox and script errors (cached)
Code
local p = {}
require('strict')
local WikidataIB = require( 'Module:WikidataIB' )
local i18n = require( 'Module:Wikidata Infobox/i18n' ).i18n
local getBestStatements = mw.wikibase.getBestStatements
local frame = mw.getCurrentFrame()
local config = {
-- toggle/customize infobox features:mw
defaultsort = true,
interwiki = true,
autocat = true,
trackingcats = true,
uploadlink = true,
sitelinks = true,
authoritycontrol = true,
helperlinks = true,
coordtemplate = 1, -- 0 = none, 1 = Geohack, 2 = Coord
mapwidth = 250,
mapheight = 250,
imagesize = '230x500px',
-- parameters for WikidataIB:
spf = '', -- suppressfields
fwd = 'ALL', -- fetchwikidata
osd = 'no', -- onlysourced
noicon = 'yes', -- pencil icon
wdlinks = 'id', -- add links to Wikidata if no label found
collapse = 10, -- collapse list of values if too many values
maxvals = 30, -- stop fetching Wikidata after this number of values
}
-- variables set by main():
local ITEM -- mw.wikibase.entity table
local QID -- qid of ITEM, e.g. 'Q42'
local CLAIMS -- ITEM.claims
local ISTAXON -- whether ITEM is a biological taxon
local INSTANCEOF = {} -- Hash set of ITEM's best "instance of" values
local MYLANG -- user's languge code
local LANG -- language object of user's language
local FALLBACKLANGS -- list containing MYLANG and its fallback languages
-- Can't have more than one {{#coordinates:primary}}, so keep track of count
local primary_coordinates = 0
--- Returns label of given Wikidata entity in user's language.
--- If label doesn't exist, returns the id as link to Wikidata.
--- @param id string
--- @param nolink? boolean: Whether to return link to Wikidata if no label found
local function getLabel( id, nolink )
local label = mw.wikibase.getLabel( id )
if label then
return mw.text.nowiki( label ) -- nowiki to prevent wikitext injection
elseif nolink then
return id
else
return '[[d:' .. id .. ']]'
end
end
--- Query Wikidata entity for the first best value of property _pid_.
--- Returns nil if first best value is novalue or somevalue.
--- Returns nil if entityOrId is neither table nor string.
--- @param entityOrId table|string: getEntity() or qid.
--- @param pid string
--- @return unknown|nil
local function getSingleValue( entityOrId, pid )
local claim
if type( entityOrId ) == 'table' then
claim = entityOrId:getBestStatements( pid )[1]
elseif type( entityOrId ) == 'string' then
claim = getBestStatements( entityOrId, pid )[1]
end
return claim and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value
end
--- Iterator function over a list of Wikidata claims/statements
--- @param t table as returned by wikibase.getBestStatements
local function iclaims( t )
local i = 1
return function()
while i <= #t do
local dv = t[i].mainsnak.datavalue
local v = dv and dv.value
i = i + 1
if v then return v end
end
end
end
--- Returns Commons sitelink (full page title), preferably to category
--- @param qid string
--- @return string|nil
local function getCommonsLink( qid )
local sitelink = mw.wikibase.getSitelink( qid, 'commonswiki' )
if sitelink and sitelink:sub(1,9) == 'Category:' then
return sitelink -- sitelink to category page
end
local maincat = getSingleValue( qid, 'P910' ) -- topic's main category
if maincat and maincat.id then
local sl = mw.wikibase.getSitelink( maincat.id, 'commonswiki' )
if sl then return sl end
end
local listcat = getSingleValue( qid, 'P1754' ) -- category related to list
if listcat and listcat.id then
local sl = mw.wikibase.getSitelink( listcat.id, 'commonswiki' )
if sl then return sl end
end
local P373 = getSingleValue( qid, 'P373' ) -- Commons category
if P373 then
return 'Category:' .. P373
end
return sitelink -- sitelink to gallery page
end
local getSitelink = (mw.wikibase.getGlobalSiteId() == 'commonswiki') and getCommonsLink or mw.wikibase.getSitelink
--- Returns sitelink to Commons as wikilink or the label of the given Q-item
--- @param qid string
local function getLinkOrLabel( qid )
local sitelink = getSitelink( qid )
if sitelink then
return "[[:" .. sitelink .. "|" .. getLabel( qid, true ) .. "]]"
else
return getLabel( qid )
end
end
--- Renders snak as rich wikitext. Returns nil if snak is nil or false.
--- @param snak table: claim.mainsnak or claim.qualifiers[pid]
local function renderSnak( snak )
if not snak then return end
local snaktype = snak.snaktype
if snaktype == 'value' then
local datatype = snak.datatype
local value = snak.datavalue.value
if datatype == 'wikibase-item' then
return getLinkOrLabel( value.id )
else
return mw.wikibase.formatValue( snak )
end
elseif snaktype == 'somevalue' then
local label = mw.message.new('Wikibase-snakview-variations-somevalue-label'):inLanguage(MYLANG):plain()
return '<i style="color:#54595d">'..label..'</i>'
end
end
--- Returns claim whose "language of work or name" (P407) qualifier matches
--- langcode, or nil if none matches.
--- @param claims table as returned by getBestStatements()
--- @param langcode string, e.g. "en"
--- @return unknown|nil
local function getClaimByLang( claims, langcode )
for _, claim in ipairs( claims or {} ) do
for _, qual in ipairs( claim.qualifiers and claim.qualifiers['P407'] or {} ) do
if qual.datavalue and qual.datavalue.value and getSingleValue( qual.datavalue.value.id, 'P424' ) == langcode then
return claim
end
end
end
end
--- If the given snaks of datatype monolingualtext contain a string in one of
--- the user's fallback languages, the string is returned; otherwise a random
--- string is retuned. The second return value indicates whether finding a
--- string in one of the user's fallback languages was successful.
--- @param snaks table, e.g. claims.qualifiers['P2096']
--- @return string?, boolean? success
local function extractMonolingualText( snaks )
if not snaks or snaks == {} then return end
-- collect strings into hash table with langcodes as keys
local monotext = {}
for _, snak in ipairs( snaks ) do
local ms = snak.mainsnak or snak
local v = ms and ms.datavalue and ms.datavalue.value
if v then
monotext[v.language] = v.text
end
end
for _, lang in ipairs( FALLBACKLANGS ) do
if monotext[lang] then return monotext[lang], true end
end
-- return random string
local _, v = next( monotext )
return v, false
end
--- Parses a string in WikiHiero syntax
local function expandhiero( hiero )
return frame:callParserFunction{ name = '#tag:hiero', args = {hiero} }
end
--- Returns a string containing two table rows
local function format2rowline( header, content )
return '<tr><th class="wikidatainfobox-lcell" style="text-align:left" colspan="2">'..header..'</th></tr><tr><td style="vertical-align:top" colspan="2">'..content..'</td></tr>'
end
--- Returns a string containing a single table row
local function format1rowline( trqid, header, content )
return '<tr id="'..trqid..'"><th class="wikidatainfobox-lcell">'..header..'</th><td style="vertical-align:top">'..content..'</td></tr>'
end
--- Returns a string containing the HTML markup for an infobox row.
--- Returns nil if content is empty.
--- @param eid string: ID of Wikidata entity whose label shall be used as heading
--- @param content string|nil
--- @param mobile? boolean: Set to true to show on devices with narrow screens
local function formatLine( eid, content, mobile )
if not content or content == '' then return end
local row = mw.html.create( 'tr' )
if not mobile then
row:addClass( 'wdinfo_nomobile' ) -- [[Template:Wikidata_Infobox/styles.css]]
end
row:tag( 'th' )
:addClass( 'wikidatainfobox-lcell' )
:node( LANG:ucfirst( getLabel(eid) ) )
row:tag( 'td' )
:node( content )
return tostring( row )
end
--- Returns unbulleted HTML list if given a sequence table.
--- @param list string[]
local function ubl( list )
if #list == 0 then return end
local out = table.concat( list, '</li><li>' )
return '<div class="plainlist"><ul><li>'..out..'</li></ul></div>'
end
--- Given a language code, returns its databaseId (as used by Wikidata sitelinks).
--- All databaseIds that a wiki knows are stored in its [[mw:Manual:sites table]].
--- @param langcode string
local function databaseId( langcode )
local exceptions = {
['be-tarask'] = 'be_x_old', -- Belarusian (Taraškievica orthography)
['bho'] = 'bh', -- Bhojpuri
['cbk-zam'] = 'cbk_zam', -- Chavacano de Zamboanga
['gsw'] = 'als', -- Alemannic
['ike'] = 'iu', -- Inuktitut
['lzh'] = 'zh_classical', -- Classical Chinese
['map-bms'] = 'map_bms', -- Basa Banyumasan
['nan'] = 'zh_min_nan', -- Min Nan Chinese
['nb'] = 'no', -- Norwegian Bokmål
['nds-nl'] = 'nds_nl', -- Low Saxon
['mo'] = 'ro', -- Moldaawisk
['roa-tara'] = 'roa_tara', -- Tarantino
['rup'] = 'roa_rup', -- Aromanian
['sgs'] = 'bat_smg', -- Samogitian
['vro'] = 'fiu_vro', -- Võro
['yue'] = 'zh_yue', -- Cantonese
-- I did my best to make this list as comprehensive as possible.
-- Useful pages for finding exceptions:
-- [[mw:Manual:$wgExtraLanguageCodes]]
-- [[meta:Special_language codes]]
-- [[meta:List_of_Wikipedias#Nonstandard_language_codes]]
-- [[meta:Template:N en/list]]
-- [[meta:Template:Wikilangcode]]
}
local exception = exceptions[langcode]
if exception then return exception end
return langcode:gsub("-.*", "") -- delete everything after hyphen
end
-- Set of pids whose values should always be linked even if they are collapsed.
-- Adding new pids may slow down the infobox on certain pages.
local should_be_linked = {
-- pid property label rationale
P2789=true, -- connects with [[Template_talk:Wikidata_Infobox/Archive_5#P2789_-_connects_with]]
P527=true, -- has part(s) [[Template_talk:Wikidata_Infobox/Archive_5#P2789_-_connects_with]]
P1382=true, -- partially coincident with [[Template_talk:Wikidata_Infobox/Archive_5#P1382_vs._P527]]
P40=true, -- child [[Template_talk:Wikidata_Infobox#No_links_if_information_is_folded?]]
P3373=true, -- sibling [[Template_talk:Wikidata_Infobox#No_links_if_information_is_folded?]]
}
--- Wrapper around WikidataIB. Returns nil if the item has no _pid_ statement.
--- @param pid string: Wikidata property id
--- @param args? table: arguments for WikidataIB
--- @return string|nil
local function getValue( pid, args )
args = args or {}
local collapse = args.collapse or config.collapse
if collapse == 0 and args.linked == nil then
error("getValue: Must give linked='no' or linked='yes' if collapse=0", 2)
end
-- linking many values harms performance if the value items are big and the sitelink needs to be taken from P910, P1754 or P373
local linked = args.linked or should_be_linked[pid]
or #getBestStatements(args.qid or QID, pid) <= collapse
return WikidataIB._getValue{
pid,
name = pid,
qid = args.qid or QID,
linked = linked,
wdlinks = args.wdlinks or config.wdlinks,
prefix = args.prefix,
postfix = args.postfix,
linkprefix = ':', -- suppress categorization
qlinkprefix = ':', -- suppress categorization
sorted = args.sorted,
qual = args.qual or 'MOST',
qualsonly = args.qualsonly,
maxvals = args.maxvals or config.maxvals,
postmaxvals = '…',
collapse = collapse,
spf = args.spf or config.spf,
fwd = args.fwd or config.fwd,
osd = args.osd or config.osd,
rank = 'best',
noicon = args.noicon or config.noicon,
list = args.list or 'Unbulleted list',
sep = args.sep,
unitabbr = args.unitabbr,
df = args.df, -- date format
plaindate = args.plaindate,
lang = args.lang,
gendered = args.gendered,
}
end
--- Used if no custom logic was specified for pid.
local function defaultFunc( pid, args )
return formatLine( pid, getValue(pid, args) )
end
local function defaultFuncMobile( pid, args )
return formatLine( pid, getValue(pid, args), true )
end
local function defaultFuncMobileGendered( pid )
return formatLine( pid, getValue(pid, {gendered=true}), true )
end
local function getAudio( pid )
local audiofile = getSingleValue( ITEM, pid )
return audiofile and formatLine( pid, '[[File:' .. audiofile .. '|100px]]' )
end
local function getAudioByLang( pid )
local claims = ITEM:getBestStatements( pid )
local claim = claims[1]
for i = 1, #FALLBACKLANGS do
local c = getClaimByLang( claims, FALLBACKLANGS[i] )
if c then
claim = c
break
end
end
local audiofile = claim and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value
return audiofile and formatLine( pid, '[[File:' .. audiofile .. '|100px]]' )
end
-- Example at [[Category:Thutmosis III]]
local function getHieroglyphs()
local rows = {}
for _, v in ipairs( ITEM:getBestStatements('P7383') ) do -- name in hiero markup
local idv = v.mainsnak.datavalue.value
if v.qualifiers and v.qualifiers['P3831'] then
for _, w in ipairs( v.qualifiers['P3831'] ) do
if w.datavalue then
local label = getLabel( w.datavalue.value.id )
rows[#rows+1] = format2rowline( label, expandhiero(idv) )
end
end
else
rows[#rows+1] = format2rowline( getLabel('Q82799', true), expandhiero(idv) )
end
end
return table.concat( rows )
end
--- WikidataIB arguments for birth and death related properties
local birthdeath_args = { list = '', quals = table.concat({
'P4241', -- refine date
'P805', -- statement is subject of
'P1932', -- object stated as
'P1810', -- subject named as
'P5102', -- nature of statement
'P1480', -- sourcing circumstances
'P459', -- determination method
'P1013', -- criterion used
'P1441', -- present in work
'P10663', -- applies to work
}, ',') }
local function getBirth( pid )
local out = {}
out[#out+1] = getValue( pid, birthdeath_args ) -- date
out[#out+1] = CLAIMS['P19'] and getValue( 'P19', birthdeath_args ) -- place
out[#out+1] = extractMonolingualText( ITEM:getBestStatements('P1477') ) -- name
return formatLine( pid, table.concat(out, '<br>') )
end
local function getDeath( pid )
local out = {}
out[#out+1] = getValue( pid, birthdeath_args ) -- date
out[#out+1] = CLAIMS['P20'] and getValue( 'P20', birthdeath_args ) -- place
return formatLine( pid, table.concat(out, '<br>') )
end
local function getWebsite( pid )
for _, claim in ipairs( ITEM:getBestStatements(pid) ) do
local quals = claim.qualifiers
local url = claim.mainsnak.datavalue and claim.mainsnak.datavalue.value
if url and not (quals and quals['P582']) then -- no "end time" qualifier
return '<tr><td colspan=2 style="text-align:center">['..url..' '..getLabel(pid)..']</td></tr>'
end
end
end
local function getSignature( pid )
local img = getSingleValue( ITEM, pid )
if img then
local alt = LANG:ucfirst( getLabel(pid, true) )
return '<tr class="wdinfo_nomobile"><td colspan=2 style="text-align:center"><span class="wpImageAnnotatorControl wpImageAnnotatorCaptionOff">[[File:'..img..'|150px|alt='..alt..']]</span></td></tr>'
-- equivalent to {{ImageNoteControl | caption=off | type=inline}}
end
end
--- If ITEM has a pid statement, this behaves exactly like defaultFunc. Otherwise
--- figures out the region that ITEM is in and queries the region item for pid.
--- It finds the region by first checking if ITEM has a regionPid value.
--- Otherwise it takes the region from the P971 (category combines topics)
--- statement of ITEM's main category.
--- Examples at Cat:Health_in_Gabon, Cat:Economy_of_Germany, Q7246071
--- @param pid string, e.g. "P2250" for life expectancy
--- @param regionPid string: usually "P17" (country) or "P276" (location)
--- @param collapse number: argument for WikidataIB
local function getByRegion( pid, regionPid, collapse )
local region = getSingleValue( ITEM, regionPid )
if CLAIMS[pid] then
region = QID
elseif region then
region = region.id
else
local maincat = getSingleValue( ITEM, 'P910' ) -- topic's main category
if maincat then
for topic in iclaims( getBestStatements(maincat.id, 'P971') ) do
local id = topic.id
if id ~= 'Q12147' and id ~= 'Q8434' and id ~= 'Q159810' then
-- assume id is QID of a region if it's not the QID for "health", "education", or "economy"
region = id
end
end
end
end
return region and defaultFunc( pid, {
qid = region,
collapse = collapse,
})
end
local function getByCountry( pid )
return getByRegion( pid, 'P17', 10 )
end
local function getByLocation( pid )
return getByRegion( pid, 'P276', 10 )
end
local function getByLocationCollapse4( pid )
return getByRegion( pid, 'P276', 4 )
end
local function getPrimeFactors()
local out = {}
for _, claim in ipairs( ITEM:getBestStatements('P5236') ) do
local quals = claim.qualifiers and claim.qualifiers['P1114']
local quantity = quals and quals[1].datavalue.value.amount
if quantity then
quantity = quantity:sub(2) -- strip plus sign
out[#out+1] = renderSnak(claim.mainsnak) .. '<sup>'..quantity..'</sup>'
else
out[#out+1] = renderSnak(claim.mainsnak)
end
end
return formatLine( 'Q4846249', table.concat(out, ' × ') )
end
local function getUnicodeChars( pid )
local rows = {}
for _, v in ipairs( ITEM:getBestStatements(pid) ) do
if v.mainsnak.datavalue then
local idv = v.mainsnak.datavalue.value
for _, w in ipairs( v.qualifiers and v.qualifiers['P3831'] or {} ) do
if w.datavalue then
local qualid = w.datavalue.value.id
rows[#rows+1] = format1rowline( qualid, getLabel(qualid), idv )
end
end
end
end
return table.concat( rows )
end
local function getCodes( pid )
local rows = {}
for _, v in ipairs( ITEM:getBestStatements(pid) ) do
if v.mainsnak.datavalue then
local idv = v.mainsnak.datavalue.value
for _, w in ipairs( v.qualifiers and v.qualifiers['P3294'] or {} ) do
if w.datavalue then
local qualid = w.datavalue.value.id
if qualid == "Q68101340" then
idv = expandhiero( idv )
end
rows[#rows+1] = format1rowline( qualid, getLinkOrLabel(qualid), idv )
end
end
end
end
return table.concat( rows )
end
local function getCodeImages( pid )
local rows = {}
for _, v in ipairs( ITEM:getBestStatements(pid) ) do
local idv = v.mainsnak.datavalue.value
for _, w in ipairs( v.qualifiers and v.qualifiers['P3294'] or {} ) do
if w.datavalue then
local qualid = w.datavalue.value.id
local img = '[[File:' .. idv .. '|none|35px]]'
rows[#rows+1] = format1rowline( qualid, getLabel(qualid), img )
end
end
end
return table.concat( rows )
end
local function getLocation()
local function fallback()
local set = {} -- locations as keys
local out = {} -- locations as values
for _, pid in ipairs{ 'P706', 'P276', 'P131', 'P17' } do
for _, claim in ipairs( ITEM:getBestStatements(pid) ) do
local location
if pid == 'P17' then -- don't link to countries
local dv = claim.mainsnak.datavalue
location = dv and getLabel( dv.value.id )
else
location = renderSnak( claim.mainsnak )
end
if location and not set[location] then
local n = #out + 1
set[location] = true -- we don't want duplicate values
out[n] = location -- we want to preserve the order
if n > config.maxvals then
out[n] = '…' -- postmaxvals
return formatLine( 'P276', ubl(out) )
end
end
end
end
return formatLine( 'P276', ubl(out) )
end
local P131,P276,P706 = CLAIMS['P131'] or {}, CLAIMS['P276'] or {}, CLAIMS['P706'] or {}
if (#P131 < 2) and (#P276 < 2) and (#P706 < 2) then
return formatLine( 'P276', WikidataIB.location{ args={QID} } ) or fallback()
else
return fallback()
end
end
local function getAuthors()
if CLAIMS['P50'] or CLAIMS['P2093'] then
local args = { list='', sep='</li><li>', collapse=0, maxvals=10, linked='yes', qual='P1545,P518,P5102,P3831' }
local authors = getValue( 'P50', args ) or ''
local namestrings = getValue( 'P2093', args )
return formatLine( 'P50', ubl{authors, namestrings} )
end
end
local function getDifferentFrom()
local out = {}
local i = 0
for different in iclaims( ITEM:getBestStatements('P1889') ) do
i = i + 1
if i > config.maxvals then break end
local href = getSitelink( different.id ) or ( 'd:'..different.id )
local label = getLabel( different.id, true )
local class = getSingleValue( different.id, 'P31' )
local isdab = class and class.id == 'Q4167410'
local icon = isdab and ' [[File:Disambig.svg|18px|alt='..mw.wikibase.getLabel('Q4167410')..']]'
local desc = mw.wikibase.getDescription( different.id )
if desc then
label = '<span title="'..mw.text.nowiki(desc)..'">'..label..'</span>'
end
out[#out+1] = string.format( '[[:%s|%s]]%s', href, label, icon or '' )
end
return formatLine( 'P1889', ubl(out) )
end
--- Returns common taxon name using [[Module:Wikidata4Bio]]
local function getVernacularName()
if ISTAXON then
local vn = frame:expandTemplate{ title = 'VNNoDisplay', args = {
useWikidata = QID
}}
if vn:sub(3,10) ~= 'Category' and not vn:match('class="error') then
-- we found at least one common name and there are no errors
local label = LANG:ucfirst( getLabel('Q502895') )
return '<tr><td colspan=2><table style="width:100%"><tr><th style="background: #cfe3ff>'..label..'</th></tr><tr><td><div style="overflow-wrap: break-word" class="mw-collapsible mw-collapsed wikidatainfoboxVN" id="wdinfoboxVN">'..vn..'</div></td></tr></table></td></tr>'
end
end
end
local function getTaxontree()
local content = require('Module:Taxontree').show{ args = {
qid = QID,
authorcite = 'y',
first = 'y',
}}
local label = LANG:ucfirst( getLabel('Q8269924') )
return '<tr><td colspan=2><table style="width:100%" id="wdinfo_taxon" class="mw-collapsible"><tr><th style="background: #cfe3ff" colspan=2>'..label..'</th></tr>'..content..'</table></td></tr>'
end
local function getOriginalCombination()
local ocomb = getSingleValue( ITEM, 'P1403' )
ocomb = ocomb and ocomb.id
local taxoname = ocomb and getSingleValue( ocomb, 'P225' ) or ''
local citation = ocomb and getSingleValue( ocomb, 'P6507' ) or ''
if taxoname then
return formatLine( 'P1403', '<i>'..taxoname..'</i>' .. ' ' .. citation )
end
end
--- Creates a taxon author citation from P405 and P574 qualifiers if
--- P6507 (taxon author citation as string) not present since otherwise
--- Taxontree already shows the citation.
local function getTaxonAuthor()
local claims = CLAIMS['P225'] -- P225 = taxon name
if #claims > 1 then
return defaultFunc( 'P225' ) -- Example at [[Category:Acacia stricta]]
elseif #claims == 1 then
if CLAIMS['P6507'] then -- P6507 = taxon author citation (string)
return -- Taxontree already shows citation, see [[Ophiogymna]]
end
local quals = claims[1].qualifiers
local author = renderSnak( quals and quals['P405'] and quals['P405'][1] )
local year = renderSnak( quals and quals['P574'] and quals['P574'][1] )
if author and year then
return formatLine( 'P405', author .. ', ' .. year )
elseif year then
return formatLine( 'P574', year ) -- [[Cat:Porphyrophora polonica]]
end
end
end
--- Given an area, returns a map zoom level to use with mw:Extension:Kartographer.
--- Fallback output is 15.
local function autoMapZoom( area )
if not area then return 15 end
if area.unit == 'http://www.wikidata.org/entity/Q35852' then -- hectare
area = area.amount / 100 -- convert to km²
elseif area.unit == 'http://www.wikidata.org/entity/Q25343' then -- m²
area = area.amount / 1e6 -- convert to km²
elseif area.unit == 'http://www.wikidata.org/entity/Q81292' then -- acre
area = area.amount * 0.004 -- convert to km²
else
area = tonumber( area.amount ) -- assume the unit is km²
end
local LUT = { 5000000, 1000000, 100000, 50000, 10000, 2000, 150, 50, 19, 14, 5, 1, 0.5 }
for zoom, scale in ipairs( LUT ) do
if area > scale then
return zoom + 1
end
end
return 15
end
local function getCoordinates( pid )
local coords = getSingleValue( ITEM, pid )
if coords then
local out
local long = coords.longitude
local lat = coords.latitude
local globeId = coords.globe:match( "Q%d+" )
if globeId == 'Q2' then -- coords are on Earth
local externaldata = { -- [[mw:Help:Extension:Kartographer]]
type = "ExternalData",
service = "geoshape",
ids = QID,
properties = {
['fill'] = "#999999",
['stroke'] = "#636363",
['stroke-width'] = 2
}
}
-- detect roads, mountain passes, rivers, borders etc.
if CLAIMS['P2043'] or CLAIMS['P16'] -- length, transport network
or CLAIMS['P974'] or CLAIMS['P4552'] -- tributary, mountain range
or CLAIMS['P177'] or CLAIMS['P1064'] -- crosses, track gauge
or CLAIMS['P15'] or CLAIMS['P14'] -- route map, traffic sign
or CLAIMS['P930'] or CLAIMS['P3858'] then -- electrification, route diagram
externaldata.service = 'geoline'
externaldata.properties['stroke'] = "#ff0000"
end
local geojson = {
externaldata,
{ type = "Feature",
geometry = { type="Point", coordinates = {long, lat} },
properties = {
['marker-size'] = "medium",
['marker-color'] = "006699"
},
},
}
local zoom
if CLAIMS['P402'] then -- OpenStreetMap relation ID
-- Let Kartographer figure out zoom level based on OSM geoshape.
-- Kartographer uses [[mw:Wikimedia_Maps/API#OSM_Geoshapes_and_lines]]
-- instead of P402 to find the OSM relation but there is no Lua
-- interface for that. You can help adding P402 statements using
-- https://mix-n-match.toolforge.org/#/catalog/688
else
local area = getSingleValue( ITEM, 'P2046' )
zoom = autoMapZoom( area )
end
out = frame:extensionTag( 'mapframe', mw.text.jsonEncode(geojson), {
frameless = 1,
lang = MYLANG,
width = config.mapwidth,
height = config.mapheight,
zoom = zoom,
align = 'center',
})
if config.trackingcats then
out = out ..'[[Category:Uses of Wikidata Infobox with maps]]'
end
if config.coordtemplate == 1 then
if primary_coordinates == 0 then
out = out .. frame:callParserFunction('#coordinates:primary', lat, long)
primary_coordinates = 1
end
out = out .. '<small>'..require('Module:Coordinates')._GeoHack_link{ lat=lat, lon=long, lang=MYLANG }..'</small>'
elseif config.coordtemplate == 2 then
local args = {
display = 'inline,title',
format = 'dms',
nosave = 1,
qid = QID
}
out = out .. '<small>'..frame:expandTemplate{ title = 'Coord', args = args }..'</small>'
end
else -- coords not on Earth
local globe = mw.wikibase.getLabelByLang( globeId, 'en' ) or mw.wikibase.getLabelByLang( globeId, 'mul' )
out = require('Module:Coordinates')._GeoHack_link{ lat=lat, lon=long, globe=globe, lang=MYLANG }
end
return '<tr class="wdinfo_nomobile"><td colspan=2 style="text-align:center">'..out..'</td></tr>'
elseif config.trackingcats and (CLAIMS['P706'] or CLAIMS['P131']) then
return '[[Category:Uses of Wikidata Infobox with no coordinate]]'
end
end
--- Show map using [[mw:Help:Map Data]] if ITEM has no coordinates
local function getCommonsMapData()
if CLAIMS['P625'] then return end
local commonsdata = getSingleValue( QID, 'P3896' )
if not commonsdata then return end
local geojson = {{
type = "ExternalData",
service = 'page',
title = commonsdata:sub(6), -- strip "Data:" prefix
}}
local out = frame:extensionTag( 'mapframe', mw.text.jsonEncode(geojson), {
frameless = 1,
lang = MYLANG,
width = config.mapwidth,
height = config.mapheight,
align = 'center',
})
if config.trackingcats then
out = out ..'[[Category:Uses of Wikidata Infobox with maps]]'
end
return '<tr class="wdinfo_nomobile"><td colspan=2 style="text-align:center">'..out..'</td></tr>'
end
local function getCelestialCoordinates()
local ra = getSingleValue( ITEM, 'P6257' ) -- right ascension
local de = getSingleValue( ITEM, 'P6258' ) -- declination
if ra and de then
local url = 'http://www.wikisky.org/?ra='..(ra.amount / 15)..'&de='..de.amount..'&de=&show_grid=1&show_constellation_lines=1&show_constellation_boundaries=1&show_const_names=1&show_galaxies=1&img_source=DSS2&zoom=9 '
local ra_unit = getLabel( ra.unit:match('Q%d+') )
local de_unit = getLabel( de.unit:match('Q%d+') )
local ra_fmt = LANG:formatNum( tonumber(ra.amount) )
local de_fmt = LANG:formatNum( tonumber(de.amount) )
local text = LANG:ucfirst( getLabel('P6257') )..' '..ra_fmt..' '..ra_unit..
'<br>'..LANG:ucfirst( getLabel('P6258') )..' '..de_fmt..' '..de_unit
return '<tr class="wdinfo_nomobile"><td colspan=2 style="text-align:center">['..url..text..']</td></tr>'
end
end
local autocats_by_id = {
P3596 = 'Archaeological monuments in Denmark with known IDs',
P1371 = 'ASI monuments with known IDs',
P2917 = 'Buildings of Madrid with COAM Register number',
P3170 = 'Cultural heritage monuments in Armenia with known IDs',
P2951 = 'Cultural heritage monuments in Austria with known IDs',
P4244 = 'Cultural heritage monuments in Bavaria with known IDs',
P2424 = 'Cultural heritage monuments in Berlin with known ID',
P2948 = 'Cultural heritage monuments in Estonia (with known IDs)',
P4009 = 'Cultural heritage monuments in Finland with known IDs',
P380 = 'Cultural heritage monuments in France with known IDs',
P4166 = 'Cultural heritage monuments in Georgia with known IDs',
P1769 = 'Cultural heritage monuments in Hesse with known ID',
P1369 = 'Cultural heritage monuments in Iran with known IDs',
P1799 = 'Cultural heritage monuments in Malta with known IDs',
P758 = 'Cultural heritage monuments in Norway with known IDs',
P1770 = 'Cultural heritage monuments in Romania with known IDs',
P1708 = 'Cultural heritage monuments in Saxony with known ID',
P808 = 'Cultural heritage monuments in Spain by ID',
P762 = 'Cultural monuments in the Czech Republic with known IDs',
P477 = 'Heritage properties in Canada with known IDs',
P5094 = 'HPIP with known IDs',
P1702 = 'IGESPAR with known IDs',
P5500 = 'IPHAN with known IDs',
P2783 = 'Listed buildings in Denmark with known IDs',
P1216 = 'Listed buildings in England with known IDs',
P1460 = 'Listed buildings in Northern Ireland with known IDs',
P709 = 'Listed buildings in Scotland with known IDs',
P1459 = 'Listed buildings in Wales with known IDs',
P649 = 'National Register of Historic Places with known IDs',
P4120 = 'Ontario Heritage Trust sites with known IDs',
P2961 = 'Periodicals in the Biblioteca Virtual de Prensa Histórica',
P7135 = 'Rijksmonumentcomplexen with known IDs',
P359 = 'Rijksmonumenten with known IDs',
P1700 = 'SIPA with known IDs',
P3759 = 'Uses of Wikidata Infobox providing SAHRA ids',
P809 = 'Uses of Wikidata Infobox providing WDPA ids',
}
--- qualifiers for "headquarters location" (P159)
local hq_quals = table.concat({
'P6375', -- street address
'P669', -- located on street
'P670', -- street number
'P4856', -- conscription number
'P281', -- postal code
'P580', -- start time
'P582', -- end time
'P585', -- point in time
'P1264', -- valid in period
'P3831', -- object has role
'P1810', -- subject named as
'P5102', -- nature of statement
}, ',' )
--- associates pids with a table of arguments for WikidataIB or with a function
--- that will be called with pid as the only argument
local property_logic = {
P51 = getAudio, -- audio
P989 = getAudioByLang, -- spoken text audio
P443 = getAudioByLang, -- pronunciation audio
P990 = getAudioByLang, -- recording of subject's voice
P7383 = getHieroglyphs, -- name in hiero markup
P569 = getBirth, -- date of birth
P570 = getDeath, -- date of death
P69 = { qual='P580,P582,P585,P512,P812' }, -- educated at
P185 = { collapse=4, maxvals=20 }, -- doctoral student
P106 = defaultFuncMobileGendered, -- occupation
P39 = { qual='P642,P580,P582,P585', collapse=6 }, -- position held
P2522 = { collapse=4 }, -- victory
P26 = { qual='DATES' }, -- spouse, TODO: sort by date qualifier (also P793)
P451 = { qual='DATES' }, -- partner
P166 = { qual='P585' }, -- award received
P856 = getWebsite, -- official website
P109 = getSignature, -- signature
P31 = defaultFuncMobile, -- instance of
P2250 = getByCountry, -- life expectancy
P4841 = getByCountry, -- total fertility rate
P5236 = getPrimeFactors, -- prime factor
P487 = getUnicodeChars, -- Unicode character
P3295 = getCodes, -- code
P7415 = getCodeImages, -- code (image)
P3270 = getByLocation, -- compulsory education (minimum age)
P3271 = getByLocation, -- compulsory education (maximum age)
P6897 = getByLocationCollapse4, -- literacy rate
P2573 = getByLocationCollapse4, -- number of out-of-school children
P971 = { osd='no' }, -- category combines topics
P180 = { list='prose', qual='' }, -- depicts
P276 = getLocation, -- location
P50 = getAuthors, -- author
P2789 = { qual='' }, -- connects with
P85 = { qual='DATES' }, -- anthem
P953 = { qual='P407', prefix="[", postfix="]" }, -- full work at
P127 = { qual='DATES' }, -- owned by
P159 = { qual=hq_quals }, -- headquarters location
P466 = { collapse=5 }, -- occupant
P126 = { collapse=5, maxvals=20 }, -- maintained by
P348 = { qual='P548,P577,P805' }, -- software version identifier
P286 = { collapse=3 }, -- head couch
P527 = { collapse=5, maxvals=20 }, -- has part
P1382 = { collapse=5, maxvals=20 }, -- partially coincident with
P1990 = { collapse=5 }, -- species kept
P1923 = { collapse=5, maxvals=10 }, -- participating team
P1346 = { collapse=5, maxvals=20 }, -- winner
P112 = { maxvals=20 }, -- founded by
P577 = {
linked = 'no', -- make film categories load much quicker
rank = 'preferred normal', -- See [[d:Property_talk:P577#Constraint_about_unique_best_value]]
},
P1082 = { qual='P585' }, -- population (qual = point in time)
P200 = { collapse=4, maxvals=20 }, -- lake inflows
P205 = { collapse=5, maxvals=20 }, -- basin country
P974 = { collapse=5, maxvals=20 }, -- tributary
P726 = { collapse=5 }, -- candidate
P1889 = getDifferentFrom, -- different from
P460 = { collapse=20, list='' }, -- same as (lots of values for given names)
P1843 = getVernacularName, -- taxon common name
P171 = getTaxontree, -- parent taxons
P1403 = getOriginalCombination, -- original combination
P225 = getTaxonAuthor, -- taxon name (and qualifiers)
P2078 = getWebsite, -- user manual URL
P625 = getCoordinates, -- coordinate location
P3896 = getCommonsMapData, -- geoshape
P6257 = getCelestialCoordinates, -- right ascension
}
--[==[----------------------------------------------------------------------
This table is used by main() to generate the infobox and by doc() to
generate [[Template:Wikidata Infobox/doc/properties]].
* `humans_allowed` determines whether the group should be displayed if the
item is a human (Q5) or a fictional human (Q15632617). It defaults to false.
* A group will only be displayed if `P31_allowed_values` contains the
"instance of" (P31) value of the item or `P31_allowed_values` is not present.
* If `bypass_property_exists_check` is set to true, the infobox tries to fetch
the values for each pid in the group, even if the item has no pid statement.
* `logic` can be a function that will be called with pid as the only argument.
`logic` can also be a WikidataIB arguments table for defaultFunc.
]==]
local property_groups = {
{ groupname = 'Switchable images', -- this group needs to be at index 1
comment = 'Users can switch between these images using [[MediaWiki:Gadget-Infobox.js|Gadget-Infobox.js]].',
humans_allowed = true,
pids = {'P2716','P3383','P18','P13146','P117','P8224','P1442','P1801','P4640','P4291','P3451','P5252','P2713','P8592','P11832','P8517','P5555','P5775','P7417','P9721','P3311','P7420','P7457','P8195','P1543','P996','P3030','P154','P2910','P41','P94','P4004','P158','P2425','P8766','P14','P1766','P15','P8512','P181','P207','P242','P1944','P1943','P1846','P1621','P367','P491','P6655','P10','P4896','P11101','P11702','P12565'},
},
{ groupname = 'Audio and hieroglyphs',
humans_allowed = true,
pids = {'P51','P989','P443','P990','P7383'},
},
{ groupname = 'Human',
P31_allowed_values = { 'Q5', 'Q15632617' },
comment = 'If this group is shown, the other groups below are ignored.',
humans_allowed = true,
pids = {'P1559','P569','P570','P1196','P509','P157','P119','P742','P2031','P2032','P1317','P27','P1532','P551','P69','P184','P185','P106','P2416','P6087','P54','P108','P463','P102','P39','P101','P135','P66','P103','P97','P2962','P2522','P793','P53','P22','P25','P3373','P40','P26','P1038','P451','P937','P800','P1441','P166','P856','P109'},
},
{ groupname = 'Instance/subclass of',
pids = {'P31','P279'},
},
{ groupname = 'Health by region',
P31_allowed_values = { 'Q64027457' },
pids = {'P2250','P4841'},
bypass_property_exists_check = true,
},
{ groupname = 'Natural number',
P31_allowed_values = { 'Q21199' },
pids = {'P5236','P487','P3295','P7415'},
},
{ groupname = 'Education by region',
P31_allowed_values = { 'Q64801076' },
pids = {'P3270','P3271','P6897','P2573'},
bypass_property_exists_check = true,
},
{ groupname = 'National economy',
P31_allowed_values = { 'Q6456916' },
pids = {'P38','P2299','P4010','P2131','P2132','P2219','P1279','P2134','P2855'},
bypass_property_exists_check = true,
logic = getByLocationCollapse4,
},
{ groupname = 'Miscellaneous 1',
pids = {'P361','P1639','P1269','P921','P629','P1559','P452','P7163','P971','P4224','P831','P2317','P138','P825','P417','P547','P180','P2596','P186','P136','P376','P3018','P7532'},
},
{ groupname = 'Location',
comment = 'The properties {{P|131}}, {{P|276}}, {{P|706}}, and {{P|17}} together produce a single infobox row.',
pids = {'P276'},
bypass_property_exists_check = true,
},
{ groupname = 'Miscellaneous 2',
pids = {'P1001','P206','P5353','P4856','P6529','P9759','P6375','P669','P495','P1885','P149','P708','P2872','P16','P2789','P59','P65','P215','P223','P196','P36','P122','P194','P208','P209','P37','P85','P38','P35','P6','P210'},
},
{ groupname = 'Author',
comment = 'Will be displayed together with {{P|2093}}.',
pids = {'P50'},
bypass_property_exists_check = true,
},
{ groupname = 'Miscellaneous 3',
pids = {'P655','P123','P1433','P84','P193','P170','P86','P676','P87','P61','P189','P98','P58','P110','P162','P175','P393','P291','P4647','P407','P2635','P437','P953','P275','P1441','P1080','P88','P6291','P199','P169','P366','P121','P127','P159','P466','P137','P126','P177','P2505','P144','P822','P115','P5138','P118','P505','P286','P527','P1454','P1990','P2522','P1427','P1444','P1923','P1132','P1346','P176','P1071','P617','P504','P532','P8047','P289','P426','P113','P114','P375','P619','P1145','P522','P664','P823','P5804','P57','P161','P195','P217','P178','P112','P400','P306','P1435','P814','P141','P348','P585','P606','P729','P730','P580','P571','P577','P1191','P5444','P575','P1619','P3999','P582','P576','P2669','P793','P516','P2957','P2109','P618','P128','P129','P111','P179'},
},
{ groupname = 'Quantities',
pids = {'P1093','P2067','P2261','P2262','P2049','P2386','P2043','P3157','P2583','P2048','P5524','P2808','P2144','P3439','P4183','P5141','P4552','P2660','P2659','P610','P559','P7309','P1082','P2052','P2217','P2046','P2044','P2050','P2047'},
logic = { unitabbr='yes' },
},
{ groupname = 'Miscellaneous 4',
pids = {'P140','P1083','P2351','P2324','P6801','P6855','P3032','P3137','P770','P1398','P167','P81','P197','P833','P834'},
},
{ groupname = 'Water',
pids = {'P885','P403','P200','P201','P4614','P205','P974','P4792','P4661','P469','P2673','P2674'},
},
{ groupname = 'Miscellaneous 5',
pids = {'P155','P156','P1365','P1366','P3730','P3729'},
},
{ groupname = 'Elections',
pids = {'P991','P726','P1831','P1867','P1868','P1697','P5043','P5045','P5044'},
},
{ groupname = 'Miscellaneous 6',
pids = {'P1590','P1120','P1446','P1339','P1092','P784','P783','P785','P786','P787','P788','P789','P183','P2130','P2769','P1174','P859','P218','P78','P238','P239','P1889','P460','P1382','P2010','P2009','P2033','P1531','P8193'},
},
{ groupname = 'Taxon common name',
comment = "Common names are taken from the item's label, sitelink, and {{P|1843}}.",
pids = {'P1843'},
bypass_property_exists_check = true,
},
{ groupname = 'Taxonomy',
pids = {'P171','P1403','P225'},
},
{ groupname = 'Miscellaneous 7',
pids = {'P6591','P7422','P2078','P856','P6257'},
},
{ groupname = 'Maps',
comment = '{{P|3896}} is only used if no {{P|625}} statement exists. Tracked at {{c|Uses of Wikidata Infobox with maps}}.',
pids = {'P625','P3896'},
bypass_property_exists_check = true,
},
}
local externalIDs = {
{ groupname = 'Authority control',
pids = {'P213','P214','P227','P244','P268','P269','P270','P349','P409','P508','P640','P651','P691','P886','P902','P906','P947','P949','P950','P1003','P1006','P1015','P1048','P1157','P1207','P1225','P1415','P1695','P2558','P2581','P4819','P5034','P5587','P7293','P8189','P9371','P10539',}
},
{ groupname = 'Books/magazines/authors/libraries',
pids = {'P236','P271','P396','P648','P723','P724','P2961','P5199',}
},
{ groupname = 'Science',
pids = {'P356','P496','P549','P698','P717','P932','P1053','P2349','P3083','P8273',}
},
{ groupname = 'Biology',
pids = {'P428','P627','P685','P687','P6535','P815','P830','P838','P842','P846','P850','P938','P959','P960','P961','P962','P1070','P1076','P1348','P1391','P1421','P1727','P1745','P1746','P1747','P1761','P1772','P1832','P1895','P1940','P1991','P1992','P2007','P2026','P2036','P2040','P2426','P2434','P2455','P2464','P2752','P2833','P2946','P3031','P3060','P3064','P3099','P3100','P3101','P3102','P3151','P3240','P3288','P3398','P3420','P3444','P3591','P3594','P3606','P3746','P4024','P4122','P4194','P4301','P4526','P4567','P4728','P4758','P4855','P5036','P5037','P5055','P5216','P5221','P5257','P5299','P6678','P7051',}
},
{ groupname = 'Art',
pids = {'P245','P347','P434','P650','P781','P1882','P1901','P3293','P3634','P4399','P4659','P4701','P5950','P6506','P6631','P7704','P8386','P9394',}
},
{ groupname = 'Culture',
pids = {'P345','P539','P1219','P1220','P1248','P1362','P6113','P6132','P12037',}
},
{ groupname = 'Sports',
pids = {'P1146','P1440','P1469','P1665','P2020','P2276','P2446','P2458','P2574','P3171','P3537','P3538','P3681','P3924','P8286',}
},
{ groupname = 'Cultural heritage and architecture',
pids = {'P359','P380','P381','P454','P481','P649','P709','P718','P757','P758','P762','P808','P1216','P1305','P1459','P1483','P1600','P1700','P1702','P1708','P1764','P1769','P2424','P2783','P2081','P2917','P3038','P3177','P3178','P3318','P3449','P3596','P3758','P3759','P4009','P4075','P4102','P4244','P4360','P4372','P4868','P5094','P5310','P5313','P5500','P5525','P5528','P6102','P6542','P6736','P7006','P7170','P7304','P7630','P7659','P7694','P7900','P9148','P9154','P9339','P9342','P10486','P11351','P11557'}
},
{ groupname = 'Protected areas',
pids = {'P809','P3425','P3613','P3974','P5965','P6602','P6230','P6280','P6478','P6560','P6659','P3296','P677',}
},
{ groupname = 'Places and geographical features',
pids = {'P402','P11693','P10689','P3120','P3580','P3616','P3628','P4266','P6630','P7350','P7352','P7548','P8655','P8988','P10451','P4533',}
},
{ groupname = 'Administrative subdivisions',
pids = {'P772','P836','P1894','P3118','P3615','P3639','P3419','P7526','P2788','P7577','P7606','P7635','P7636','P7579','P7752','P7673','P7674','P7736','P7735',}
},
{ groupname = 'Other',
pids = {'P458','P587','P2037','P3112','P10557','P3479','P4344','P6228','P7721',}
},
}
--- @param group table
local function groupIsAllowed( group )
local ishuman = INSTANCEOF['Q5'] or INSTANCEOF['Q15632617']
if ishuman and not group.humans_allowed then return false end
local allowlist = group.P31_allowed_values
if not allowlist then return true end
for _, class in ipairs( allowlist ) do
if INSTANCEOF[class] then return true end
end
return false
end
local function noImage()
-- Wikidata classes that don't need an image
local dontNeedImg = {
'Q4167410', -- disambiguation page
'Q4167836', -- Wikimedia category
'Q11266439', -- Wikimedia template
'Q14204246', -- Wikimedia project page
'Q13406463', -- Wikimedia list article
'Q101352', -- family name
'Q202444', -- given name
'Q12308941', -- male given name
'Q11879590', -- female given name
'Q3409032', -- unisex given name
}
for _, class in ipairs( dontNeedImg ) do
if INSTANCEOF[class] then return end
end
local hasImg
for _, imgPid in ipairs( property_groups[1].pids ) do
if CLAIMS[imgPid] then
hasImg = true
break
end
end
if not hasImg then
return '[[Category:Uses of Wikidata Infobox with no image]]'
end
end
--- Returns string with all labels/descs/aliases for search engine optimization
local function seo()
local out = {}
for lang, v in pairs( ITEM.labels or {} ) do
out[#out+1] = v.value
end
for lang, v in pairs( ITEM.descriptions or {} ) do
out[#out+1] = v.value
end
for lang, v in pairs( ITEM.aliases or {} ) do
for _, w in ipairs( v ) do
out[#out+1] = w.value
end
end
return table.concat( out, '; ' )
end
-- wikiprojects that are not Wikipedia despite their IDs ending with 'wiki'
local excludedProjects = {
wikidatawiki = true, commonswiki = true, specieswiki = true,
metawiki = true, mediawikiwiki = true, outreachwiki = true,
sourceswiki = true, wikimaniawiki = true, incubatorwiki = true,
akwiki = true, foundationwiki = true, wikifunctionswiki = true,
}
-- Returns interwiki link if site is Wikipedia
local function interwikilink( site, title )
-- from LanguageCode.php
local deprecatedLangs = {
['als'] = 'gsw', -- T25215
['bat-smg'] = 'sgs', -- T27522
['be-x-old'] = 'be-tarask', -- T11823
['fiu-vro'] = 'vro', -- T31186
['roa-rup'] = 'rup', -- T17988
['zh-classical'] = 'lzh', -- T30443
['zh-min-nan'] = 'nan', -- T30442
['zh-yue'] = 'yue', -- T30441
}
if site:sub(-4) == 'wiki' and not excludedProjects[site] then
local iwprefix = site:sub(1, -5):gsub('_', '-') -- "zh_yuewiki" to "zh-yue"
if deprecatedLangs[iwprefix] then
iwprefix = deprecatedLangs[iwprefix]
end
return string.format( '[[%s:%s]]', iwprefix, title )
end
end
--- Adds Wikipedia sitelinks from similar items. Example at Cat:Moore_(surname)
local function interwikis()
local out = {}
-- ITEM is usually P301 of connected item, so this is not redundant:
for site, v in pairs( ITEM.sitelinks or {} ) do
out[#out+1] = interwikilink( site, v.title )
end
for _, pid in ipairs{ 'P910', 'P2354', 'P1753', 'P460', 'P1420' } do -- topic's main category, has list, related list, said to be same as, taxon synonym
for similar in iclaims( ITEM:getBestStatements(pid) ) do
for site, v in pairs( mw.wikibase.getEntity(similar.id).sitelinks or {} ) do
out[#out+1] = interwikilink( site, v.title )
end
end
end
return table.concat( out )
end
local charMap -- memoized
local function stripDiacritics( str )
if not charMap then
local from = 'ÁÀÂÄǍĂĀÃÅẠĄƏĆĊĈČÇĎĐḐḌÐÉÈĖÊËĚĔƐƎỀỂỄẾỆĒẼĘẸĠĜĞĢĤĦḤİÍÌÎÏǏĬĪĨĮỊĴĶĹĿĽĻŁḶḸṂŃŇÑŅṆŊÓÒÔÖǑŎŌÕǪỌŐØꝚŔŘŖⱤɌƦȐȒṘṚṜŚŜŠŞȘṢŤŢȚṬÚÙÛÜǓŬŪŨŮŲỤŰǗǛǙǕŴÝŶŸỸȲŹŻŽ'..
'ằắắáẳàẵâäǎăāãåặầẩẫấậảạąəćċĉčçḑďđḍðéèėêëěɛǝềểễếệĕēẽęẹġĝğģḩĥħḥıíìîïǐĭīĩįịĵķĺŀľļłḷḹṃńňñņṇŋơóồòôöǒŏōõǫọőøꝛŕɽřŗṛṝɍʀȑȓṙśŝšşșṣťţțṭưúùûứừüǔŭūũůųụűǘǜǚǖŵýŷÿỹȳźżž'
local to = 'AAAAAAAAAAAACCCCCDDDDDEEEEEEEEEEEEEEEEEEGGGGHHHIIIIIIIIIIIJKLLLLLLLMNNNNNNOOOOOOOOOOOORRRRRRRRRRRRSSSSSSTTTTUUUUUUUUUUUUUUUUWYYYYYZZZ'..
'aaaaaaaaaaaaaaaaaaaaaaaacccccdddddeeeeeeeeeeeeeeeeeegggghhhhiiiiiiiiiiijklllllllmnnnnnnoooooooooooooorrrrrrrrrrrrssssssttttuuuuuuuuuuuuuuuuuuuwyyyyyzzz'
charMap = {}
for i = 1, mw.ustring.len( from ) do
charMap[mw.ustring.sub(from, i, i)] = mw.ustring.sub(to, i, i)
end
charMap['ß'] = 'ss'; charMap['ẞ'] = 'SS'
charMap['æ'] = 'ae'; charMap['ǣ'] = 'ae'; charMap['ǽ'] = 'ae'
charMap['Æ'] = 'AE'; charMap['Ǣ'] = 'AE'; charMap['Ǽ'] = 'AE'
charMap['œ'] = 'oe'; charMap['Œ'] = 'OE'
charMap['þ'] = 'th'; charMap['Þ'] = 'Th'
end
return (string.gsub( str, '[^\128-\191][\128-\191]*', charMap ))
end
local function humannames( out )
local surname = ITEM:formatPropertyValues('P734').value:gsub(',.*', '')
local givennames = ITEM:formatPropertyValues('P735').value:gsub(', ', ' ')
local spanish2nd = ITEM:formatPropertyValues('P1950').value:gsub(',.*', '')
if config.trackingcats then
if surname == '' then
out[#out+1] = '[[Category:Uses of Wikidata Infobox with no family name]]'
end
if givennames == '' then
out[#out+1] = '[[Category:Uses of Wikidata Infobox with no given name]]'
end
end
if config.autocat then
for _, pid in ipairs{ 'P734', 'P1950', 'P9139' } do
for surname in iclaims( ITEM:getBestStatements(pid) ) do
local sitelink = getCommonsLink( surname.id )
if sitelink and sitelink:sub(1,9) == 'Category:' then
if givennames == '' then
out[#out+1] = string.format('[[%s]]', sitelink)
else
out[#out+1] = string.format('[[%s|%s]]', sitelink, stripDiacritics(givennames))
end
else
local surnamelabel = mw.wikibase.getLabelByLang( surname.id, 'en' ) or mw.wikibase.getLabelByLang( surname.id, 'mul' )
if givennames == '' then
out[#out+1] = surnamelabel and string.format('[[Category:%s (surname)]][[Category:Uses of Wikidata Infobox with no surname sitelink]]', surnamelabel)
else
out[#out+1] = surnamelabel and string.format('[[Category:%s (surname)|%s]][[Category:Uses of Wikidata Infobox with no surname sitelink]]', surnamelabel, stripDiacritics(givennames))
end
end
end
end
for givenname in iclaims( ITEM:getBestStatements('P735') ) do
local sitelink = getCommonsLink( givenname.id )
if sitelink and sitelink:sub(1,9) == 'Category:' then
out[#out+1] = string.format('[[%s]]', sitelink) -- no sort key needed because DEFAULTSORT starts with family name
else
local givennamelabel = mw.wikibase.getLabelByLang( givenname.id, 'en' ) or mw.wikibase.getLabelByLang( givenname.id, 'mul' )
out[#out+1] = givennamelabel and string.format('[[Category:%s (given name)]]', givennamelabel)
end
end
end
if not config.defaultsort then
out[#out+1] = '[[Category:Uses of Wikidata Infobox with defaultsort suppressed]]'
elseif surname ~= '' and surname ~= 'no value' and surname ~= 'some value' then
if spanish2nd ~= '' then
surname = surname .. ' ' .. spanish2nd
end
local sortkey = stripDiacritics( surname..', '..givennames )
out[#out+1] = frame:preprocess('{{DEFAULTSORT:'..sortkey..'}}')
end
end
--- @param pid "P569"|"P570"
--- @param event "birth"|"death"
local function datecat( pid, event, out )
local year = WikidataIB._getValue{ pid, qid=QID, ps=1, df='y', plaindate='adj', lang='en', maxvals=1 }
if year and year ~= 'unknown value' then
local cat = 'Category:' .. year .. ' ' .. event .. 's'
if mw.title.new( cat ).exists then
out[#out+1] = '[['..cat..']]'
elseif config.trackingcats then
mw.addWarning( 'Categorization under [[:'..cat..']] supressed' )
out[#out+1] = '[[Category:Uses of Wikidata Infobox with unknown '..event..' category|'..year..']]'
end
end
end
local function countrycat( out )
local countryLabels = {
-- All countries that have a "Men of {} by name" Commons category.
-- When adding a value, make sure it's not a [[Template:Category redirect]].
-- See also [[User:LennardHofmann/countries without "men by name" category]].
Q16 = "Canada",
Q17 = "Japan",
Q20 = "Norway",
Q21 = "England",
Q22 = "Scotland",
Q25 = "Wales",
Q26 = "Northern Ireland",
Q27 = "the Republic of Ireland",
Q28 = "Hungary",
Q29 = "Spain",
Q30 = "the United States",
Q31 = "Belgium",
Q32 = "Luxembourg",
Q33 = "Finland",
Q34 = "Sweden",
Q35 = "Denmark",
Q36 = "Poland",
Q37 = "Lithuania",
Q38 = "Italy",
Q39 = "Switzerland",
Q40 = "Austria",
Q41 = "Greece",
Q43 = "Turkey",
Q45 = "Portugal",
Q55 = "the Netherlands",
Q77 = "Uruguay",
Q79 = "Egypt",
Q96 = "Mexico",
Q114 = "Kenya",
Q115 = "Ethiopia",
Q117 = "Ghana",
Q142 = "France",
Q145 = "the United Kingdom",
Q148 = "the People's Republic of China",
Q155 = "Brazil",
Q159 = "Russia",
Q183 = "Germany",
Q184 = "Belarus",
Q189 = "Iceland",
Q191 = "Estonia",
Q211 = "Latvia",
Q212 = "Ukraine",
Q213 = "the Czech Republic",
Q214 = "Slovakia",
Q215 = "Slovenia",
Q217 = "Moldova",
Q218 = "Romania",
Q219 = "Bulgaria",
Q221 = "North Macedonia",
Q222 = "Albania",
Q223 = "Greenland",
Q224 = "Croatia",
Q225 = "Bosnia and Herzegovina",
Q227 = "Azerbaijan",
Q228 = "Andorra",
Q229 = "Cyprus",
Q230 = "Georgia",
Q232 = "Kazakhstan",
Q233 = "Malta",
Q235 = "Monaco",
Q236 = "Montenegro",
Q238 = "San Marino",
Q241 = "Cuba",
Q242 = "Belize",
Q244 = "Barbados",
Q252 = "Indonesia",
Q258 = "South Africa",
Q262 = "Algeria",
Q265 = "Uzbekistan",
Q298 = "Chile",
Q334 = "Singapore",
Q347 = "Liechtenstein",
Q398 = "Bahrain",
Q399 = "Armenia",
Q403 = "Serbia",
Q408 = "Australia",
Q414 = "Argentina",
Q419 = "Peru",
Q423 = "North Korea",
Q424 = "Cambodia",
Q574 = "East Timor",
Q657 = "Chad",
Q664 = "New Zealand",
Q668 = "India",
Q672 = "Tuvalu",
Q678 = "Tonga",
Q683 = "Samoa",
Q685 = "the Solomon Islands",
Q686 = "Vanuatu",
Q691 = "Papua New Guinea",
Q695 = "Palau",
Q697 = "Nauru",
Q702 = "the Federated States of Micronesia",
Q709 = "the Marshall Islands",
Q711 = "Mongolia",
Q712 = "Fiji",
Q717 = "Venezuela",
Q730 = "Suriname",
Q733 = "Paraguay",
Q734 = "Guyana",
Q736 = "Ecuador",
Q739 = "Colombia",
Q750 = "Bolivia",
Q754 = "Trinidad and Tobago",
Q757 = "Saint Vincent and the Grenadines",
Q760 = "Saint Lucia",
Q763 = "Saint Kitts and Nevis",
Q766 = "Jamaica",
Q769 = "Grenada",
Q774 = "Guatemala",
Q781 = "Antigua and Barbuda",
Q783 = "Honduras",
Q784 = "Dominica",
Q786 = "the Dominican Republic",
Q790 = "Haiti",
Q792 = "El Salvador",
Q794 = "Iran",
Q796 = "Iraq",
Q800 = "Costa Rica",
Q801 = "Israel",
Q804 = "Panama",
Q805 = "Yemen",
Q810 = "Jordan",
Q811 = "Nicaragua",
Q813 = "Kyrgyzstan",
Q817 = "Kuwait",
Q819 = "Laos",
Q822 = "Lebanon",
Q826 = "the Maldives",
Q833 = "Malaysia",
Q836 = "Myanmar",
Q837 = "Nepal",
Q842 = "Oman",
Q843 = "Pakistan",
Q846 = "Qatar",
Q851 = "Saudi Arabia",
Q854 = "Sri Lanka",
Q858 = "Syria",
Q863 = "Tajikistan",
Q865 = "Taiwan",
Q869 = "Thailand",
Q874 = "Turkmenistan",
Q878 = "the United Arab Emirates",
Q881 = "Vietnam",
Q884 = "South Korea",
Q889 = "Afghanistan",
Q902 = "Bangladesh",
Q912 = "Mali",
Q916 = "Angola",
Q917 = "Bhutan",
Q921 = "Brunei",
Q924 = "Tanzania",
Q928 = "the Philippines",
Q929 = "the Central African Republic",
Q945 = "Togo",
Q948 = "Tunisia",
Q953 = "Zambia",
Q954 = "Zimbabwe",
Q958 = "South Sudan",
Q962 = "Benin",
Q963 = "Botswana",
Q965 = "Burkina Faso",
Q967 = "Burundi",
Q970 = "the Comoros",
Q971 = "the Republic of the Congo",
Q974 = "the Democratic Republic of the Congo",
Q977 = "Djibouti",
Q983 = "Equatorial Guinea",
Q986 = "Eritrea",
Q1000 = "Gabon",
Q1005 = "the Gambia",
Q1006 = "Guinea",
Q1007 = "Guinea-Bissau",
Q1008 = "Ivory Coast",
Q1009 = "Cameroon",
Q1011 = "Cape Verde",
Q1013 = "Lesotho",
Q1014 = "Liberia",
Q1016 = "Libya",
Q1019 = "Madagascar",
Q1020 = "Malawi",
Q1025 = "Mauritania",
Q1027 = "Mauritius",
Q1028 = "Morocco",
Q1029 = "Mozambique",
Q1030 = "Namibia",
Q1032 = "Niger",
Q1033 = "Nigeria",
Q1036 = "Uganda",
Q1037 = "Rwanda",
Q1039 = "São Tomé and Príncipe",
Q1041 = "Senegal",
Q1042 = "Seychelles",
Q1044 = "Sierra Leone",
Q1045 = "Somalia",
Q1049 = "Sudan",
Q1050 = "Eswatini",
Q1055 = "Hamburg",
Q1183 = "Puerto Rico",
Q1209 = "Bremen",
Q1231 = "Kosovo",
Q1246 = "Kosovo",
Q1410 = "Gibraltar",
Q1741 = "Vienna",
Q2184 = "the Russian Soviet Federative Socialist Republic",
Q4948 = "the Republic of Venice",
Q6250 = "Western Sahara",
Q7318 = "Nazi Germany",
Q8646 = "Hong Kong",
Q8680 = "the British Empire",
Q11768 = "Ancient Egypt",
Q12548 = "the Holy Roman Empire",
Q12560 = "the Ottoman Empire",
Q14773 = "Macau",
Q15180 = "the Soviet Union",
Q15581 = "the Principality of Catalonia",
Q15864 = "the United Kingdom of the Netherlands",
Q16641 = "American Samoa",
Q16957 = "the German Democratic Republic",
Q17557 = "California Republic",
Q20135 = "the Grand Duchy of Hesse",
Q22502 = "Taiwan",
Q22880 = "Electoral Palatinate",
Q23334 = "Abkhazia",
Q23681 = "Northern Cyprus",
Q25230 = "the Bailiwick of Guernsey",
Q26988 = "the Cook Islands",
Q27306 = "the Kingdom of Prussia",
Q28513 = "Austria-Hungary",
Q29999 = "the Kingdom of the Netherlands",
Q31747 = "the Irish Free State",
Q33946 = "Czechoslovakia",
Q34020 = "Niue",
Q34266 = "the Russian Empire",
Q34762 = "the Principality of Bayreuth",
Q35672 = "the Pitcairn Islands",
Q36704 = "Yugoslavia",
Q37024 = "Serbia and Montenegro",
Q38610 = "the Dominion of Newfoundland",
Q38872 = "Prussia",
Q41304 = "the Weimar Republic",
Q42199 = "the Principality of Ansbach",
Q42585 = "the Kingdom of Bohemia",
Q43287 = "the German Empire",
Q45670 = "the Kingdom of Portugal",
Q46370 = "West Francia",
Q47261 = "the Duchy of Bavaria",
Q49683 = "the Grand Duchy of Lithuania",
Q56036 = "West Berlin",
Q58296 = "the French First Republic",
Q61292 = "the Far Eastern Republic",
Q62589 = "the Union between Sweden and Norway",
Q62633 = "the Grand Principality of Finland",
Q69829 = "French Fourth Republic",
Q70802 = "French Third Republic",
Q70972 = "the Kingdom of France",
Q71084 = "the First French Empire",
Q71747 = "the Duchy of Brittany",
Q80702 = "the Spanish Empire",
Q83286 = "Socialist Federal Republic of Yugoslavia",
Q121932 = "the People's Republic of Bulgaria",
Q124943 = "the Kingdom of Egypt",
Q129286 = "British Raj",
Q130280 = "Estonian Soviet Socialist Republic",
Q131964 = "the Austrian Empire",
Q133356 = "Ukrainian Soviet Socialist Republic",
Q139319 = "the Russian Republic",
Q140359 = "First Czechoslovak Republic",
Q146562 = "the State of Damascus",
Q146600 = "the Arab Kingdom of Syria",
Q146880 = "the State of Syria",
Q146885 = "Second Syrian Republic",
Q147909 = "the Kingdom of Bulgaria",
Q148499 = "the Margraviate of Brandenburg",
Q148540 = "the Republic of Florence",
Q149805 = "the Kingdom of Iraq",
Q150981 = "the North German Confederation",
Q151624 = "German Confederation",
Q152115 = "the Duchy of Warsaw",
Q152750 = "the Protectorate of Bohemia and Moravia",
Q152855 = "the Kingdom of Tungning",
Q153015 = "the Kingdom of Saxony",
Q153080 = "East Francia",
Q153128 = "the Independent State of Croatia",
Q153136 = "Habsburg monarchy",
Q153529 = "the Duchy of Milan",
Q153943 = "the Kingdom of Westphalia",
Q154195 = "the Kingdom of Bavaria",
Q154741 = "the Confederation of the Rhine",
Q154849 = "the Grand Duchy of Tuscany",
Q155019 = "the Duchy of Lorraine",
Q156038 = "the Duchy of Courland and Semigallia",
Q156199 = "the Electorate of Saxony",
Q156418 = "the Kingdom of Hawaiʻi",
Q157367 = "Brandenburg-Prussia",
Q158445 = "the Grand Duchy of Mecklenburg-Schwerin",
Q158835 = "the Prince-Bishopric of Liège",
Q159631 = "the Kingdom of Württemberg",
Q159856 = "the Duchy of Brabant",
Q161036 = "the Free State of Prussia",
Q161215 = "the Grand Duchy of Mecklenburg-Strelitz",
Q161885 = "the Kingdom of Great Britain",
Q164079 = "the Kingdom of Hanover",
Q165154 = "the Kingdom of Sardinia",
Q170072 = "Dutch Republic",
Q170174 = "Papal States",
Q170468 = "United Arab Republic",
Q170588 = "the Republic of Texas",
Q170604 = "New France",
Q171150 = "the Kingdom of Hungary",
Q172107 = "Polish–Lithuanian Commonwealth",
Q172579 = "the Kingdom of Italy",
Q173065 = "the Kingdom of Naples",
Q174193 = "the United Kingdom of Great Britain and Ireland",
Q174306 = "the Republic of Genoa",
Q175276 = "the Kingdom of León",
Q176495 = "the Federal State of Austria",
Q178085 = "the Principality of Zeta",
Q179293 = "the Kingdom of Castile",
Q179876 = "the Kingdom of England",
Q180393 = "the Kingdom of the Two Sicilies",
Q185682 = "French Indochina",
Q186096 = "the Tsardom of Russia",
Q186320 = "the Grand Duchy of Baden",
Q188553 = "the Batavian Republic",
Q188586 = "the Kingdom of Sicily",
Q188712 = "the Empire of Japan",
Q191077 = "the Kingdom of Yugoslavia",
Q193619 = "the Union of South Africa",
Q199442 = "the Kingdom of Aragon",
Q199821 = "Gran Colombia",
Q200464 = "the Portuguese Empire",
Q203493 = "the Kingdom of Romania",
Q204920 = "the Crown of Aragon",
Q205662 = "Tokugawa shogunate",
Q207272 = "the Second Polish Republic",
Q207353 = "Acadia",
Q208169 = "the Republic of Ragusa",
Q209065 = "the Kingdom of Greece",
Q209857 = "the Kingdom of Lombardy–Venetia",
Q211274 = "the Polish People's Republic",
Q212278 = "the Kingdom of Holland",
Q215443 = "the Swedish Empire",
Q215530 = "the Kingdom of Ireland",
Q218023 = "Orange Free State",
Q219060 = "the State of Palestine",
Q221457 = "Congress Poland",
Q223936 = "the Kingdom of Italy",
Q230791 = "the Kingdom of Scotland",
Q241748 = "the Kingdom of Serbia",
Q243610 = "Ukrainian People's Republic",
Q244165 = "the Republic of Artsakh",
Q253094 = "the Kingdom of Hungary",
Q256961 = "the Electorate of Bavaria",
Q258532 = "British America",
Q268970 = "the Republic of German-Austria",
Q284667 = "the Electorate of Mainz",
Q310293 = "the Saar Protectorate",
Q310650 = "Schaumburg-Lippe",
Q330362 = "the Commonwealth of England",
Q389004 = "Wallachia",
Q389688 = "the Achaemenid Empire",
Q391980 = "the Free Territory of Trieste",
Q430309 = "Đại Việt",
Q435583 = "the Old Swiss Confederacy",
Q457167 = "West Ukrainian People's Republic",
Q467864 = "the People's Socialist Republic of Albania",
Q514423 = "the Parthenopean Republic",
Q518101 = "the First Republic of Austria",
Q529605 = "the Electorate of Hesse",
Q533534 = "Cisleithania",
Q556263 = "the Duchy of Brunswick-Lüneburg",
Q574644 = "the Prince-Bishopric of Speyer",
Q577867 = "the Kingdom of Poland",
Q590743 = "Ruanda-Urundi",
Q600018 = "the Kingdom of Hungary",
Q600093 = "Habsburg Spain",
Q618399 = "the Republic of the Congo (Léopoldville)",
Q630882 = "the Republic of New Granada",
Q637238 = "the Electorate of Baden",
Q650370 = "the Margraviate of Baden-Durlach",
Q650489 = "the Margraviate of Baden",
Q654342 = "the Federation of Rhodesia and Nyasaland",
Q655621 = "the Principality of Transylvania",
Q682318 = "Swedish Pomerania",
Q684030 = "the Principality of Serbia",
Q686965 = "Anhalt-Bernburg",
Q690821 = "the Republic of Baden",
Q693570 = "the Duchy of Ferrara",
Q696241 = "the Khanate of Kokand",
Q696908 = "the Kingdom of Poland",
Q699964 = "the Archduchy of Austria",
Q701614 = "the Archbishopric of Salzburg",
Q704300 = "the Free City of Frankfurt",
Q707767 = "the Prince-Bishopric of Utrecht",
Q713750 = "West Germany",
Q736727 = "the Republic of Siena",
Q750583 = "Southern Rhodesia",
Q756617 = "the Kingdom of Denmark",
Q766501 = "the Duchy of Mantua",
Q779011 = "the Principality of Montenegro",
Q836680 = "the Duchy of Nassau",
Q838261 = "the Federal Republic of Yugoslavia",
Q838931 = "the Kingdom of Italy",
Q858841 = "the Kingdom of Croatia",
Q877875 = "Palmyrene Empire",
Q899706 = "Peru–Bolivian Confederation",
Q913828 = "the Republic of Prekmurje",
Q958291 = "the United Principalities of Moldavia and Wallachia",
Q964024 = "Moldavian Democratic Republic",
Q1031430 = "Habsburg Netherlands",
Q1048340 = "the Kingdom of Albania",
Q1057542 = "the Republic of Hawaii",
Q1063498 = "the United States of the Ionian Islands",
Q1077630 = "the Septinsular Republic",
Q1152126 = "the People's Republic of the Congo",
Q1206012 = "the German Reich",
Q1233672 = "the County of Barcelona",
Q1235720 = "the Republic of Lucca",
Q1290149 = "the Federal People's Republic of Yugoslavia",
Q1365493 = "the Republic of Pisa",
Q1421888 = "Ubangi-Shari",
Q1470101 = "the Kingdom of Hungary",
Q1508143 = "Ukrainian State",
Q1541723 = "the County of Lippe",
Q1615455 = "the Duchy of Mirandola",
Q1649871 = "the Kingdom of Poland",
Q1658411 = "the Raj of Sarawak",
Q1747689 = "Ancient Rome",
Q1794352 = "the Electorate of Trier",
Q1900716 = "Margraviate Hachberg-Sausenberg",
Q1900717 = "the Margraviate of Brandenburg-Küstrin",
Q1917014 = "the County of Sicily",
Q2002279 = "Portuguese Guinea",
Q2010024 = "the Second Czechoslovak Republic",
Q2017684 = "the French protectorate of Tunisia",
Q2037576 = "the Republic of San Marco",
Q2079909 = "the Province of Massachusetts Bay",
Q2196956 = "the Kingdom of Norway",
Q2208280 = "the People's Republic of Angola",
Q2227570 = "the Duchy of Württemberg",
Q2252973 = "the Duchy of Florence",
Q2305208 = "the Russian Socialist Federative Soviet Republic",
Q2335128 = "the Province of New Jersey",
Q2396442 = "the Kingdom of Galicia and Lodomeria",
Q2415003 = "the Kingdom of Serbia",
Q2577303 = "the Kingdom of Sardinia",
Q2670751 = "the Margraviate of Moravia",
Q2719360 = "Duchy of Luxembourg",
Q3113481 = "the Principality of Transylvania",
Q3324486 = "the Prince-Bishopric of Montenegro",
Q3456410 = "the Republic of Mulhouse",
Q3503555 = "Palembang Sultanate",
Q3755547 = "the Kingdom of Italy",
Q4304392 = "the Russian State",
Q4398229 = "the Russian State (1918–1920)",
Q6581823 = "the Southern Netherlands",
Q7842409 = "Trinidad and Tobago",
Q8890160 = "the Kingdom of Poland",
Q10957559 = "the Principality of Moldavia",
Q11750128 = "the Kingdom of Poland",
Q13426199 = "the Republic of China",
Q14164803 = "the Prince-Bishopric of Fulda",
Q15102440 = "the Kingdom of Serbs, Croats and Slovenes",
Q15824804 = "the Kénédougou Kingdom",
Q16056854 = "the Kingdom of Hungary",
Q16550783 = "the Duchy of Anhalt",
Q17059107 = "the Western Wei",
Q18285930 = "the German Empire of 1848/1849",
Q19872858 = "the Earldom of Ulster",
Q19901436 = "Suriname",
Q23366230 = "the Republic of Geneva",
Q23498721 = "Gold Coast",
Q25395037 = "the Kingdom of Hungary",
Q30890672 = "the Kingdom of Sicily",
Q55599391 = "the Kingdom of Sardinia",
Q64576860 = "the Lordship of Bologna",
Q112660052 = "the British India",
}
for country in iclaims( ITEM:getBestStatements('P27') ) do
local countryLabel = countryLabels[country.id]
if not countryLabel then
if config.trackingcats then
out[#out+1] = '[[Category:Uses of Wikidata Infobox with unknown country category|'..country['numeric-id']..']]'
end
else
local sex = getSingleValue( ITEM, 'P21' )
local sexLabel = sex and ({
Q6581097 = 'Men',
Q2449503 = 'Men',
Q6581072 = 'Women',
Q1052281 = 'Women',
})[sex.id]
if sexLabel then
out[#out+1] = '[[Category:'..sexLabel..' of '..countryLabel..' by name]]'
else
out[#out+1] = '[[Category:People of '..countryLabel..' by name]]'
end
end
end
end
local function autocat( out, pid, dict )
for _, claim in ipairs( ITEM:getAllStatements(pid) ) do
if claim.rank ~= "deprecated" then
local dv = claim.mainsnak.datavalue
local cat = dict[dv and dv.value.id]
out[#out+1] = cat and '[[Category:'..cat..']]'
end
end
end
local function metadata()
local out = {}
if config.trackingcats then
out[#out+1] = noImage()
if not (CLAIMS['P31'] or CLAIMS['P279']) then
out[#out+1] = '[[Category:Uses of Wikidata Infobox with no instance of]]'
end
if INSTANCEOF['Q5'] and not CLAIMS['P569'] then
out[#out+1] = '[[Category:Uses of Wikidata Infobox with no year of birth]]'
elseif INSTANCEOF['Q4167836'] and not (CLAIMS['P301'] or CLAIMS['P971']) then
out[#out+1] = '[[Category:Uses of Wikidata Infobox with no topic]]'
end
end
out[#out+1] = '<div style="display:none"><nowiki>'..seo()..'</nowiki></div>'
-- Add interwiki links from related items, inspired by Module:Interwiki
if config.interwiki and mw.title.getCurrentTitle().namespace == 14 then
out[#out+1] = interwikis()
end
if config.autocat then
for pid, cat in pairs( autocats_by_id ) do
local val = getSingleValue( ITEM, pid )
out[#out+1] = val and string.format( '[[Category:%s| %s]]', cat, val )
end
out[#out+1] = CLAIMS['P757'] and '[[Category:World Heritage Sites by name]]'
autocat( out, 'P1435', { -- heritage designation
Q34932610 = 'Conjuntos de Interesse Municipal in Portugal by name',
Q28419115 = 'Conjuntos de Interesse Público in Portugal by name',
Q54171320 = 'Monuments under study in Portugal by name',
Q15697324 = 'Imóveis de Interesse Público in Portugal by name',
Q11791 = 'Imóveis de Interesse Municipal in Portugal by name',
Q53806418 = 'Monuments included in classified sites in Portugal by name',
Q28423275 = 'Monumentos de Interesse Municipal in Portugal by name',
Q22222923 = 'Monumentos de Interesse Público in Portugal by name',
Q908411 = 'Monumentos Nacionais in Portugal by name',
Q28419400 = 'Sítios de Interesse Municipal in Portugal by name',
Q28419109 = 'Sítios de Interesse Público in Portugal by name',
Q54163210 = 'Pending classification monuments in Portugal by name',
})
autocat( out, 'P31', { -- instance of
Q235670 = 'Common years starting and ending on Sunday',
Q235673 = 'Common years starting and ending on Saturday',
Q235676 = 'Common years starting and ending on Wednesday',
Q235680 = 'Common years starting and ending on Friday',
Q235684 = 'Common years starting and ending on Tuesday',
Q235687 = 'Common years starting and ending on Monday',
Q235690 = 'Common years starting and ending on Thursday',
Q217041 = 'Leap years starting on Sunday and ending on Monday',
Q217026 = 'Leap years starting on Saturday and ending on Sunday',
Q217015 = 'Leap years starting on Wednesday and ending on Thursday',
Q217036 = 'Leap years starting on Friday and ending on Saturday',
Q217034 = 'Leap years starting on Tuesday and ending on Wednesday',
Q217024 = 'Leap years starting on Monday and ending on Tuesday',
Q217019 = 'Leap years starting on Thursday and ending on Friday',
Q66010119 = 'Months starting on Monday',
Q66010126 = 'Months starting on Tuesday',
Q66010132 = 'Months starting on Wednesday',
Q66010139 = 'Months starting on Thursday',
Q66010148 = 'Months starting on Friday',
Q66010153 = 'Months starting on Saturday',
Q66010158 = 'Months starting on Sunday',
Q3305213 = 'Individual painting categories',
})
if INSTANCEOF['Q5'] and mw.title.getCurrentTitle().namespace == 14 then
humannames( out )
datecat( 'P569', 'birth', out )
datecat( 'P570', 'death', out )
countrycat( out )
autocat( out, 'P21', { -- sex or gender
Q6581097 = 'Men by name',
Q6581072 = 'Women by name',
Q1052281 = 'LGBT people by name]][[Category:Women by name',
Q2449503 = 'LGBT people by name]][[Category:Men by name',
Q48270 = 'Non-binary people by name',
Q12964198 = 'LGBT people by name', -- genderqueer
Q1097630 = 'LGBT people by name', -- intersex
Q18116794 = 'LGBT people by name', -- genderfluid
Q505371 = 'LGBT people by name', -- agender
})
autocat( out, 'P509', { -- cause of death
Q2840 = "Deaths from influenza",
Q8277 = "Deaths from multiple sclerosis",
Q9687 = "Deaths from road accidents",
Q11081 = "Deaths from Alzheimer's disease",
Q11085 = "Deaths from Parkinson's disease",
-- Q12078 = "Deaths from cancer", -- too unspecific
Q12090 = "Deaths from cholera",
Q12152 = "Deaths from myocardial infarction",
Q12156 = "Deaths from malaria",
Q12192 = "Deaths from pneumonia",
Q12199 = "Deaths from AIDS",
Q12202 = "Deaths from stroke",
Q12204 = "Deaths from tuberculosis",
Q12206 = "Deaths from diabetes",
Q12214 = "Deaths from smallpox",
Q12796 = "Deaths by gunshot",
Q29496 = "Deaths from leukemia",
Q36956 = "Deaths from leprosy",
Q40867 = "Deaths by poisoning",
Q41083 = "Deaths from syphilis",
Q41571 = "Deaths from epilepsy",
Q47790 = "Deaths from tetanus",
Q47912 = "Deaths from lung cancer",
Q48143 = "Deaths from meningitis",
Q83030 = "Deaths from dementia",
Q83319 = "Deaths from typhoid fever",
Q128015 = "People executed by guillotine",
Q128581 = "Deaths from breast cancer",
Q131742 = "Deaths from hepatitis",
Q133462 = "People who committed seppuku",
Q133780 = "Deaths from plague (disease)",
Q134649 = "Deaths from diphtheria",
Q147778 = "Deaths from cirrhosis",
Q152234 = "Deaths from edema",
Q160105 = "Deaths from cervical cancer",
Q160649 = "Deaths from typhus",
Q172341 = "Deaths from ovarian cancer",
Q175111 = "Death by hanging",
Q178275 = "Deaths from Spanish flu",
Q180614 = "Deaths from melanoma",
Q181257 = "Deaths from prostate cancer",
Q181754 = "Deaths from heart failure",
Q183134 = "Deaths from sepsis",
Q188605 = "Deaths from emphysema",
Q188874 = "Deaths from colorectal cancer",
Q189389 = "Deaths from aneurysm",
Q189588 = "Deaths from stomach cancer",
Q190564 = "Deaths from Huntington's disease",
Q190805 = "Deaths from diseases and disorders of the heart",
Q192102 = "Deaths from skin cancer",
Q193840 = "Asphyxia",
Q199804 = "Deaths from chronic obstructive pulmonary disease",
Q200779 = "Deaths from genetic diseases and disorders",
Q202837 = "Deaths from cardiac arrest",
Q204933 = "People executed by decapitation",
Q206901 = "Deaths from amyotrophic lateral sclerosis",
Q208414 = "Deaths from lymphoma",
Q210392 = "Military people killed in action",
Q212961 = "Deaths from pancreatic cancer",
Q220570 = "Deaths from pulmonary embolism",
Q223102 = "Deaths from peritonitis",
Q261327 = "Deaths from thrombosis",
Q275466 = "Deaths from embolism",
Q372701 = "Deaths from esophageal cancer",
Q389735 = "Deaths from diseases and disorders of the cardiovascular system",
Q401402 = "Deaths from nephritis",
Q468455 = "People executed by burning",
Q476921 = "Deaths from kidney failure",
Q504775 = "Deaths from bladder cancer",
Q506616 = "Deaths from drowning",
Q621076 = "Self-immolation",
Q623031 = "Deaths from liver cancer",
Q707774 = "Deaths from coronary thrombosis",
Q744913 = "Victims of aviation accidents or incidents",
Q767485 = "Deaths from respiratory failure",
Q809831 = "BASE jumping deaths",
Q826522 = "Deaths from thyroid cancer",
Q847583 = "Deaths from cardiomyopathy",
Q852423 = "Deaths from laryngeal cancer",
Q857667 = "Deaths from pulmonary edema",
Q929737 = "Deaths from diseases and disorders of the liver",
Q949302 = "Deaths from diseases and disorders of the skin",
Q958797 = "Deaths from scleroderma",
Q970208 = "Deaths from liver failure",
Q977787 = "Deaths from gallbladder cancer",
Q1036696 = "Deaths from hypothermia",
Q1054718 = "Deaths from diseases and disorders of the kidneys",
Q1193870 = "Deaths from multiple organ failure",
Q1198391 = "Deaths from intracranial aneurysm",
Q1209744 = "Deaths from uterine cancer",
Q1368943 = "Deaths from cerebral hemorrhage",
Q1649580 = "Deaths from organ failure",
Q1963588 = "Deaths from diseases and disorders of the blood",
Q2140674 = "Deaths by gunshot",
Q2300099 = "Deaths from diseases and disorders of the digestive system",
Q2509220 = "Deaths from blood cancer",
Q2661443 = "Deaths from diseases and disorders of the endocrine system",
Q2967712 = "Deaths by horse-riding accident",
Q3010352 = "Deaths from diseases and disorders of the cerebrovascular system",
Q3242950 = "Deaths from kidney cancer",
Q3286546 = "Deaths from diseases and disorders of the respiratory system",
Q3339235 = "Deaths from diseases and disorders of the nervous system",
Q3392853 = "Deaths from diseases and disorders of the lungs",
Q3505252 = "Deaths from drug overdose",
-- Q3966286 = "Deaths from executions", -- too unspecific
Q4941552 = "Deaths from diseases and disorders of the skeletal system",
Q5526839 = "Deaths from gastrointestinal cancer",
Q7130407 = "Deaths from diseases and disorders of the pancreas",
Q7258523 = "Deaths in childbirth",
Q7692360 = "Deaths from volcanic eruptions",
Q7900883 = "Deaths from diseases and disorders of the genitourinary system",
Q8084905 = "Deaths from autoimmune diseases and disorders",
Q9303627 = "Deaths from brain cancer",
Q14467705 = "Deaths from surgical complications",
Q15747939 = "People executed by shooting",
Q18123741 = "Deaths from infectious diseases and disorders",
Q18554919 = "Deaths from bone cancer",
Q19403959 = "Victims of rail transport accidents or incidents",
Q55790434 = "Deaths from oral cancer",
-- Q84263196 = "Deaths from COVID-19", -- has a subcategory for every country
})
out[#out+1] = '[[Category:People by name]]'
out[#out+1] = CLAIMS['P570'] and '[[Category:Deceased people by name]]'
out[#out+1] = WikidataIB.getAwardCat{ args = {qid=QID, fwd='ALL', osd=config.osd, noicon='yes'} }
if not CLAIMS['P570'] then
-- This person has no death date, but are they really alive?
local birth = getSingleValue( ITEM, 'P569' )
local year = tonumber( birth and birth.time:gsub('-.*', '') )
if year and os.date('%Y') - year < 100 then
out[#out+1] = '[[Category:Living people]]'
end
end
end
end
return table.concat( out )
end
--- @return string|nil
local function getImage( pid )
local claims = ITEM:getBestStatements( pid )
local claim = getClaimByLang( claims, MYLANG ) or claims[1]
local ms = claim and claim.mainsnak
local file = ms and ms.datavalue and ms.datavalue.value
if file then
local panoramalink = (pid == 'P4640') and '|link=https://panoviewer.toolforge.org/#'..mw.uri.encode(file, 'WIKI') or ''
local img = '<span class="wpImageAnnotatorControl wpImageAnnotatorCaptionOff">[[File:'..file..'|'..config.imagesize..panoramalink..']]</span>' -- equivalent to {{ImageNoteControl | caption=off | type=inline}}
local medialegends = claim.qualifiers and claim.qualifiers['P2096']
if medialegends then
return img .. '<div>'..extractMonolingualText( medialegends )..'</div>'
else
return img -- no image caption
end
end
end
--- Returns images and sitelinks
--- @param uploadlink? boolean: Whether to show the "Upload media" link
local function header( uploadlink )
local imgs = {}
for _, imgPid in ipairs( property_groups[1].pids ) do
local formatted_img = getImage(imgPid)
imgs[#imgs+1] = formatted_img and { imgPid, formatted_img }
end
local switcherContainer = mw.html.create( 'div' )
switcherContainer:addClass( 'switcher-container' )
-- Only show switching labels if we have more than one image to show
if #imgs > 1 then
for _, img in ipairs( imgs ) do
switcherContainer:tag( 'div' )
:addClass( 'center' )
:node( img[2] )
:tag( 'span' )
:attr{ class = "switcher-label", style = "display:none" }
:node( ' ' .. getLabel(img[1]) .. ' ' )
end
elseif #imgs == 1 then
switcherContainer:tag( 'div' )
:addClass( 'center' )
:node( imgs[1][2] )
end
local images = mw.html.create( 'tr' )
images:tag( 'td' )
:attr{ colspan=2, class="wdinfo_nomobile" }
:css( 'text-align', 'center' )
:tag( 'div' )
:node( ITEM:getDescription() or '')
:done()
:node( switcherContainer )
local out = {}
if INSTANCEOF['Q4167410'] or INSTANCEOF['Q15407973'] then -- disambiguation page/category
if config.trackingcats then
out[1] = '[[Category:Uses of Wikidata Infobox for disambig pages]]'
end
elseif uploadlink then
local url = tostring(mw.uri.fullUrl('Special:UploadWizard', {
categories = mw.title.getCurrentTitle().text
}))
local text = mw.message.new('Cx-contributions-upload'):inLanguage(MYLANG):plain()
out[1] = '<tr><td colspan=2 style="text-align:center"><b>['..url..' '..text..']</b></td></tr>'
end
local sitelinks = ITEM.sitelinks
if config.sitelinks and sitelinks then
out[#out+1] = '<tr><td colspan=2 style="text-align:center; font-weight:bold">'
local langId = databaseId(MYLANG)
local langprefix = langId:gsub('_', '-')
local wikis = {
-- wikiId, prefix logo, qid, multilang
{ 'wiki', '', 'Wikipedia-logo-v2', 'Q52', false },
{ 'wikiquote', 'q', 'Wikiquote-logo', 'Q369', false },
{ 'wikisource', 's', 'Wikisource-logo', 'Q263', false },
{ 'wikibooks', 'b', 'Wikibooks-logo', 'Q367', false },
{ 'wikinews', 'n', 'Wikinews-logo', 'Q964', false },
{ 'wikiversity', 'v', 'Wikiversity-logo', 'Q370', false },
{ 'specieswiki', 'species', 'Wikispecies-logo', 'Q13679', true },
{ 'wikivoyage', 'voy', 'Wikivoyage-logo', 'Q373', false },
{ 'metawiki', 'm', 'Wikimedia_Community_Logo', 'Q1063116', true },
}
for _, v in ipairs( wikis ) do
local wikiId, prefix, logo, qid, multilang = unpack( v )
logo = '[[File:'..logo..'.svg|16x16px|alt=|link=]] '
if multilang then
local sitelink = sitelinks[wikiId]
if sitelink then
out[#out+1] = '<div>'..logo..'[['..prefix..':'..sitelink.title..'|'..getLabel(qid)..']]</div>'
end
else
local sitelink = sitelinks[langId .. wikiId]
if sitelink then
out[#out+1] = '<div>'..logo..'[['..prefix..':'..langprefix..':'..sitelink.title..'|'..getLabel(qid)..']]</div>'
end
end
end
out[#out+1] = '</td></tr>'
end
return tostring( images ) .. table.concat( out )
end
--- Returns "Edit at Wikidata" pencil
local function pencil()
local msg, lang = i18n( 'editlink-alttext', FALLBACKLANGS )
local out = mw.html.create( 'tr' )
out
:addClass( "wdinfo_nomobile" )
:tag( 'td' )
:css( 'text-align', 'right' )
:attr{ lang = lang, colspan = 2 }
:node( string.format('[[File:Blue pencil.svg|15px|link=d:%s|%s]]', QID, msg) )
return tostring( out )
end
--- Evaluates all non-image property groups and adds generated HTML rows to
--- the table given as argument.
local function getBodyContent( t )
for i, group in ipairs( property_groups ) do
if i > 1 and groupIsAllowed( group ) then
for _, pid in ipairs( group.pids ) do
if CLAIMS[pid] or group.bypass_property_exists_check then
local x = property_logic[pid] or group.logic or defaultFunc
if type(x) == 'function' then
t[#t+1] = x( pid )
else -- type(x) == 'table'
t[#t+1] = defaultFunc( pid, x )
end
end
end
end
end
end
--- Returns the infobox's main content
local function body()
if not CLAIMS then return '' end
local out = {}
getBodyContent( out )
-- If category combines at most 2 topics, show subinfoboxes for those topics.
-- See Category:Uses_of_Wikidata_Infobox_with_subinfoboxes
local topics = ITEM:getBestStatements( 'P971' )
if not topics or #topics > 2 then return table.concat( out ) end
-- country (Q6256), continent (Q5107), sovereign state (Q3624078), ocean (Q9430)
local geoEntities = { 'Q6256', 'Q5107', 'Q3624078', 'Q9430' }
-- The loop below modifies these variables and restores them afterwards
local qid, item, claims, istaxon, instanceof = QID, ITEM, CLAIMS, ISTAXON, INSTANCEOF
local map
for _, claim in ipairs( topics ) do
QID = claim.mainsnak.datavalue.value.id
ITEM = mw.wikibase.getEntity( QID )
if not ITEM then
out[#out+1] = '[[Category:Uses of Wikidata Infobox for deleted Wikidata items]]'
break
end
CLAIMS = ITEM.claims or {}
ISTAXON = CLAIMS['P105'] or CLAIMS['P171'] or CLAIMS['P225'] or CLAIMS['P1843']
INSTANCEOF = {}
for class in iclaims( ITEM:getBestStatements('P31') ) do
INSTANCEOF[class.id] = true
end
local skip
for _, geoEnt in ipairs( geoEntities ) do
if INSTANCEOF[geoEnt] then
skip = true
map = getCoordinates( 'P625' )
break
end
end
-- Skip if topic is a calendar year (Q3186692) or decade (Q39911)
skip = skip or INSTANCEOF['Q3186692'] or INSTANCEOF['Q39911']
if not skip and #getBestStatements(QID, 'P279') == 0 then -- subclass of
if config.trackingcats then
out[#out+1] = '[[Category:Uses of Wikidata Infobox with subinfoboxes]]'
end
out[#out+1] = '<tr><th colspan=2>'..(ITEM:getLabel() or QID)..'</th></tr>'
out[#out+1] = header( false )
getBodyContent( out )
out[#out+1] = pencil()
end
end
out[#out+1] = map
QID, ITEM, CLAIMS, ISTAXON, INSTANCEOF = qid, item, claims, istaxon, instanceof
return table.concat( out )
end
local function authoritycontrol()
if not config.authoritycontrol then return '' end
local ids = {}
for _, group in ipairs( externalIDs ) do
for _, pid in ipairs( group.pids ) do
if CLAIMS[pid] then
local icon = getSingleValue( pid, 'P2910' )
icon = icon and '[[File:'..icon..'|18px|alt=|link=]] ' or ''
local fmtSt = ITEM:formatStatements( pid )
if fmtSt.value ~= '' then
ids[#ids+1] = icon .. fmtSt.label .. ': ' .. fmtSt.value
end
end
end
end
local wdlogo = '[[File:Wikidata-logo.svg|20px|alt='..getLabel('Q2013')..'|link=d:'..QID..']]'
return table.concat{
'<tr><th style="background: #cfe3ff">',
LANG:ucfirst( getLabel('Q36524') ),
'</th></tr>',
'<tr><td style="text-align: center;">',
'<div style="overflow-wrap: break-word; font-size: smaller">',
wdlogo..' [[d:'..QID..'|'..QID..']]<br>',
'<span class="wdinfo_nomobile">',
table.concat(ids, '<br>'),
'</span>',
'</div>',
'</td></tr>',
}
end
local function helperlinks()
if not config.helperlinks then return '' end
local hl = {}
local title = mw.title.getCurrentTitle()
local pagename = title.text
local pagenamee = mw.uri.encode(pagename, 'WIKI')
local coords = getSingleValue( ITEM, 'P625' )
local otherplanet = coords and coords.globe ~= 'http://www.wikidata.org/entity/Q2'
hl[#hl+1] = '[https://reasonator.toolforge.org/?q='..QID..' '..getLabel('Q20155952')..']'
hl[#hl+1] = '[[toolforge:scholia/'..QID..'|'..getLabel('Q45340488')..']]'
hl[#hl+1] = '[https://wikidocumentaries-demo.wmcloud.org/'..QID..' '..getLabel('Q85947706')..']'
if title.namespace == 14 then
hl[#hl+1] = '[https://petscan.wmflabs.org/?language=commons&categories='..pagenamee..'&project=wikimedia&ns%5B6%5D=1 '..getLabel('Q23665536')..']'
hl[#hl+1] = '[https://glamtools.toolforge.org/glamorgan.html?&category='..pagenamee..'&depth=1&month=last '..getLabel('Q12483')..']'
if not otherplanet then
hl[#hl+1] = '[https://wikimap.toolforge.org/?cat='..pagenamee..'&subcats=true&subcatdepth=1&cluster=true '..getLabel('Q99232292')..']'
hl[#hl+1] = '[https://locator-tool.toolforge.org/#/geolocate?category='..pagenamee..' '..getLabel('Q66498380')..']'
end
end
hl[#hl+1] = '[https://kmlexport.toolforge.org/?project=commons&article='..mw.uri.encode(title.prefixedText)..' '..getLabel('P3096')..']'
if coords and not otherplanet then
hl[#hl+1] = '[https://wikishootme.toolforge.org/#q='..QID..'&main_commons_category='..pagenamee..' '..getLabel('Q26964791')..']'
hl[#hl+1] = '[https://overpass-api.de/api/interpreter?data='..mw.uri.encode('[out:custom];rel[wikidata='..QID..'];if(count(relations)==0){way[wikidata='..QID..'];if(count(ways)==0){node[wikidata='..QID..'];};};out 1;', 'PATH')..' '..getLabel('Q936')..']'
end
for i, v in ipairs( hl ) do
hl[i] = '<span style="white-space:nowrap">' .. v .. '</span>'
end
hl[#hl+1] = '[[Special:Search/haswbstatement:P180='..QID..'|'..i18n('search-depicted', FALLBACKLANGS)..']]'
hl[#hl+1] = ISTAXON and '[https://commons-query.wikimedia.org/#%23defaultView%3AImageGrid%0ASELECT%20%3Ffile%20%3Fimage%0AWITH%20%7B%0A%20%20SELECT%20%3Fitem%20WHERE%20%7B%0A%20%20%20%20SERVICE%20%3Chttps%3A%2F%2Fquery.wikidata.org%2Fsparql%3E%20%7B%0A%20%20%20%20%20%20%20%20%3Fitem%20wdt%3AP171%2Fwdt%3AP171%2a%20wd%3A'..QID..'.%0A%20%20%20%20%7D%20%0A%20%20%7D%0A%7D%20AS%20%25get_items%0AWHERE%20%7B%0A%20%20INCLUDE%20%25get_items%0A%20%20%3Ffile%20wdt%3AP180%20%3Fitem%20.%0A%20%20%3Ffile%20schema%3AcontentUrl%20%3Furl%20.%0A%20%20BIND%28IRI%28CONCAT%28%22http%3A%2F%2Fcommons.wikimedia.org%2Fwiki%2FSpecial%3AFilePath%2F%22%2C%20wikibase%3AdecodeUri%28SUBSTR%28STR%28%3Furl%29%2C53%29%29%29%29%20AS%20%3Fimage%29%0A%7D '..i18n('taxon-depicted', FALLBACKLANGS)..']'
return table.concat{
'<tr class="wdinfo_nomobile">',
'<td colspan=2 style="text-align: center"><small>',
'<div class="hlist hlist-separated"><ul>',
'<li>' .. table.concat(hl, '</li><li>') .. '</li>',
'</ul></div>',
'</small></td>',
'</tr>',
}
end
local function footer()
return (config.authoritycontrol or config.helperlinks) and table.concat{
'<tr><td colspan=2>',
'<table style="width:100%" id="wdinfo_ac" class="mw-collapsible">',
authoritycontrol(),
helperlinks(),
'</table>',
'</td></tr>',
} or ''
end
--- @param eid string: Wikidata entity ID starting with Q or P
local function entityLink( eid )
local label = getLabel( eid, true )
local ns = ( eid:sub(1, 1) == 'P' ) and 'Property:' or ''
return '[[d:'..ns..eid..'|'..label..' <small>('..eid..')</small>]]'
end
--- Generates [[Template:Wikidata Infobox/doc/properties]]
function p.doc()
local out = {}
for _, group in ipairs( property_groups ) do
out[#out+1] = '<h2>' .. group.groupname .. '</h2>'
if group.comment then
out[#out+1] = frame:preprocess( group.comment )
end
if group.P31_allowed_values then
local classes = {}
for _, class in ipairs( group.P31_allowed_values ) do
classes[#classes+1] = entityLink( class )
end
out[#out+1] = 'This group is only shown if the connected Wikidata item is an instance of ' .. table.concat(classes, ' or ') .. '.'
elseif group.humans_allowed then
out[#out+1] = 'This group is always shown (by default, a group is ignored if the connected Wikidata item represents a human).'
end
local props = {}
for _, pid in ipairs( group.pids ) do
props[#props+1] = entityLink( pid )
end
out[#out+1] = table.concat( props, ' • ' )
end
-- authority control
out[#out+1] = '<h2>'..getLabel('Q36524')..'</h2>'
out[#out+1] = 'This group is always shown.'
for _, group in ipairs( externalIDs ) do
out[#out+1] = '<h3>' .. group.groupname .. '</h3>'
local props = {}
for _, pid in ipairs( group.pids ) do
props[#props+1] = entityLink( pid )
end
out[#out+1] = table.concat( props, ' • ' )
end
return table.concat( out, '\n\n' )
end
local function configure( t )
config.defaultsort = t['defaultsort'] == 'y'
config.interwiki = t['interwiki'] == 'yes'
config.autocat = t['autocat'] == 'yes'
config.trackingcats = t['trackingcats'] == 'yes'
config.uploadlink = t['conf_upload'] == 'yes'
config.sitelinks = t['conf_sitelinks'] == 'yes'
config.authoritycontrol = t['conf_authoritycontrol'] == 'yes'
config.helperlinks = t['conf_helperlinks'] == 'yes'
if t['conf_coordtemplate'] then config.coordtemplate = tonumber( t['conf_coordtemplate'] ) end
if t['conf_mapwidth'] then config.mapwidth = t['conf_mapwidth'] end
if t['conf_mapheight'] then config.mapheight = t['conf_mapheight'] end
if t['conf_imagesize'] then config.imagesize = t['conf_imagesize'] end
if t['spf'] then config.spf = t['spf'] end
if t['fwd'] then config.fwd = t['fwd'] end
if t['osd'] then config.osd = t['osd'] end
if t['noicon'] then config.noicon = t['noicon'] end
end
function p.main( frame )
MYLANG = frame:callParserFunction( 'int', 'lang' ) or "en"
LANG = mw.language.new( MYLANG )
FALLBACKLANGS = { MYLANG, unpack(mw.language.getFallbacksFor(MYLANG)) }
QID = frame.args[1]
ITEM = mw.wikibase.getEntity( QID )
if not ITEM then
return '[[Category:Uses of Wikidata Infobox for deleted Wikidata items]]'
end
CLAIMS = ITEM.claims
if not CLAIMS then
local msg = i18n('noclaims', FALLBACKLANGS):gsub('$1', '[[d:'..QID..'|'..QID..']]' )
return '[[Category:Uses of Wikidata Infobox with no claims]]<table id="wdinfobox" dir="'..LANG:getDir()..'" class="fileinfotpl-type-information vevent infobox"><tr><td><strong class="error">'..msg..'</strong></td></tr>'
end
-- identifying a taxon by checking whether it has a taxon property is faster than checking whether its P31 value is a subclass of taxon
ISTAXON = CLAIMS['P105'] or CLAIMS['P171'] or CLAIMS['P225'] or CLAIMS['P1843']
local parentframe = frame:getParent()
if parentframe then
configure( parentframe.args )
end
for class in iclaims( ITEM:getBestStatements('P31') ) do
INSTANCEOF[class.id] = true
end
local out = {
metadata(),
'<table id="wdinfobox" class="fileinfotpl-type-information vevent infobox mw-collapsible" dir="'..LANG:getDir()..'">',
'<caption class="fn org" id="wdinfoboxcaption">',
'<b>' .. (ITEM:getLabel() or QID) .. ' </b>',
'</caption>',
header( config.uploadlink ),
body(),
footer(),
pencil(),
'</table>',
}
if config.trackingcats and os.clock() > 2.5 then -- longer than 2.5 seconds
out[#out+1] = '[[Category:Uses of Wikidata Infobox with bad performance]]'
end
return table.concat( out )
end
function p.debug( qid )
frame.args = { qid or 'Q42' }
return p.main( frame )
end
return p
-- Credits:
-- Original authors: Mike Peel with contributions by Jura1
-- 2022 rewrite: LennardHofmann