Module:Cite Q
Appearance
(Redirected from Module:Citeq)
![]() | This Lua module is used on approximately 54,000 pages and changes may be widely noticed. Test changes in the module's /sandbox or /testcases subpages, or in your own module sandbox. Consider discussing changes on the talk page before implementing them. |
Implements {{Cite Q}}
Test cases at:
-- Version: 2021-10-19localp={}require('strict')localwdib=require('Module:WikidataIB')localgetValue=wdib._getValuelocalgetPropOfProp=wdib._getPropOfProplocalfollowQid=wdib._followQidlocalgetPropertyIDs=wdib._getPropertyIDslocali18n={["unknown-author"]=mw.wikibase.getLabel("Q4233718"):gsub("^%l",mw.ustring.upper),["unknown-author-trackingcat"]="",-- [[Category:Cite Q - author unknown]] removed as misplaced; someone is welcome to restore it if it is placed outside of the template parameter value["ordinal"]={[1]="st",[2]="nd",[3]="rd",["default"]="th"},["months"]={"January","February","March","April","May","June","July","August","September","October","November","December"},}--------------------------------------------------------------------------------- makeOrdinal needs to be internationalised along with the above i18n-- takes cardinal number as a numeric and returns the ordinal as a string-- we need three exceptions in English for 1st, 2nd, 3rd, 21st, .. 31st, etc.-------------------------------------------------------------------------------p.makeOrdinal=function(cardinal)localcard=tonumber(cardinal)ifnotcardthenreturncardinalendlocalordsuffix=i18n.ordinal.defaultifcard%10==1thenordsuffix=i18n.ordinal[1]elseifcard%10==2thenordsuffix=i18n.ordinal[2]elseifcard%10==3thenordsuffix=i18n.ordinal[3]end-- In English, 1, 21, 31, etc. use 'st', but 11, 111, etc. use 'th'-- similarly for 12 and 13, etc.if(card%100==11)or(card%100==12)or(card%100==13)thenordsuffix=i18n.ordinal.defaultendreturncard..ordsuffixend-- Table of simple properties that can be fetched in roughly the same way:-- id = PXXX-- maxvals = maximum number of multiple values (0 for all)-- linked = "no" suppresses linking-- populate_from_journal = true/false determines whether to look in a journal where the source is published-- rank = "best", "preferred", normal, etc. determines how Wikidata ranks are treated-- others = true - the value for the property goes to "others" sectionlocalsimple_properties={publisher={id="P123",maxvals=1},oclc={id="P243",maxvals=1},['publication-place']={id="P291",maxvals=0,linked='no'},-- publication place (don't put into |place=; is treated specially in {{citation}} if both are given)doi={id="P356",maxvals=1},-- take care of |doi-broken-date= (WD "reason for deprecation"/"stated as") and |doi-access= (WD "access status")?issue={id="P433",maxvals=0,populate_from_journal=true},-- distinguish from |number= ("P1545"?) if both are given (still blocked by {{citation}}, but will be supported in the future)pmid={id="P698",maxvals=1},-- gbooks = {id = "P675", maxvals = 1}, -- to be added to {{citation}}-- ia = {id = "P724", maxvals = 1}, -- to be added to {{citation}}arxiv={id="P818",maxvals=1},bibcode={id="P819",maxvals=1},-- take care of |bibcode-access=?jstor={id="P888",maxvals=1},-- take care of |jstor-access=?mr={id="P889",maxvals=1},rfc={id="P892",maxvals=1},zbl={id="P894",maxvals=1},ssrn={id="P893",maxvals=1},place={id="P1071",maxvals=0,linked='no'},-- written-at place-- ['total-pages'] = {id = "P1104", maxvals = 0, linked = 'no'}, -- to be added to {{citation}} / COinS &rft.tpages=-- coden = {id = "P1159", maxvals = 1}, -- to be added to {{citation}} / COinS &rft.coden=s2cid={id="P8299",maxvals=1},-- take care of |s2cid-access=?pmc={id="P932",maxvals=1},-- take care of |pmc-embargo-date= (WD "reason for deprecation")?lccn={id="P1144",maxvals=1},hdl={id="P1184",maxvals=1},-- take care of |hdl-access=?ismn={id="P1208",maxvals=1},journal={id="P1433",maxvals=1},citeseerx={id="P3784",maxvals=1},osti={id="P3894",maxvals=1},-- take care of |osti-access=?biorxiv={id="P3951",maxvals=1},asin={id="P5749",maxvals=1},-- What about |asin-tld=? (WD examples resolve to .com at present, but may change)-- ['catalog-number'] = {id = "P528", maxvals = 0}, -- to be added to {{citation}} / COinS &rft.artnum=isbn={id="P212",maxvals=1,populate_from_journal=true},-- ISBN 13issn={id="P236",maxvals=1,populate_from_journal=true},-- distinguish from |eissn= for electronic issues?-- jfm = {id = "P?", maxvals = 1}, -- Jahrbuch über die Fortschritte der Mathematik (not Zbl)-- sbn = {id = "P?", maxvals = 1}, -- Standard Book Number (predecessor of ISBN, not ICCU)-- message-id = {id = "P?", maxvals = 1}, -- Usenet message IDchapter={id="P792",maxvals=1},['publication-date']={id="P577",maxvals=1,populate_from_journal=true},-- publication date (don't use |date=; is treated specially in {{citation}} if both are given.)series={id="P179",maxvals=1,populate_from_journal=true},version={id="P348",maxvals=0},edition={id="P393",maxvals=0},volume={id="P478",maxvals=0,populate_from_journal=true},-- part = {id = "P1545"?, maxvals = 0}, -- to be added to {{citation}} / COinS &rft.part=title={id="P1476",rank="p n"},-- url = {id = "P953", maxvals = 1}, -- deal with this along with archive-urlpages={id="P304",maxvals=0,populate_from_journal=true},at={id="P958",maxvals=0,populate_from_journal=true},-- also incorporate lines (P7421) and columns (P3903) into this (cite map also supports |section=)-- sheets = {id = "P7416", maxvals = 0, populate_from_journal = true},-- interviewer = {id = "P?", maxvals = 0}, -- does **not** go to "others" section! Multiple interviewers should be n-enumeratedillustrator={id="P110",maxvals=10,others=true},-- goes to "others" section-- foreword and afterword, when contributions to another author's work, are contributions so belong in |contribution=;-- the writer's name goes in |contributor=; requires |title= and |author=-- However, this might need to add support for multiple contributors and their roles to {{citation}}, see Help_talk:Citation_Style_1#Others-- foreword = {id = "P2679", maxvals = 10, others = true}, -- goes to "others" section-- afterword = {id = "P2680", maxvals = 10, others = true}, -- goes to "others" sectioncomposer={id="P86",maxvals=10,others=true},-- goes to "others" sectionanimator={id="P6942",maxvals=10,others=true},-- goes to "others" sectiondirector={id="P57",maxvals=10,others=true},-- goes to "others" sectionscreenwriter={id="P58",maxvals=10,others=true},-- goes to "others" sectionsignatory={id="P1891",maxvals=10,others=true},-- goes to "others" sectionpresenter={id="P371",maxvals=10,others=true},-- goes to "others" sectionperformer={id="P175",maxvals=10,others=true},-- goes to "others" section}--[[--------------------------< 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.]]localfunctionis_set(var)returnnot(var==nilorvar=='')end--[[--------------------------< I N _ A R R A Y >--------------------------------------------------------------Whether needle is in haystack (taken from Module:Citation/CS1/Utilities)]]localfunctionin_array(needle,haystack)ifneedle==nilthenreturnfalseendforn,vinipairs(haystack)doifv==needlethenreturnnendendreturnfalseend--[[--------------------------< A C C E P T _ V A L U E >-------------------------------------------------------Accept WD value by framing in ((...)) if param_val is equal to keyword; else pass-through WD value as is.]]localfunctionaccept_value(param_val,wd_val)localval=param_valifvalthenifin_array(val,{'accept','))((',':d:'})thenval='(('..wd_val..'))'elseif'((accept))'==valthenval='accept'elseif'(())(())'==valthenval='))(('elseif'((:d:))'==valthenval=':d:'elseval=wd_valendendreturnvalend-- function to fetch a value to displaylocalfunctionmakelink(v,out,link,maxpos,wdl)locallabelifv.mainsnak.snaktype=="value"thenifv.mainsnak.datatype=="wikibase-item"thenlocalqnumber=v.mainsnak.datavalue.value.idlocalsitelink=mw.wikibase.getSitelink(qnumber)ifqnumber=="Q2818964"thensitelink=nilend-- suppress link to "Various authors"ifv.qualifiersandv.qualifiers.P1932thenlabel=v.qualifiers.P1932[1].datavalue.valueelselabel=mw.wikibase.getLabel(qnumber)iflabelthenlabel=mw.text.nowiki(label)elselabel=qnumber-- should add tracking categoryendendlocalposition=maxpos+1-- Default to 'next' author.-- use P1545 (series ordinal) instead of default position.ifv["qualifiers"]andv.qualifiers["P1545"]andv.qualifiers["P1545"][1]thenposition=tonumber(v.qualifiers["P1545"][1].datavalue.value)endmaxpos=math.max(maxpos,position)ifsitelinkthen-- just the plain name,-- but keep a record of the links, using the same indexout[position]=labellink[position]=sitelinkelseifwdlthen-- show that there's a Wikidata entry availableout[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 labelout[position]=labelendendelseifv.mainsnak.datatype=="string"thenlocalposition=maxpos+1-- Default to 'next' author.-- use P1545 (series ordinal) instead of default position.ifv["qualifiers"]andv.qualifiers["P1545"]andv.qualifiers["P1545"][1]thenposition=tonumber(v.qualifiers["P1545"][1].datavalue.value)endmaxpos=math.max(maxpos,position)out[position]=v.mainsnak.datavalue.valueelse-- not a wikibase-item or a string!endelse-- code here if we want to return something when author is "unknown"ifv.qualifiersandv.qualifiers.P1932thenlabel=v.qualifiers.P1932[1].datavalue.valueelselabel=i18n["unknown-author"]..(i18n["unknown-author-trackingcat"]or"")endmaxpos=maxpos+1out[maxpos]=labelendreturnmaxposend--[=[-------------------------< G E T _ N A M E _ L I S T >----------------------------------------------------get_name_list -- adapted from getAuthors code taken from Module:RexxSarguments: nl_type - type of name list to fetch: nl_type = 'author' for authors; 'editor' for editors; 'translator' for translators 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 |wdl= parameter; a Boolean passed to enable links to Wikidata when no article existsreturns nothing; modifies the args table]=]localfunctionget_name_list(nl_type,args,qid,wdl)localpropertyID="P50"localfallbackID="P2093"-- author name stringifnl_type=="author"thenpropertyID='P50'-- for authorsfallbackID='P2093'-- author-stringelseifnl_type=="editor"thenpropertyID='P5769'-- "editor-in-chief"fallbackID='P98'-- for editors - So-called "fallbacks" are actually a second set of properties processed-- TBD. Take book series editors into account as well (if they have a separate P code as well)?elseifnl_type=="translator"thenpropertyID='P655'-- for translatorsfallbackID=nil-- elseif 'contributor' == nl_type then-- f.e. author of forewords (P2679) and afterwords (P2680); requires |contribution=, |title= and |author=-- propertyID = 'P' -- for contributors-- fallbackID = nilelsereturn-- not specified so returnend-- wdl 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 falseifwdland(#wdl>0)thenwdl=wdl:lower()wdl=in_array(wdl,{"false","no","0"})else-- wdl is empty, sowdl=falseendlocalprops=nillocalfallback=nilifmw.wikibase.entityExists(qid)thenprops=mw.wikibase.getAllStatements(qid,propertyID)ifpropsandfallbackIDthenfallback=mw.wikibase.getAllStatements(qid,fallbackID)endend-- Make sure it actually has at least one of the properties requestedifnot(propsandprops[1])andnot(fallbackandfallback[1])thenreturnnilend-- 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 articlelocalout={}locallink={}localmaxpos=0ifpropsandprops[1]thenfork,vinpairs(props)domaxpos=makelink(v,out,link,maxpos,wdl)endendiffallbackandfallback[1]then-- second propertiesfork,vinpairs(fallback)domaxpos=makelink(v,out,link,maxpos,wdl)endend-- 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 numberinglocalkeys={}fork,vinpairs(out)dokeys[#keys+1]=kendtable.sort(keys)-- as they might be out of orderfori,kinipairs(keys)doout[k]=out[k]:gsub(''','\'');-- prevent cs1|2 multiple names categorization; replace html entity with the actual charactermw.log(i.." "..k.." "..(out[k]))ifargs[nl_type..i]then-- name gets overwritten-- pull corresponding -link only if overwritten name is same as WD nameiflink[k]and(args[nl_type..i]==out[k])thenargs[nl_type..'-link'..i]=args[nl_type..'-link'..i]orlink[k]-- author-linkn or editor-linknendelse-- name does not get overwritten, so pull name from WDargs[nl_type..i]=out[k]iflink[k]thenargs[nl_type..'-link'..i]=args[nl_type..'-link'..i]orlink[k]-- author-linkn or editor-linknendendendend-- gets language codes used for a monolingual text property as a tablefunctionp._getLangOfProp(qid,pid)ifnotpidthenreturn{}endlocalout={}localprops=mw.wikibase.getAllStatements(qid,pid)fori,vinipairs(props)doifv.mainsnak.datatype=="monolingualtext"andv.mainsnak.datavaluethenout[#out+1]=v.mainsnak.datavalue.value.languageendendreturnoutendfunctionp.getLangOfProp(frame)localpid=frame.args.pidormw.text.trim(frame.args[1]or"")ifpid==""thenreturnendlocalqid=frame.args.qidifqid==""thenqid=nilendreturntable.concat(p._getLangOfProp(qid,pid),", ")end-- gets the language codes of a Wikidata entry as a tablelocalfunction_lang_code(qid)locallc=getPropOfProp({qid=qid,prop1="P407",prop2="P424",ps=1})iflcthenreturnmw.text.split(lc,"[, ]+")endlc=getPropOfProp({qid=qid,prop1="P407",prop2="P218",ps=1})iflcthenreturnmw.text.split(lc,"[, ]+")endreturnp._getLangOfProp(qid,"P1476")endfunctionp.lang_code(frame)returntable.concat(_lang_code(frame.args.qidormw.text.trim(frame.args[1]or"")),", ")end-- export for debugfunctionp.getPropOfProp(frame)returngetPropOfProp(frame.args)end-- wraps a string in nowiki unless disable flag is setlocalfunctionwrap_nowiki(str,disable)ifdisablethenreturnstror''endreturnmw.text.nowiki(stror'')end-- sort sequence table whose values are key-value pairs by keylocalfunctioncomp_key(a,b)returna[1]<b[1]end-- sort sequence table whose values are key-value pairs by valuelocalfunctioncomp_val(a,b)returna[2]<b[2]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.--]]functionp._cite_q(citeq_args)localframe=mw.getCurrentFrame()-- parameters that don't get passed to Citationlocalexpand=citeq_args.expand-- when set to anything, causes {{cite q}} to render <code><nowiki>{{citation|...}}</nowiki></code>localqid=citeq_args.qidorciteq_args[1]localwdl=citeq_args.wdllocaltemplate=citeq_args.templateciteq_args.expand=nilciteq_args[1]=nilciteq_args.qid=nilciteq_args.wdl=nilciteq_args.template=nil-- if title supplied, flag to not read html titlelocaltitleforced=(citeq_args.title~=nil)localoth={}-- put the language codes into a sequential table langcodes[]locallangcodes={}ifciteq_args.languagethen-- check these are a supported language codesforlcinmw.text.gsplit(citeq_args.language,"[, ]+",false)dolangcodes[#langcodes+1]=mw.language.isSupportedLanguage(citeq_args.language)andciteq_args.languageendendifnotlangcodes[1]then-- try to find language of worklangcodes=_lang_code(qid)endifnotlangcodes[1]then-- try fallback to journal's languagelocaljournal_qid=followQid({qid=qid,props="P1433"})langcodes=journal_qidand_lang_code(journal_qid)endciteq_args.language=citeq_args.languageortable.concat(langcodes,", ")-- loop through list of simple properties and get their values in citeq_argsforname,datainpairs(simple_properties)dociteq_args[name]=getValue({data.id,fwd="ALL",osd="no",noicon="true",qid=qid,maxvals=data.maxvals,linked=data.linked,rank=data.rankor"best",citeq_args[name]})ifdata.populate_from_journalthenlocalpublishedin=getValue({"P1433",ps=1,qid=qid,maxvals=0,citeq_args[name],qual=data.id,qualsonly='yes'})citeq_args[name]=publishedinorgetPropOfProp({qid=qid,prop1="P1433",prop2=data.id,maxvals=data.maxvals,ps=1})endifciteq_args[name]andciteq_args[name]:find('[[Category:Articles with missing Wikidata information]]',1,true)then-- try fallback to work's native languageciteq_args[name]=getValue({data.id,ps=1,qid=qid,maxvals=data.maxvals,linked="no",lang=langcodes[1]})ifciteq_args[name]:find('^Q%d+$')then-- qid was returned-- try fallback to qid's native languagelocalqid_languages=_lang_code(citeq_args[name])citeq_args[name]=getValue({data.id,ps=1,qid=qid,maxvals=data.maxvals,linked="no",lang=qid_languages[1]})ifciteq_args[name]:find('^Q%d+$')then-- qid was returned againciteq_args[name]=nilelse-- record the language found if no lang specifiedciteq_args.language=citeq_args.languageorqid_languages[1]endendendifdata.othersthenoth[#oth+1]=citeq_args[name]and(name:gsub("^%l",string.upper)..": "..citeq_args[name])citeq_args[name]=nilendendciteq_args.others=citeq_args.othersortable.concat(oth,". ")ifciteq_args.others==""thenciteq_args.others=nilendciteq_args.journal=citeq_args.journalandciteq_args.journal:gsub("^''",""):gsub("''$",""):gsub("|''","|"):gsub("'']]","]]")citeq_args.ol=(getValue({"P648",ps=1,qid=qid,maxvals=1,citeq_args.ol})or''):gsub("^OL(.+)$","%1")ifciteq_args.ol==""thenciteq_args.ol=nilend-- TBD. Take care of |ol-access=?citeq_args.biorxiv=citeq_args.biorxivand("10.1101/"..citeq_args.biorxiv)citeq_args.isbn=getValue({"P957",ps=1,qid=qid,maxvals=1,rank="best",citeq_args.isbn})-- try ISBN 10 (only one value accepted)-- if url then see if there's an archive: citeq_args.urllocalurlifnotciteq_args.urlthenfori,prinipairs({"P953","P856","P2699"})dourl=getValue({pr,ps=1,qid=qid,maxvals=1,qual="P1065"})ifurlthenciteq_args.url=mw.text.split(url," (",true)[1]localarcurl=mw.ustring.match(url," %((.*)%)")-- when there is an archive url, <url> holds: url<space>(archive url); here extract the archive url if presentifarcurlthenlocalarcy,arcm,arcd=arcurl:match("(20%d%d)%p?(%d%d)%p?(%d%d)")ifarcyandarcmandarcdthenciteq_args["archive-url"]=arcurlciteq_args["archive-date"]=tonumber(arcd).." "..i18n.months[tonumber(arcm)].." "..arcyendendbreakendendendifciteq_args.publisher=="Unknown"then-- look for "stated as" (P1932)localstated_as=getValue({"P123",ps=1,qid=qid,maxvals=1,qual="P1932",qo="y"})ifstated_asthenciteq_args.publisher=stated_asendendifnottitleforcedthen-- Handle subtitle.ifciteq_args.titlethenlocalsubtitle=mw.wikibase.getBestStatements(qid,'P1680');if0~=#subtitlethensubtitle=subtitle[1].mainsnak.datavalue.value.text;citeq_args.title=citeq_args.title..": "..subtitleendendlocalhtmltitle=getValue({"P1476",qual="P6833",ps=1,qid=qid,maxvals=1,qo="y"})ifhtmltitlethenciteq_args.title=htmltitle:gsub("</?i>","''")elselocaltitle_display=citeq_args.titleormw.wikibase.getLabel(qid)or(langcodes[1]andmw.wikibase.getLabelByLang(qid,langcodes[1]))or("No label or title -- debug: "..qid)ifciteq_args.urlthenciteq_args.title=wrap_nowiki(title_display)elselocalslink=mw.wikibase.getSitelink(qid)localslink_flag=falselocalwrap_title=''localwslink=falseifnotslinkthen-- See if we have wikisourceifnotciteq_args.urlthenlocalwikisource_sitelink=mw.wikibase.getSitelink(qid,"enwikisource")ornilifwikisource_sitelinkthenslink=':s:'..wikisource_sitelinkwslink=trueendendendifciteq_args.titlethenifslinkthenwrap_title=wrap_nowiki(citeq_args.title)slink_flag=trueelseciteq_args.title=wrap_nowiki(citeq_args.title)endelseifslinkandnotwslinkthenifslink:lower()==title_display:lower()thenciteq_args.title='[['..slink..']]'elsewrap_title=wrap_nowiki(slink:gsub("%s%(.+%)$",""):gsub(",.+$",""))slink_flag=trueendelseifwslinkthenwrap_title=wrap_nowiki(title_display)slink_flag=trueelseciteq_args.title=wrap_nowiki(title_display)endendifslink_flagthenifslink==wrap_titleandnotwslinkthen-- direct linkciteq_args.title='[['..slink..']]'else-- piped linkciteq_args.title='[['..slink..'|'..wrap_title..']]'endendendendend-- TBD: incorporate |at, |sheets= and |sheet= here as well-- Sort out what should happen if several of them are given at the same timeifciteq_args.pageorciteq_args.pthen-- let single take precedence over multipleciteq_args.pages=nilciteq_args.pp=nilendifciteq_args.pagesthenlocal_,count=string.gsub(citeq_args.pages,"[,;%s]%d+","")ifcount==1thenciteq_args.page=citeq_args.pagesciteq_args.pages=nilendendifis_set(qid)thenifnotis_set(citeq_args.author)andnotis_set(citeq_args.author1)andnotis_set(citeq_args.subject)andnotis_set(citeq_args.subject1)andnotis_set(citeq_args.host)andnotis_set(citeq_args.host1)andnotis_set(citeq_args.last)andnotis_set(citeq_args.last1)andnotis_set(citeq_args.surname)andnotis_set(citeq_args.surname1)andnotis_set(citeq_args['author-last'])andnotis_set(citeq_args['author-last1'])andnotis_set(citeq_args['author1-last'])andnotis_set(citeq_args['author-surname'])andnotis_set(citeq_args['author-surname1'])andnotis_set(citeq_args['author1-surname1'])then-- if neither are set, try to get authors from Wikidataget_name_list('author',citeq_args,qid,wdl)-- modify citeq_args table with authors from Wikidataendifnotis_set(citeq_args.editor)andnotis_set(citeq_args.editor1)andnotis_set(citeq_args['editor-last'])andnotis_set(citeq_args['editor-last1'])andnotis_set(citeq_args['editor1-last'])andnotis_set(citeq_args['editor-surname'])andnotis_set(citeq_args['editor-surname1'])andnotis_set(citeq_args['editor1-surname'])then-- if neither are set, try to get editors from Wikidataget_name_list('editor',citeq_args,qid,wdl)-- modify citeq_args table with editors from Wikidataendifnotis_set(citeq_args.translator)andnotis_set(citeq_args.translator1)andnotis_set(citeq_args['translator-last'])andnotis_set(citeq_args['translator-last1'])andnotis_set(citeq_args['translator1-last'])andnotis_set(citeq_args['translator-surname'])andnotis_set(citeq_args['translator-surname1'])andnotis_set(citeq_args['translator1-surname'])then-- if neither are set, try to get translators from Wikidataget_name_list('translator',citeq_args,qid,wdl)-- modify citeq_args table with translators from Wikidataendendfork,vinpairs(citeq_args)doifin_array(v,{'(())','unset','ignore'})or'string'~=type(k)then-- empty accept-as-is-written (()) markup to indicate an empty/unused parameter value, other ((...)) markups are deliberately passed down to {{citation}}citeq_args[k]=nilelseifin_array(v,{'((unset))','((ignore))'})then-- strip off markup for free-text values clashing with local keywordsciteq_args[k]='unset'endendlocalauthor_count=0fork,vinpairs(citeq_args)doifk:find("^author%d+$")thenauthor_count=author_count+1endendifauthor_count>8then-- convention in astronomy journals, optional mode for this?if'all'==citeq_args['display-authors']thenciteq_args['display-authors']=nil;-- unset because no longer neededelseciteq_args['display-authors']=citeq_args['display-authors']or3-- limit to three displayed namesendendlocaleditor_count=0fork,vinpairs(citeq_args)doifk:find("^editor%d+$")theneditor_count=editor_count+1endendifeditor_count>8then-- convention in astronomy journals, optional mode for this?if'all'==citeq_args['display-editors']thenciteq_args['display-editors']=nil;-- unset because no longer neededelseciteq_args['display-editors']=citeq_args['display-editors']or3-- limit to three displayed namesendend-- change edition to ordinal if it's set and numericciteq_args.edition=citeq_args.editionandp.makeOrdinal(citeq_args.edition)-- code to make a guess what template to use from the supplied parameters-- (first draft for proof-of-concept)ifciteq_args.isbnthentemplate=templateor"book"citeq_args.asin=nil-- suppress ASIN if ISBN existselseifciteq_args.journalthentemplate=templateor"journal"elseifciteq_args.websitethentemplate=templateor"web"end-- template is CS1 designator: journal, web, news, etc.iftemplatethen-- citeq_args.mode = citeq_args.mode or "cs1" -- a cs1 template already knows that it is cs1 so this line is superfluoustemplate="Cite "..templateelse-- citeq_args.mode = citeq_args.mode or "cs2" -- a cs2 template already knows that it is cs2 so this line is superfluoustemplate="Citation"end-- |id= could hold more than one identifier pulled from Wikidata not supported by {{citation}}, right now only add our qid to the listlocallist_sep='. 'ifciteq_args.mode~='cs1'thenlist_sep=', 'endlocalid='[[WDQ (identifier)|Wikidata]] [[:d:'..qid..'|'..qid..']]'-- go through "WDQ (identifier)" redirect to reduce clutter in "What links here" and improve reverse lookup. Keep in sync with {{QID}}.localold_id=citeq_args.idifwdlthen-- show WD logoid=id..'[[File:Wikidata-logo.svg|16px|alt=|link=]]'-- possibly replace by WD edit icon?endifis_set(old_id)thenciteq_args.id=old_id..list_sep..id-- append to user-specified contentselseciteq_args.id=idend-- clean up any blank parametersfork,vinpairs(citeq_args)doifv==""thenciteq_args[k]=nilendend-- if |expand=<anything>, write a nowiki'd version to see what the {{citation}} template call looks likeifexpandthenlocalexpand_args={"{{"..template}-- init with citation templateifexpand=="self"thenciteq_args.id=old_id-- restore original |id= parameterexpand_args={"{{cite Q|"..qid}-- expand to itselfend-- make a sortable table and sort it by param namelocalsorttable={}forparam,valinpairs(citeq_args)dotable.insert(sorttable,{param,val})endtable.sort(sorttable,comp_key)-- add contents to expand_argsforidx,valinipairs(sorttable)dotable.insert(expand_args,val[1]..'='..val[2])end-- make the nowiki'd string and donereturnframe:preprocess(table.concat({'<syntaxhighlight lang="wikitext" inline="1">',table.concat(expand_args,' |')..'}}','</syntaxhighlight>'}));endlocalerratumid=getPropertyIDs({"P2507",qid=qid,fwd="ALL",osd="no",rank="best",maxvals=1})iferratumidthenerratumid=" [[d:"..erratumid.."|(erratum)]]".."[[Category:Cite Q - cites a work with an erratum]]"elseerratumid=""endlocalopt_cat=''ifgetValue({"P5824",ps=1,qid=qid})thenopt_cat='[[Category:Cite Q - cites a retracted work]]<!-- retracted -->'endifgetValue({"P1366",ps=1,qid=qid})thenopt_cat=opt_cat..'[[Category:Cite Q - cites a replaced work]]<!-- replaced -->'endreturnframe:expandTemplate{title=template,args=citeq_args}..erratumid..opt_cat-- render the templateendfunctionp.cite_q(frame)localargs={}fork,vinpairs(frame:getParent().args)doifv~=""thenargs[k]=vendendfork,vinpairs(frame.args)doifv~=""thenargs[k]=vendendargs.qid=args.qidorargs[1]or""ifargs.qid==""thenreturnnilendargs[1]=nillocalcitesep=(args.citesepor"")ifcitesep==""thencitesep=", "endcitesep=citesep:gsub('"','')-- strip double quotes after setting default to allow |citesep="" as a blank separatorargs.citesep=nillocaltag=args.tagor""iftag==""thentag=nilendargs.tag=nillocallist=args.listor""iflist==""thenlist=nilendargs.list=nilargs.language=args.languageorargs.langargs.lang=nillocalcites={}forqinargs.qid:gmatch("Q%d+")do-- make a new copy of the argumentslocalnewargs={}fork,vinpairs(args)doifk~="qid"thennewargs[k]=vendendnewargs.qid=qiftag=="ref"thencites[#cites+1]=frame:callParserFunction{name="#tag:ref",args={p._cite_q(newargs),name=q}}-- expand like this: args = { p._cite_q(newargs), name = 'foo', group = 'bar' }elsecites[#cites+1]=p._cite_q(newargs)endendiflistthenreturnframe:expandTemplate{title=list,args=cites}elsereturntable.concat(cites,citesep)endendreturnp