Module:Cite Q
From HandWiki
Implements {{Cite Q}}
require('Module:No globals') local wdib = require('Module:WikidataIB') local getValue = wdib._getValue local getPropOfProp = wdib._getPropOfProp local followQid = wdib._followQid local simple_properties = { -- PXXX, is multiple?, linked? publisher = {id="P123", maxvals=1}, oclc = {id="P243", maxvals=1}, place = {id="P291", maxvals=0,linked='no'}, doi = {id="P356", maxvals=1}, issue = {id="P433", maxvals=1, populate_from_journal = true}, pmid = {id="P698", maxvals=1}, arxiv = {id="P818", maxvals=1}, bibcode = {id="P819", maxvals=1}, jstor = {id="P888", maxvals=1}, mr = {id="P889", maxvals=1}, ssrn = {id="P893", maxvals=1}, pmc = {id="P932", maxvals=1}, lccn = {id="P1144", maxvals=1}, hdl = {id="P1184", maxvals=1}, ismn = {id="P1208", maxvals=1}, journal = {id="P1433", maxvals=1}, citeseerx = {id="P3784", maxvals=1}, osti = {id="P3894", maxvals=1}, biorxiv = {id="P3951", maxvals=1}, isbn = {id="P212", maxvals=1, populate_from_journal = true}, -- ISBN 13 issn = {id="P236", maxvals=1, populate_from_journal = true}, chapter = {id="P792", maxvals=1}, ["date"] = {id="P577", maxvals=1, populate_from_journal = true}, series = {id="P179", maxvals=1, populate_from_journal = true}, volume = {id="P478", maxvals=1, populate_from_journal = true}, title = {id="P1476", maxvals=1}, url = {id="P953", maxvals=1}, -- full work available at pages = {id="P304", maxvals=1, populate_from_journal = true}, translator = {id="P655", maxvals=0}, -- does **not** go to "others" section! illustrator = {id="P110", maxvals=0, others=true}, -- goes to "others" section composer = {id="P86", maxvals=0, others=true}, -- goes to "others" section animator = {id="P6942", maxvals=0, others=true}, -- goes to "others" section director = {id="P57", maxvals=0, others=true}, -- goes to "others" section screenwriter = {id="P58", maxvals=0, others=true}, -- goes to "others" section } local citeq = {} --[[--------------------------< I S _ S E T >------------------------------------------------------------------ Returns true if argument is set; false otherwise. Argument is 'set' when it exists (not nil) or when it is not an empty string. ]] local function is_set( var ) return not (var == nil or var == ''); end --[=[-------------------------< G E T _ N A M E _ L I S T >---------------------------------------------------- get_name_list -- adapted from getAuthors code taken from [[Module:RexxS]] arguments: nl_type - type of name list to fetch: nl_type = 'author' for authors; 'editor' for editors args - pointer to the parameter arguments table from the template call qid - value from |qid= parameter; the Q-id of the source (book, etc.) in qid wdl - value from the |wdlinks= parameter; a boolean passed to enable links to Wikidata when no article exists returns nothing; modifies the args table ]=] local function get_name_list (nl_type, args, qid, wdl) local propertyID = "P50" local fallbackID = "P2093" -- author name string if 'author' == nl_type then propertyID = 'P50'; -- for authors fallbackID = 'P2093'; elseif 'editor' == nl_type then propertyID = 'P98'; -- for editors fallbackID = nil; else return; -- not specified so return end -- wdlinks is a boolean passed to enable links to Wikidata when no article exists -- if "false" or "no" or "0" is passed set it false -- if nothing or an empty string is passed set it false if wdl and (#wdl > 0) then wdl = wdl:lower() wdl = (wdl == "false") or (wdl == "no") or (wdl == "0") else -- wdl is empty, so wdl = false end local entity = mw.wikibase.getEntity(qid) local props = nil local fallback = nil if entity and entity.claims then props = entity.claims[propertyID] if fallbackID then fallback = entity.claims[fallbackID] end end -- Make sure it actually has at least one of the properties requested if not (props and props[1]) and not (fallback and fallback[1]) then return nil end -- So now we have something to return: -- table 'out' is going to store the names(s): -- and table 'link' will store any links to the name's article local out = {} local link = {} local maxpos = 0 if props and props[1] then for k, v in pairs(props) do local qnumber = "Q" .. v.mainsnak.datavalue.value["numeric-id"] local sitelink = mw.wikibase.sitelink(qnumber) local label = mw.wikibase.label(qnumber) if label then label = mw.text.nowiki(label) else label = qnumber end local position = maxpos + 1 -- Default to 'next' author. -- use P1545 (series ordinal) instead of default position. if v["qualifiers"] and v.qualifiers["P1545"] and v.qualifiers["P1545"][1] then position = tonumber(v.qualifiers["P1545"][1].datavalue.value) end maxpos = math.max(maxpos, position) if sitelink then -- just the plain name, -- but keep a record of the links, using the same index out[position] = label link[position] = sitelink else -- no sitelink, so check first for a redirect with that label -- this code works, but causes the article to appear in WhatLinksHere for the possible destination, so remove -- local artitle = mw.title.new(label, 0) -- if artitle.id > 0 then -- if artitle.isRedirect then -- no sitelink, -- but there's a redirect with the same title as the label; -- so store the link to that -- out[position] = label -- link[position] = label -- else -- no sitelink and not a redirect but an article exists with the same title as the label -- that's probably a dab page, so output the plain label -- out[position] = label -- end --else -- no article or redirect with the same title as the label if wdl then -- show that there's a Wikidata entry available out[position] = "[[:d:Q" .. v.mainsnak.datavalue.value["numeric-id"] .. "|" .. label .. "]] <span title='" .. i18n["errors"]["local-article-not-found"] .. "'>[[File:Wikidata-logo.svg|16px|alt=|link=]]</span>" else -- no wikidata links wanted, so just give the plain label out[position] = label end -- end end end end if fallback and fallback[1] then -- Fallback to name-only authors / editors for k, v in pairs(fallback) do local label = v.mainsnak.datavalue["value"] local position = maxpos + 1 -- Default to 'next' author. -- use P1545 (series ordinal) instead of default position. if v["qualifiers"] and v.qualifiers["P1545"] and v.qualifiers["P1545"][1] then position = tonumber(v.qualifiers["P1545"][1].datavalue.value) end maxpos = math.max(maxpos, position) out[position] = label end end -- if there's anything to return, then insert the additions in the template arguments table -- in the form |author1=firstname secondname |author2= ... -- Renumber, in case we have inconsistent numbering local keys = {} for k,v in pairs(out) do keys[#keys+1] = k end table.sort(keys) -- as they might be out of order for i, k in ipairs(keys) do mw.log(i.." "..k.." "..out[k]) args[nl_type .. i] = out[k] -- author-n or editor-n if link[k] then args[nl_type .. '-link' .. i] = link[k] -- author-linkn or editor-linkn end end end --[[-------------------------< C I T E _ Q >------------------------------------------------------------------ Takes standard cs1|2 template parameters and passes all to {{citation}}. If neither of |author= and |author1= are set, calls get_authors() to try to get an author name-list from wikidata. The result is passed to {{citation}} for rendering. ]] local function wrap_nowiki(str) return mw.text.nowiki(str or '') end function citeq.cite_q (frame) local citeq_args = {}; for k, v in pairs(frame:getParent().args) do citeq_args[k] = v end for k, v in pairs(frame.args) do citeq_args[k] = v end local qid = citeq_args.qid local wdl = citeq_args.wdl citeq_args.qid = nil citeq_args.wdl = nil local oth = {} citeq_args.language = citeq_args.language or getPropOfProp( {qid = qid, prop1 = "P407", prop2 = "P218", ps = 1} ) if citeq_args.language == '' then citeq_args.language = nil end if not citeq_args.language then -- try fallback to journal's language local journal_qid = followQid({qid = qid, props = "P1433"}) citeq_args.language = journal_qid and getPropOfProp( {qid = journal_qid, prop1 = "P407", prop2 = "P218", ps = 1} ) end for name, data in pairs(simple_properties) do citeq_args[name] = getValue( {data.id, ps = 1, qid = qid, maxvals=data.maxvals, linked=data.linked, citeq_args[name] } ) if data.populate_from_journal then citeq_args[name] = getValue( {"P1433", ps = 1, qid = qid, maxvals=0, citeq_args[name], qual=data.id, qualsonly='yes'} ) citeq_args[name] = citeq_args[name] or getPropOfProp({qid = qid, prop1 = "P1433", prop2 = data.id, maxvals=data.maxvals, ps = 1}) end if citeq_args[name] and citeq_args[name]:find('[[Category:Articles with missing Wikidata information]]', 1, true) then -- try fallback to work's native language citeq_args[name] = getValue( {data.id, ps = 1, qid = qid, maxvals=data.maxvals, linked="no", lang = citeq_args.language } ) if citeq_args[name]:find('^Q%d+$') then -- qid was returned -- try fallback to qid's native language local qid_language = getPropOfProp( {qid = citeq_args[name], prop1 = "P407", prop2 = "P218", ps = 1} ) citeq_args[name] = getValue( {data.id, ps = 1, qid = qid, maxvals=data.maxvals, linked="no", lang = qid_language } ) if citeq_args[name]:find('^Q%d+$') then -- qid was returned again citeq_args[name] = nil end end end if data.others then oth[#oth+1] = citeq_args[name] and (name:gsub("^%l", string.upper) .. ": " .. citeq_args[name]) citeq_args[name] = nil end end citeq_args.others = citeq_args.others or table.concat(oth, ". ") citeq_args.journal = citeq_args.journal and citeq_args.journal:gsub("^''", ""):gsub("''$", ""):gsub("|''", "|"):gsub("'']]", "]]") citeq_args.ol = (getValue( {"P648", ps = 1, qid = qid, maxvals=1, citeq_args.ol } ) or ''):gsub("^OL(.+)$", "%1") citeq_args.biorxiv = citeq_args.biorxiv and ("10.1101/" .. citeq_args.biorxiv) citeq_args.isbn = getValue( {"P957", ps = 1, qid = qid, maxvals=0, citeq_args.isbn } ) -- try ISBN 10 citeq_args.url = getValue( {"P856", ps = 1, qid = qid, maxvals=0, citeq_args.url } ) -- try official website citeq_args.url = getValue( {"P2699", ps = 1, qid = qid, maxvals=0, citeq_args.url } ) -- try url local slink = mw.wikibase.getSitelink(qid) local label = mw.wikibase.getLabel(qid) or citeq_args.language and mw.wikibase.getLabelByLang(qid, citeq_args.language) if citeq_args.title then if slink then citeq_args.url = nil citeq_args.title = '[[' .. slink .. '|' .. wrap_nowiki(citeq_args.title) .. ']]' else citeq_args.title = wrap_nowiki(citeq_args.title) end else if slink then citeq_args.url = nil if slink:lower() == label:lower() then citeq_args.title = '[[' .. slink .. ']]' else citeq_args.title = '[[' .. slink .. '|' .. wrap_nowiki(slink:gsub("%s%(.+%)$", ""):gsub(",.+$", "")) .. ']]' end else citeq_args.title = wrap_nowiki(label) end end if citeq_args.p or citeq_args.page then citeq_args.pages = nil end if citeq_args.pages then local _, count = string.gsub(citeq_args.pages, " %d+", "") if count == 1 then citeq_args.p = citeq_args.pages citeq_args.pages = nil end end for k, v in pairs(citeq_args) do if v == 'unset' or type(k) ~= 'string' then citeq_args[k] = nil end end if is_set (qid) then if not is_set (citeq_args.author) and not is_set (citeq_args.author1) then -- if neither are set, try to get authors from wikidata get_name_list ('author', citeq_args, qid, wdl); -- modify citeq_args table with authors from wikidata end if not is_set (citeq_args.editor) and not is_set (citeq_args.editor1) then -- if neither are set, try to get editors from wikidata get_name_list ('editor', citeq_args, qid, wdl); -- modify citeq_args table with editors from wikidata end end local author_count = 0 for k, v in pairs(citeq_args) do if k:find("^author%d+$") then author_count = author_count + 1 end end if author_count > 8 then -- convention in astronomy journals citeq_args['display-authors'] = citeq_args['display-authors'] or 3 end local editor_count = 0 for k, v in pairs(citeq_args) do if k:find("^editor%d+$") then editor_count = editor_count + 1 end end if editor_count > 8 then -- convention in astronomy journals citeq_args['display-editors'] = citeq_args['display-editors'] or 3 end local returntext = frame:expandTemplate{title = 'citation', args = citeq_args} -- render the template if citeq_args.mode ~= 'cs1' then returntext = returntext .. ',' end returntext = returntext .. ' [[WDQ (identifier)|Wikidata]] [[:d:' .. qid .. '|' .. qid .. ']]' -- go through special "WDQ (identifier)" redirect to reduce clutter in "What links here" and improve reverse lookup. (A better name might be "QID (identifier)", but needs to be kept in sync with what's used by Template:QID.) return returntext end return citeq