Wikipedia igwiki https://ig.wikipedia.org/wiki/Ihu_mb%E1%BB%A5 MediaWiki 1.47.0-wmf.23 first-letter Midia Ọpụrụiche Ńkàtá Ojiarụ Ńkàtá ojiarụ Wikipedia Ńkàtá Wikipedia Faịlụ Ńkàtá faịlụ MidiaWiki Ńkàtá MidiaWiki Templeeti Ńkàtá templeeti Enyemaka Ńkàtá enyemaka Otú Ńkàtá otú Édēchághị́ Ńkàtá Édēchághị́ TimedText TimedText talk Module Module talk Event Event talk Module:List 828 10413 736706 599243 2026-09-12T00:43:13Z JJMC89 6760 move was reverted 736706 Scribunto text/plain local libUtil = require('libraryUtil') local checkType = libUtil.checkType local mTableTools = require('Module:TableTools') local p = {} local listTypes = { ['bulleted'] = true, ['unbulleted'] = true, ['horizontal'] = true, ['ordered'] = true, ['horizontal_ordered'] = true } function p.makeListData(listType, args) -- Constructs a data table to be passed to p.renderList. local data = {} -- Classes and TemplateStyles data.classes = {} data.templatestyles = '' if listType == 'horizontal' or listType == 'horizontal_ordered' then table.insert(data.classes, 'hlist') data.templatestyles = mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Hlist/styles.css' } } elseif listType == 'unbulleted' then table.insert(data.classes, 'plainlist') data.templatestyles = mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Plainlist/styles.css' } } end table.insert(data.classes, args.class) -- Main div style data.style = args.style -- Indent for horizontal lists if listType == 'horizontal' or listType == 'horizontal_ordered' then local indent = tonumber(args.indent) indent = indent and indent * 1.6 or 0 if indent > 0 then data.marginLeft = indent .. 'em' end end -- List style types for ordered lists -- This could be "1, 2, 3", "a, b, c", or a number of others. The list style -- type is either set by the "type" attribute or the "list-style-type" CSS -- property. if listType == 'ordered' or listType == 'horizontal_ordered' then data.listStyleType = args.list_style_type or args['list-style-type'] data.type = args['type'] -- Detect invalid type attributes and attempt to convert them to -- list-style-type CSS properties. if data.type and not data.listStyleType and not tostring(data.type):find('^%s*[1AaIi]%s*$') then data.listStyleType = data.type data.type = nil end end -- List tag type if listType == 'ordered' or listType == 'horizontal_ordered' then data.listTag = 'ol' else data.listTag = 'ul' end -- Start number for ordered lists data.start = args.start if listType == 'horizontal_ordered' then -- Apply fix to get start numbers working with horizontal ordered lists. local startNum = tonumber(data.start) if startNum then data.counterReset = 'listitem ' .. tostring(startNum - 1) end end -- List style -- ul_style and ol_style are included for backwards compatibility. No -- distinction is made for ordered or unordered lists. data.listStyle = args.list_style -- List items -- li_style is included for backwards compatibility. item_style was included -- to be easier to understand for non-coders. data.itemStyle = args.item_style or args.li_style data.items = {} for _, num in ipairs(mTableTools.numKeys(args)) do local item = {} item.content = args[num] item.style = args['item' .. tostring(num) .. '_style'] or args['item_style' .. tostring(num)] item.value = args['item' .. tostring(num) .. '_value'] or args['item_value' .. tostring(num)] table.insert(data.items, item) end return data end function p.renderList(data) -- Renders the list HTML. -- Return the blank string if there are no list items. if type(data.items) ~= 'table' or #data.items < 1 then return '' end -- Render the main div tag. local root = mw.html.create('div') for _, class in ipairs(data.classes or {}) do root:addClass(class) end root:css{['margin-left'] = data.marginLeft} if data.style then root:cssText(data.style) end -- Render the list tag. local list = root:tag(data.listTag or 'ul') list :attr{start = data.start, type = data.type} :css{ ['counter-reset'] = data.counterReset, ['list-style-type'] = data.listStyleType } if data.listStyle then list:cssText(data.listStyle) end -- Render the list items for _, t in ipairs(data.items or {}) do local item = list:tag('li') if data.itemStyle then item:cssText(data.itemStyle) end if t.style then item:cssText(t.style) end item :attr{value = t.value} :wikitext(t.content) end return data.templatestyles .. tostring(root) end function p.makeList(listType, args) if not listType or not listTypes[listType] then error(string.format( "bad argument #1 to 'makeList' ('%s' is not a valid list type)", tostring(listType) ), 2) end checkType('makeList', 2, args, 'table') local data = p.makeListData(listType, args) local list = p.renderList(data) return list end for listType in pairs(listTypes) do p[listType] = function (frame) local mArguments = require('Module:Arguments') local origArgs = mArguments.getArgs(frame, { frameOnly = ((frame and frame.args and frame.args.frameonly or '') ~= ''), valueFunc = function (key, value) if not value or not mw.ustring.find(value, '%S') then return nil end if mw.ustring.find(value, '^%s*[%*#;:]') then return value else return value:match('^%s*(.-)%s*$') end return nil end }) -- Copy all the arguments to a new table, for faster indexing. local args = {} for k, v in pairs(origArgs) do args[k] = v end return p.makeList(listType, args) end end return p lyheh2t5yqhjixmg8vlktt3t9sq2ewi 736707 736706 2026-10-07T14:40:41Z King ChristLike 13051 1 revision imported from [[:en:Module:List]] 736706 Scribunto text/plain local libUtil = require('libraryUtil') local checkType = libUtil.checkType local mTableTools = require('Module:TableTools') local p = {} local listTypes = { ['bulleted'] = true, ['unbulleted'] = true, ['horizontal'] = true, ['ordered'] = true, ['horizontal_ordered'] = true } function p.makeListData(listType, args) -- Constructs a data table to be passed to p.renderList. local data = {} -- Classes and TemplateStyles data.classes = {} data.templatestyles = '' if listType == 'horizontal' or listType == 'horizontal_ordered' then table.insert(data.classes, 'hlist') data.templatestyles = mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Hlist/styles.css' } } elseif listType == 'unbulleted' then table.insert(data.classes, 'plainlist') data.templatestyles = mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Plainlist/styles.css' } } end table.insert(data.classes, args.class) -- Main div style data.style = args.style -- Indent for horizontal lists if listType == 'horizontal' or listType == 'horizontal_ordered' then local indent = tonumber(args.indent) indent = indent and indent * 1.6 or 0 if indent > 0 then data.marginLeft = indent .. 'em' end end -- List style types for ordered lists -- This could be "1, 2, 3", "a, b, c", or a number of others. The list style -- type is either set by the "type" attribute or the "list-style-type" CSS -- property. if listType == 'ordered' or listType == 'horizontal_ordered' then data.listStyleType = args.list_style_type or args['list-style-type'] data.type = args['type'] -- Detect invalid type attributes and attempt to convert them to -- list-style-type CSS properties. if data.type and not data.listStyleType and not tostring(data.type):find('^%s*[1AaIi]%s*$') then data.listStyleType = data.type data.type = nil end end -- List tag type if listType == 'ordered' or listType == 'horizontal_ordered' then data.listTag = 'ol' else data.listTag = 'ul' end -- Start number for ordered lists data.start = args.start if listType == 'horizontal_ordered' then -- Apply fix to get start numbers working with horizontal ordered lists. local startNum = tonumber(data.start) if startNum then data.counterReset = 'listitem ' .. tostring(startNum - 1) end end -- List style -- ul_style and ol_style are included for backwards compatibility. No -- distinction is made for ordered or unordered lists. data.listStyle = args.list_style -- List items -- li_style is included for backwards compatibility. item_style was included -- to be easier to understand for non-coders. data.itemStyle = args.item_style or args.li_style data.items = {} for _, num in ipairs(mTableTools.numKeys(args)) do local item = {} item.content = args[num] item.style = args['item' .. tostring(num) .. '_style'] or args['item_style' .. tostring(num)] item.value = args['item' .. tostring(num) .. '_value'] or args['item_value' .. tostring(num)] table.insert(data.items, item) end return data end function p.renderList(data) -- Renders the list HTML. -- Return the blank string if there are no list items. if type(data.items) ~= 'table' or #data.items < 1 then return '' end -- Render the main div tag. local root = mw.html.create('div') for _, class in ipairs(data.classes or {}) do root:addClass(class) end root:css{['margin-left'] = data.marginLeft} if data.style then root:cssText(data.style) end -- Render the list tag. local list = root:tag(data.listTag or 'ul') list :attr{start = data.start, type = data.type} :css{ ['counter-reset'] = data.counterReset, ['list-style-type'] = data.listStyleType } if data.listStyle then list:cssText(data.listStyle) end -- Render the list items for _, t in ipairs(data.items or {}) do local item = list:tag('li') if data.itemStyle then item:cssText(data.itemStyle) end if t.style then item:cssText(t.style) end item :attr{value = t.value} :wikitext(t.content) end return data.templatestyles .. tostring(root) end function p.makeList(listType, args) if not listType or not listTypes[listType] then error(string.format( "bad argument #1 to 'makeList' ('%s' is not a valid list type)", tostring(listType) ), 2) end checkType('makeList', 2, args, 'table') local data = p.makeListData(listType, args) local list = p.renderList(data) return list end for listType in pairs(listTypes) do p[listType] = function (frame) local mArguments = require('Module:Arguments') local origArgs = mArguments.getArgs(frame, { frameOnly = ((frame and frame.args and frame.args.frameonly or '') ~= ''), valueFunc = function (key, value) if not value or not mw.ustring.find(value, '%S') then return nil end if mw.ustring.find(value, '^%s*[%*#;:]') then return value else return value:match('^%s*(.-)%s*$') end return nil end }) -- Copy all the arguments to a new table, for faster indexing. local args = {} for k, v in pairs(origArgs) do args[k] = v end return p.makeList(listType, args) end end return p lyheh2t5yqhjixmg8vlktt3t9sq2ewi Jewel Plummer Cobb 0 12497 736838 706319 2026-10-08T04:32:46Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736838 wikitext text/x-wiki {{databox}} [[Category:Articles with hCards]] '''Jewel Plummer Cobb''' (January 17, 1924 - Jenụwarị 1, 2017) <ref>{{Cite news|url=https://www.nytimes.com/2017/01/11/obituaries/jewel-plummer-cobb-92-dies-led-a-california-campus.html|title=Jewel Plummer Cobb, 92, Dies; Led a California Campus|author=Slotnik|first=Daniel E.|date=2017-01-11|work=The New York Times|accessdate=2017-02-09}}</ref> bụ ọkà mmụta ihe ndị dị ndụ America, onye nyocha ọrịa kansa, prọfesọ, dean, na onye nchịkwa agụmakwụkwọ. O nyere aka na ngalaba nyocha ọrịa kansa site n'ịmụ ọgwụgwọ maka melanoma . Cobb bụ onye na-akwado maka ịbawanye nnochite anya ụmụ nwanyị na ụmụ akwụkwọ nke agba na mahadum, ma o mepụtara mmemme iji kwado ụmụ akwụkwọ nwere mmasị ịchụso ụlọ akwụkwọ gụsịrị akwụkwọ. <ref name=":122">{{Cite news|title=Former Dean Honored by Chemical Firm|date=April 14, 1982|work=The Day}}</ref> == Ndụ mbido ya == Jewel Isadora Plummer bụ naanị nwa Frank V. Plummer, na Carriebel (Cole) Plummer. Ndị mụrụ ya abụọ na-ebibu na Washington DC <ref>{{Cite journal|author=Clewell|first=Beatriz|title=Women in the Biological Sciences: A Biobibliographic Sourcebook|doi=10.2307/1223679|url=https://pdfs.semanticscholar.org/adf9/b4f8cd53c41b221692873dc9e9fa3faf43e9.pdf}}</ref> Nne ya, Carriebel, chọtara ọrụ dị ka agụmakwụkwọ anụ ahụ <ref name="blackpast2"/> na onye nkuzi ịgba egwu nke gụsịrị akwụkwọ na kọleji nwere BA na ịgba egwu ntụgharị. Ọ banyeghachiri mahadum n'otu oge Jewel debara aha ya nke mere ka ma nne na nwa nwanyị nweta akara ugo mmụta n'otu afọ ahụ. <ref name="distinguished20thcenturyscientists"/> Nna Jewel, Frank, bụ onye isi ojii mbụ nke gụsịrị akwụkwọ na Dọkịta nke Ọgwụ na Mahadum Cornell, ghọrọ dọkịta ọkachamara na dermatology. <ref name=":32">{{Cite book|title=Women Pioneers of Medical Research|url=https://archive.org/details/womenpioneersofm0000chun|author=Chung|first=King-Thom|publisher=McFarland & Company, Inc.|year=2010|isbn=978-0-7864-2927-1|location=Jefferson, North Carolina|pages=[https://archive.org/details/womenpioneersofm0000chun/page/179 179]–183}}</ref> Nna nna Plummer bụ ohu a tọhapụrụ onwe ya nke gụsịrị akwụkwọ na Mahadum Howard n'afọ 1898 na-ebi ndụ dị ka onye na-ere ọgwụ. <ref name=":83">{{Cite news|title=Dr. Cobb names Dean of the College|author=Eunson|first=Robi|date=March 5, 1969|work=The Day}}</ref> Nzụlite Cobb nwere oke akụ na ụba nyere ya ohere nchọgharị ọgụgụ isi n'oge ọ bụ nwata. Site na ọba akwụkwọ sayensị nke nna ya ruo na agụmakwụkwọ ya n'ọtụtụ ụlọ ọrụ agbụrụ dị iche iche, <ref name=":92">{{Cite journal|author=Biermann; Grinstein|first=Carol; Louise|date=December 1994|title=Despite the Odds: Women Biologists Who Succeed|url=https://archive.org/details/sim_american-biology-teacher_november-december-1994_56_8/page/n21|journal=The American Biology Teacher|volume=56|issue=8|pages=468–475|doi=10.2307/4449891}}</ref> Cobb zụlitere mmasị n'ịmụ ihe site na nwata. N'agbanyeghị na ọ tụrụ anya ịghọ onye nkuzi mmụta anụ ahụ, mmasị ya na sayensị gbasiri ike n'afọ nke abụọ nke ụlọ akwụkwọ sekọndrị ka ọ na-ele anya na microscope na klas biology. <ref name=":02">{{Cite book|url=http://go.galegroup.com./ps/i.do?id=GALE%7CCX3404707987&v=2.1&u=msu_main&it=r&p=GVRL&sw=w&asid=32d8a550785208d049340eaea97b7f55|title=Jewel Plummer Cobb|date=2004|publisher=Encyclopedia of World Biography|edition=2nd|location=Detroit|pages=112–114|accessdate=March 14, 2016}}</ref> Mmasị a bụ onye nkuzi biology ya gbara ume, akwụkwọ gbasara microorganisms dị ka Paul DeKruif's ''The Microbe Hunters masịrị'' ya. <ref name="distinguished20thcenturyscientists"/> == Agụmakwụkwọ Mahadum ya == Cobb gbara akwụkwọ na Mahadum Michigan N'afọ 1942, mana, enweghị afọ ojuju maka ụlọ ndị kewapụrụ maka ụmụ akwụkwọ America America na Michigan, ọ gafere na kọleji Talladega na [[Alabama]]. <ref name="Collins">{{Cite web|author=Collins|first=Sibrina Nichelle|title=Unsung: Jewel Plummer Cobb|url=https://undark.org/article/remembering-jewel-isadora-plummer-cobb/|work=UnDark|accessdate=7 November 2018|date=February 7, 2017}}</ref> Ụlọ akwụkwọ Talladega anabataghị kredit mbufe, na-amanye Cobb ịmalite ọzọ. N'agbanyeghị nke a, ọ rụchara ọrụ nkuzi ya n'ime afọ atọ karịa ọkọlọtọ anọ. <ref name="distinguished20thcenturyscientists">{{Cite book|author=Kessler|first=James H.|date=1996|title=Distinguished African American Scientists of the 20th Century|url=https://archive.org/details/distinguishedafr00kess|location=Phoenix, Arizona|publisher=Oryx Press|isbn=0-89774-955-3}}</ref> Ọ gụsịrị akwụkwọ na BA na bayoloji n'afọ 1944 <ref name=":32"/> wee bụrụ onye otu Alpha Kappa Alpha sorority. <ref name="blackpast2"/> Na mbụ a jụrụ Cobb mkpakọrịta nke gụsịrị akwụkwọ na bayoloji na Mahadum New York, ebubo na ọ bụ n'ihi agbụrụ ya, mana enyere ya mkpakọrịta mgbe a gbachara ajụjụ ọnụ. <ref name="blackpast2">{{Cite web|url=http://www.blackpast.org/?q=aah/cobb-jewel-plummer-1924|title=Cobb, Jewel Plummer (1924- )|publisher=The Black Past|accessdate=2012-07-13|date=2011-03-16}}</ref> O nwetara MS ya na Mahadum New York n'afọ 1947, yana PhD ya na-elekwasị anya na physiology cell n'afọ 1950 <ref name=":83"/> Akwụkwọ edemede ya, ''Mechanisms of Pigment Formation'', nyochara nhazi nke melanin pigment granules in vitro site na iji enzyme tyrosinase. <ref name=":13">Warren, W. (1999). Black women scientists in the United States. Bloomington: Indiana University Press.</ref> N' 1949, a họpụtara ya onye nyocha onwe ya na Woods Hole Marine Biological Laboratory . <ref name="blackpast2"/> N'afọ 2021, obodo ahụ degharịrị aha okporo ụzọ dị nso na Laboratory Marine Biological "Jewel Cobb Road" iji sọpụrụ Cobb. <ref>{{Cite web|title='Jewel Cobb Road' Coming May 28|url=https://www.capenews.net/falmouth/briefs/jewel-cobb-road-coming-may-28/article_e4a3f515-8614-5dbb-803f-ad0bbd4fb517.html|accessdate=2021-05-24|work=CapeNews.net|language=en|archive-url=https://web.archive.org/web/20210524122712/https://www.capenews.net/falmouth/briefs/jewel-cobb-road-coming-may-28/article_e4a3f515-8614-5dbb-803f-ad0bbd4fb517.html|archive-date=2021-05-24|url-status=dead}}</ref> == Ndụ ọkachamara ya == Mgbe ọ nwetasịrị Ph.D ya, Cobb ghọrọ onye nkuzi nkuzi bayoloji na Mahadum New York ka ọ na-arụkwa ọrụ maka National Cancer Institute na Harlem Hospital (1950-1952). === Mahadum nke Illinois College of Medicine === Site na 1952-1954 Cobb bụ onye nkuzi na mmewere ahụ na Chicago na Mahadum Illinois College of Medicine ebe ọ kuziri histology. <ref name="blackpast2"/> === Ụlọ akwụkwọ Hunter === N’oge na-adịghị anya ka nke ahụ gasịrị, Cobb laghachiri na New York, na-eje ozi dị ka onye osote prọfesọ maka ụlọ akwụkwọ ahụike gụsịrị akwụkwọ na NYU (1955–60), ebe ọ na-arụkwa ọrụ dị ka onye nkuzi nleta na Hunter College (1956–57). <ref>"CC NEWS Press Release", February 12, 1969. Plummer Cobb Jewel, Folder 1. Linda Lear Center for Special Collections and Archives, Connecticut College, New London, CT.</ref> === Ụlọ akwụkwọ Sarah Lawrence === Site n'afọ 1960-69, Cobb were n'ọrụ dị ka onye isi ụlọ nyocha bayoloji na kọleji Sarah Lawrence . Mgbe ọ nọ ebe ahụ, o mere nyocha maka ndị sonyere na National Science Foundation . <ref name="blackpast2"/> === Kọleji Connecticut === Cobb jere ozi dị ka onye prọfesọ nke [[Agụmanụmanụ|Zoology]] yana Dean of Arts and Sciences na Kọleji Connecticut site na Julaị 1969 ruo Julaị 1976. Cobb bụ onye isi ojii mbụ na akụkọ ihe mere eme kọleji. <ref name=":53">"CC NEWS Press Release 1976." Plummer Cobb Jewel, Folder 1. Linda Lear Center for Special Collections and Archives, Connecticut College, New London, CT.</ref> Mgbe ọ nabatara ọkwa ahụ na Kọleji Connecticut, o kwuru, sị: "Nke a bụ kọleji na mgbanwe, na-aga n'ihu n'ụzọ na-akpali akpali. Anyị chọrọ ụmụ akwụkwọ na ndị nkuzi ojii ka ha nyere anyị aka ịhazi na ime atụmatụ ọhụrụ anyị nwere obi ike." <ref name=":42">{{Cite news|title=Conn College has a Black Dean|date=September 10, 1970|work=Bay State Banner}}</ref> N'oge ya na Connecticut College, o mejuputa atumatu Black Scholarship nke nyere aka ego ma ọ dịkarịa ala iri aNọ Black undergraduates na kọleji. Nkuzi nkuzi a bu n’obi ịbawanye mkpa enyemaka ego maka ụmụ akwụkwọ nwere agba. <ref name=":42"/> Ọrụ a kpaliri mmemme ndị yiri ya na mahadum ndị ọzọ. <ref name="distinguished20thcenturyscientists"/> Cobb guzobekwara mmemme Pre-Medical Post-Baccalaureate nke afọ ise, nke nyere enyemaka ego na ohere mmụta maka ụmụ akwụkwọ pere mpe na kọleji chọrọ ịchụso ọrụ na ọgwụ ma ọ bụ dentistry. Enyere ụmụ akwụkwọ ihe enyemaka maka nkuzi na ndụmọdụ. Naanị afọ ise ka emechara mmemme a, a nabatara ụmụ akwụkwọ ndị a na mmemme gụsịrị akwụkwọ, nke gụnyere, Yale, Georgetown, na Mahadum Connecticut . <ref name=":53">"CC NEWS Press Release 1976." Plummer Cobb Jewel, Folder 1. Linda Lear Center for Special Collections and Archives, Connecticut College, New London, CT.</ref> Mgbe ọ nọ na Connecticut, Dr. Cobb jere ozi dị ka onye otu Lawrence na Ụlọ Ọgwụ Ncheta dị na New [[London]], <ref name=":113">{{Cite news|title=The Travelers|author=Jones R.|first=Thomas|date=September 6, 1974|work=Travelers Corporation}}</ref> na mgbakwunye na ịbụ onye a họpụtara ahọpụta onye isi oche nke American Council on Education, (1973-1976). Dr Cobb, dị ka onye so na National Science Board na onye na-enye ndụmọdụ na Otu Amerika maka nganihu nke Sayensị, onye isi oche ogbako nke ụmụ nwanyị iri atọ pere mpe bụ ndị ọkà mmụta sayensị iji nye ndụmọdụ maka ụlọ akwụkwọ, ndị na-eme iwu na gọọmentị US maka otu esi ewebata ụmụ nwanyị ndị ọzọ. agba n'ime sayensị. E bipụtara akụkọ ahụ nwere mmetụta dị ukwuu dị ka [http://web.mit.edu/cortiz/www/Diversity/1975-DoubleBind.pdf The Double Bind: The Price of Being a Minority Woman in Science] . N'ihi ọtụtụ ọrụ, Cobb rụrụ ọrụ ọtụtụ awa. Ọ rụrụ ọrụ laabu n'isi ụtụtụ na-esochi ọrụ nchịkwa tupu izi ihe n'ehihie. <ref name="distinguished20thcenturyscientists"/> === Douglass Residential College === Na July 1976, Cobb kpebiri ịhapụ Connecticut College wee bụrụ onye isi na prọfesọ nke sayensị sayensị na Douglass Residential College na Mahadum Rutgers . Mkpebi Cobb ịpụ abụghị ebum n'obi, kama ọ gbadoro ụkwụ na mmasị ịbụ onye nchịkwa oge niile maka ngalaba ụmụ nwanyị Rutgers. <ref name=":62">{{Cite news|title=Rutgers News Service|author=Scott|first=Ruth|date=April 9, 1976|work=Rutgers the State University Press Release}}</ref> Ihe kacha egbu azụ Cobb na ịhapụ kọleji metụtara enweghị ike ịga n'ihu nyocha ruo otu ogo na ọrụ ọhụrụ ya. <ref name=":53">"CC NEWS Press Release 1976." Plummer Cobb Jewel, Folder 1. Linda Lear Center for Special Collections and Archives, Connecticut College, New London, CT.</ref> Mgbe ọ nọ na Douglass, Rockefeller Foundation họpụtara Cobb (ya na ndị America itoolu) ka ha sonye na ogbako zuru ụwa ọnụ na Ịtali gbasara ọdịnihu agụmakwụkwọ ka elu maka ụmụ nwanyị. <ref name=":62"/> Na mgbakwunye, na Eprel 1978, Onye isi ala Carter họpụtara Cobb ka ọ bụrụ onye otu Board of Scholarships Ofesi, nke a kacha mara amara dị ka nzukọ na-ahụ maka ikpebi ntozu Fulbright. === Mahadum California State, Fullerton === A họpụtara Cobb Onye isi oche nke Mahadum [[California]] State, Fullerton n'afọ 1981 ebe ọ malitere imeziwanye akụrụngwa ụlọ akwụkwọ site na mmalite nke oge ya. Cobb nwere ihe ịga nke ọma n'inweta ego maka owuwu nke Engineering na Kọmputa Science Building nke e ji ego steeti wuo, yana Ruby Gerontology Center, nke bụ ụlọ mbụ n'ime akụkọ ihe mere eme kọleji nke a na-enweta site na onyinye nkeonwe. O nwetakwara ego maka iwu ụlọ obibi ụmụ akwụkwọ mbụ na kampos. Emechara ụlọ a ka emechara aha maka nsọpụrụ ya. Cobb kpakọrịtakwara nkwekọrịta ya na Marriott Corporation na obodo Fullerton maka ịgbazinye ụlọ iji wuo ụlọ oriri na ọṅụṅụ, na-enye ya ohere iji ego dịnụ maka iwu ụlọ egwuregwu ogige. Ọtụtụ n'ime atụmatụ maka Sayensị laabu center, nke a na-akpọ ugbu a Dan Black Hall, mere mgbe Cobb bụ onyeisi oche. <ref>{{Cite web|url=http://d-c.fullerton.edu/HistoricalInformation/HistoryMilestones.aspx|title=History Milestones of Cal State Fullerton|publisher=California State University, Fullerton|archiveurl=https://web.archive.org/web/20110710020112/http://d-c.fullerton.edu/HistoricalInformation/HistoryMilestones.aspx|archivedate=2011-07-10|accessdate=2012-07-13}}</ref> Na Fullerton, ụfọdụ ndị otu ngalaba ekereghị mmasị Cobb na nyocha na iwughachi ụlọ, na-ejide na isi ọrụ nke kọleji ahụ bụ ịkụziri ihe. Mkpebi ya ịbanye n'ime nkwekọrịta iji wuo ụlọ nkwari akụ na ụlọ akwụkwọ na ịgbakwunye ogige satịlaịtị na mpaghara ndịda Orange County si otú a mee nkatọ na ụlọ akwụkwọ. Cobb wetara okwu abụọ a na ngalaba Senate maka ntuli aka. Ugboro abụọ ahụ, a kwadoro mkpebi ya. <ref name="times12">{{Cite web|url=http://articles.latimes.com/1988-05-28/news/li-3375_1_cal-state-fullerton/3|title=Cal State Fullerton's Crown Jewel: Cobb's Accomplishments Calm Critics, but Her Dedication Is a Two-Edged Sword|author=Morgan|first=Lael|date=May 28, 1988|work=Los Angeles Times|accessdate=2012-07-13}}</ref> N'afọ 1990, ọ dị afọ 66, a manyere ya ịla ezumike nká n'okpuru iwu nyere W. Ann Reynolds, Chancellor nke California State University System, na-achọ ka ndị isi ụlọ akwụkwọ niile dị afọ iri isii na ise ma ọ bụ karịa ka ha lara ezumike nká. <ref>{{Cite news|url=http://articles.latimes.com/1990-03-28/local/me-315_1_search-committee|title=FULLERTON: Truce Reached on CSF President Search|author=Johnson|first=Ted|date=March 28, 1990|work=Los Angeles Times|accessdate=2012-07-13}}</ref> <ref>{{Cite news|url=http://articles.latimes.com/1990-07-28/news/mn-714_1_cal-state-fullerton|title=Cobb's Cal State Legacy: Minority, Campus Growth|author=Lindgren|first=Kristina|date=July 28, 1990|work=Los Angeles Times|accessdate=2012-07-13}}</ref> Na nzaghachi na ọpụpụ ya, Julian Foster, onye ndu ụlọ akwụkwọ na onye ọkà mmụta ndọrọ ndọrọ ọchịchị a ma ama, kwuputara mmesi ike Cobb na nyocha na agụmakwụkwọ ka ọ bụrụ ntinye aka ya kacha mkpa na Cal State Fullerton . <ref name=":22">{{Cite news|url=http://articles.latimes.com/1989-10-27/news/mn-787_1_cal-state-fullerton|title=Cal State Fullerton's Cobb to Step Down After 8 Years|author=Davidson, J.|date=October 27, 1989|work=[[Los Angeles Times]]|accessdate=March 15, 2016}}</ref> N'oge na-adịghị anya ka ọ lara ezumike nká, a kpọrọ Cobb aha Prọfesọ Nlekọta Mahadum California State maka ngalaba Los Angeles ya. N'afọ 1991, ọ ghọrọ onye isi nyocha na Southern California Sayensi na Engineering ACCESS Center and Network, nke na-enyere ụmụ akwụkwọ sekọndrị na ụlọ akwụkwọ sekọndrị sitere na enweghị nsogbu na-achụso ọdịnihu na ngalaba sayensị na injinia. N'afọ 2001, Cobb ghọrọ onye nyocha isi maka Mmemme Sayensị Teknụzụ Injinia (STEP) Up for Youth—ASCEND project na Mahadum California State, Los Angeles. <ref name=":72">{{Cite web|url=http://www.calstatela.edu/univ/ppa/newsrel/jpcobb2.htm|title=wilson award 2001|date=22 October 2013|work=Calstatela.edu|accessdate=13 January 2018}}</ref> Akpọrọkwa ya aha wee jee ozi dịka onye otu Board of Trustees Caltech. <ref name="page12">{{Cite web|url=http://www.ncbw.org/programs/award1.html|title=CANDACE AWARD RECIPIENTS 1982-1990, Page 1|work=National Coalition of 100 Black Women|archiveurl=https://web.archive.org/web/20030314021634/http://www.ncbw.org/programs/award1.html|archivedate=March 14, 2003}}</ref> == Nyocha == Nnyocha nke Cobb gụnyere ọrụ na mmekọrịta dị n'etiti melanin na mmebi akpụkpọ ahụ, yana mmetụta nke homonụ, ìhè ultraviolet, na ọgwụ chemotherapy na nkewa cell. Cobb chọpụtara na methotrexate dị irè n'ịgwọ ụfọdụ ọrịa cancer akpụkpọ anụ, ọrịa cancer akpa ume, na leukemia nwata. <ref>{{Cite web|url=http://breastcancer.about.com/b/2010/03/29/jewel-plummer-cobb.htm|title=Jewel Plummer Cobb - Overcomer and Cancer Biologist|author=Stephan|first=Pam|date=March 29, 2010|publisher=Breastcancer.about.com|accessdate=2012-07-13|archivedate=2012-04-26|archiveurl=https://web.archive.org/web/20120426065358/http://breastcancer.about.com/b/2010/03/29/jewel-plummer-cobb.htm}}</ref> A ka na-eji ọgwụ a eme ihe na chemotherapy taa na-enye ọgwụgwọ ọrịa cancer dị iche iche na ọrịa autoimmune nke gụnyere: ọrịa ara ara, ọrịa isi na olu, ọrịa cancer akpa ume, leukemia, na ụfọdụ ụdị lymphoma. Cobb bụ onye mbụ bipụtara data na actinomycin D na ikike ya ime ka mbelata nke nucleoli na nucleus nke sel mmadụ nkịtị na nke ọjọọ. <ref name=":13">Warren, W. (1999). Black women scientists in the United States. Bloomington: Indiana University Press.</ref> O nwetara onyinye $5,000 sitere na American Cancer Society ka ọ gaa n'ihu na nyocha ya na "Direct Hormone Action to Human and Mouse Melanomas in Tissue Culture." <ref>"Letter from American Cancer Society. "May 26, 1971. Plummer Cobb Jewel, Folder 1. Lear Center for Special Collections and Archives, Connecticut College, New London, CT.</ref> Onyinye a kwadoro nyocha ya na nyocha sara mbara nke uto cell pigmenti na ọdịiche dị na melanomas mmadụ na òké. <ref name=":63">{{Cite web|url=http://nas.nasonline.org/site/PageServer?pagename=AAHP_Database_Bio_J_Cobb|title=Jewel Plummer Cobb|publisher=National Academy of Sciences|archiveurl=https://web.archive.org/web/20120428161713/http://nas.nasonline.org/site/PageServer?pagename=AAHP_Database_Bio_J_Cobb|archivedate=2012-04-28|accessdate=2012-07-13}}</ref> <ref>{{Cite news|title=Connecticut College Dean Gets $5000 Cancer Grant|date=June 14, 1971|work=Times Hartford, Connecticut}}</ref> Nkwado ndị ọzọ maka nyocha ọrịa kansa sitere na mkpakọrịta post-doctoral ya, onyinye nyocha sitere na: Damon Runyon, National Science Foundation, National Cancer Institute, na Ọrụ Ahụike Ọha. <ref name=":53">"CC NEWS Press Release 1976." Plummer Cobb Jewel, Folder 1. Linda Lear Center for Special Collections and Archives, Connecticut College, New London, CT.</ref> Cobb bụ akụkụ nke United States International Cancer Congress na London (1958) na Moscow (1962) wee jee ozi na bọọdụ ndụmọdụ na Mohegan Community College. Enyere ya National Institute of Health Fellowship na ọnụ $68,000, ebe ọ nọrọ ọnwa asaa na Naples, Italy na-aga n'ihu na nyocha uto cell na International Laboratory of Genetics and Biophysics. <ref name=":83"/> N'ime oge ọrụ ya niile, ya na ndị nchọpụta ndị ọzọ a ma ama na-arụkọ ọrụ, gụnyere oncologist Jane C. Wright, Grace Antikajian, na Dorothy Walker Jones . <ref name="Collins"/> Ndị ndụmọdụ ya kacha emetụta bụ prọfesọ banyere nje bacteria James R. Hayden na prọfesọ biochemistry ya bụ MJ Kopac. <ref name=":13">Warren, W. (1999). Black women scientists in the United States. Bloomington: Indiana University Press.</ref> N'ịkwado mmezu nyocha ya, a họpụtara Cobb na Institute of Medicine na National Academy of Sciences n'afọ 1974. <ref name=":63"/> Ọ bụkwa onye so na National Science Board site na 1974 ruo 1980. <ref>{{Cite web|url=http://www.aaregistry.org/historic_events/view/jewel-plummer-cobb-biologist|title=Jewel Plummer Cobb, Biologist|publisher=African American Registry|accessdate=2012-07-13}}</ref> <ref>{{Cite news|title=National Foundation News|author=Renirie|first=Jack|date=June 26, 1974|work=National Foundation}}</ref> == Ntinye aka ọha == Akpọrọ Cobb osote onye isi oche nke Board maka 21st Century Foundation, raara onwe ya nye n'ịkwado mmepe nke ụlọ ọrụ ojii na-ekwu okwu na obodo ojii. <ref>"CC NEWS 1972" Plummer Cobb Jewel, Folder 1. Linda Lear Center for Special Collections and Archives, Connecticut College, New London, CT.</ref> Mmemme nke nzukọ ahụ hibere gụnyere: mmepe akụ na ụba, agụmakwụkwọ na obodo na ebumnuche nke imepụta ohere maka ndị agba. <ref name=":92"/> Ọ bụkwa onye òtù American Association for the Advancement of Science, nke kwadoro ma ndị inyom na ndị na-agba agba n'ọhịa. <ref name=":113"/> Cobb bụ otu n'ime mmadụ asaa nke Oakland Museum Association's Cultural and Ethnic Affairs ghọtara maka ntinye aka ya na sayensị na/ma ọ bụ teknụzụ. Ihe ngosi ihe ngosi nka nwere olile anya ịbawanye nnochite anya nta na sayensị site n'igosipụta mmezu nke ndị agba agba, gụnyere ọtụtụ nchọpụta Cobb. <ref>"Dr Jewel Cobb to be honored," ''The Day.'' Feb 15, 1973 – via the Linda Center for Special Collections and Archives, Connecticut College, New London, CT.</ref> Dị ka onye isi okwu na mmalite 1971 Wheaton College mmalite, Cobb kpọrọ oku maka njikọ n'etiti Women's Liberation Movement na Black Liberation Movement. <ref>{{Cite news|title=Dean Calls for Alliance of Women and Black|author=Brayne|first=Marylin|date=June 23, 1971|work=The Day}}</ref> <ref name=":102">Plummer Cobb Jewel "Commencement Speech at Wheaton College." May 29, 1971. Plummer Cob Jewel, Folder 1. Linda Lear Center for Special Collections and Archives, Connecticut College, New London, CT.</ref> Ọ kpọkuru maka nha nhata nke ụmụ nwanyị, kagbuo iwu ite ime, na ịchọ nlekọta ọha na eze karịsịa. <ref name=":102" /> == Afọ ikpeazụ na ihe nketa == Ọtụtụ n'ime atumatu na mmemme Cobb bidoro n'oge ọrụ nchịkwa ya na-ewere ọnọdụ na akwụkwọ 1979 ya, ''Filters for Women in Science'', ebe o kwuputara nchegbu banyere nnọchite nwanyị na sayensị na injinia. Site na ntụnyere jikọtara mmasị ya maka sayensị na ọchịchọ maka ịha nhatanha, Cobb kwuru na njirimara nke nzacha na-agafe na nzacha na-ekpebi n'ụzọ bụ isi n'ogo nke pores, nke o jikọtara ya na njedebe nke ọrụ ụmụ nwanyị na sayensị. <ref>{{Cite journal|author=Cobb, J. P.|date=1979|title=Filters for Women in Science|journal=Annals of the New York Academy of Sciences|volume=323|issue=1|pages=236–48|doi=10.1111/j.1749-6632.1979.tb16857.x}}</ref> Mkpesa Cobb n'inye akụrụngwa na mmemme iji mee ka ndị pere mpe nọchite anya na kọleji ọrụ ya na-akọwa ihe nketa ya na mpụga ụlọ nyocha. <ref name=":122"/> Onye bụbu nwa akwụkwọ, Timothy Yarboro, kwuru, sị, “Agaraghị m abụ dọkịta. N’ihi ya, amaara m na ọ ga-ekwe omume.” <ref name=":33">Carey, P. M. (2012). The power of a role model Biologist Jewel Plummer Cobb inspired a generation of Connecticut College students. ''Connecticut College Magazine''.</ref> Cobb biri na Maplewood, New Jersey, <ref name=":33">Carey, P. M. (2012). The power of a role model Biologist Jewel Plummer Cobb inspired a generation of Connecticut College students. ''Connecticut College Magazine''.</ref> ruo mgbe ọ nwụrụ na Jenụwarị 1, 2017 mgbe ọ dị afọ 92. <ref name=":102">Plummer Cobb Jewel "Commencement Speech at Wheaton College." May 29, 1971. Plummer Cob Jewel, Folder 1. Linda Lear Center for Special Collections and Archives, Connecticut College, New London, CT.</ref> <ref name=":122"/> Ọ mụrụ naanị otu nwa ya, Jonathan, onye ọkà mmụta redio nke ọkachamara n'ihe onyonyo magnetik . <ref name=":92"/> === Nkwanyere ugwu, ihe nrite na ndị otu === ; nzere doctorate * Medical College nke Pennsylvania * Mahadum Northern * Ụlọ ọrụ Rensselaer Polytechnic Institute * Mahadum Rutgers * Mahadum Tuskegee ; Ihe nrite * Reginald Wilson Award * Onyinye Candace, Njikọ Mba nke ụmụ nwanyị ojii 100, 1982 <ref name="page12"/> * 1999 Achievement in Excellence Award from the Center for Excellence in Education ; Ndị nso n'otu * Commission maka enyemaka mmadụ * Sigma Xi * National Academy of Sciences (Institute of Medicine) * National Science Foundation. * Ndị isi ụlọ ọrụ Allied Corporation * Òtù Ọdịbendị Omenala Tissue nke Kọmitii Mmụta (1972-1974) * Ụlọ nyocha mmiri mmiri * Board of Trustees maka Institute of Education Management == Mbipụta ya == * Cobb, Jewel Plummer, Dorothy G. Walker, na Jane C. Wright. "Ọmụmụ ihe ọmụmụ chemotherapy na-atụnyere na omenala obere oge nke ụmụ mmadụ nkịtị, benign, and malignant tumor tissues-ihe ọmụmụ afọ ise." Nnyocha ọrịa kansa 21.5 (1961): 583. * Cobb, Jewel Plummer, na Dorothy G. Walker. "Ọmụmụ ihe gbasara mkpụrụ ndụ Melanoma mmadụ na Omenala Tissue I. Njirimara Uto na Cytology." Nnyocha ọrịa kansa 20.6 (1960): 858-867. * Cobb, Jewel Plummer, na Dorothy G. Walker. "Mmetụta nke Actinomycin D na Omenala Tissue nke Nkịtị na Neoplastic Cell23." (1958). * Ntụle mba nke arụmọrụ na nsonye ụmụ nwanyị na mgbakọ na mwepụ, 1979 * Ọmụmụ gburugburu ebe mmụta na kọleji ụmụ nwanyị, 1981 * Nnyocha nke Black American Doctorates, 1968 * Nnyocha nke ọnọdụ dị ugbu a na atụmatụ nke kọleji maka omenala maka naanị ụmụ nwanyị, 1972 * Nnyocha nyocha gbasara ihe gbasara ụmụ nwanyị, 1975 * Ihe ịma aka agụmakwụkwọ, 1990 * Ịnweta na ike maka ndị isi ojii na agụmakwụkwọ dị elu, 1972 * Ịga n’ihu n’ọchịchị ụmụ nwanyị na Sayensị, 1995 * Ntụle nke ihe ndị na-emetụta nsonye ụmụ nwanyị na mmemme ntinye dị elu na mgbakọ na mwepụ, kemistri na physics, 1975 * Ntụle mmetụta nke ọrụ akwadoro iji kwalite nsonye ụmụ nwanyị na ọrụ na sayensị na teknụzụ, 1977 * Na obi ụtọ leghara mmekọahụ m anya, 1974 * Akụkọ kwa afọ nke kọmitii Sayensị Sayensị Mba na-ahụ maka ohere nhata na Sayensị na Nkà na ụzụ, 1982 * Ọrụ Black Initiative na Ọchịchị, 1987 * Campus 1970, Ebee ka ụmụ nwanyị guzoro? Akụkọ nyocha nke nyocha gbasara ụmụ nwanyị na Academe, 1970 * Ọrụ na Sayensị na Injinia maka ndị ojii America, 1972 * Nkwupụta Kwa Afọ Catalyst, 1978-1979 * Ịgbanwe America: Ihu Sayensị na Injinia Ọhụrụ, 1989 * Kọlọji Resource Council— Ọmụmụ banyere ndị agadi na ọhụrụ nke ọnụ ọgụgụ kọleji n'ime otu ndị otu, ud * Kọmitii na Education na Employment of Women in Science and Engineering (CEEWISE), 1977-1979 * Data na ụmụ nwanyị na nyocha sayensị, 1977 * Ugo mmụta ogo ụmụ nwanyị: Mmelite, 1979 * Enyere ogo ogo na usoro ndebanye aha na kọleji ojii mere eme: Ọmụmụ afọ asatọ, 1965 * Ngalaba ahụike, agụmakwụkwọ na ọdịmma- Nkwupụta nke onye isi, mmemme ọrịa kansa mba, Institutelọ Ọrụ Ọrịa Cancer nke Mba, 1975. == Edensibia == {{Reflist}} == Ọgụgụ ọzọ == * {{Cite book|author=Shearer|first=Benjamin & Barbara|title=Notable women in the life sciences : a biographical dictionary|url=https://archive.org/details/notablewomeninli0000unse|date=1996|publisher=Greenwood Press|location=Westport, Conn. [u.a.]|isbn=9780313293023|edition=1. publ.}} == Njikọ mpụga == * [http://www.fullerton.edu/ Profaịlụ], Fullerton.edu; enwetara Jenụwarị 13, 2018. {{s-start}} {{s-aca}} {{succession box|title=[[California State University Fullerton|President of California State University, Fullerton]]|before=[[Miles D. McCarthy]]|years=1981–1990|after=[[Milton A. Gordon]]}} {{s-end}} {{Authority control}} [[Òtù:Pages with unreviewed translations]] nami34mx9h38k5zhy6z7xqng6hw0zsy Jazmine Sullivan 0 12676 736835 727855 2026-10-08T04:00:25Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736835 wikitext text/x-wiki {{Infobox musical artist|name=Jazmine Sullivan|image=Jazmine_Sullivan_2015.jpg|caption=Sullivan at the ASCAP Rhythm & Soul Awards in [[Beverly Hills, California]] in 2015|birth_date={{Birth date and age|mf=yes|1987|04|09}}|birth_name=Jazmine Marie Sullivan|birth_place=[[Philadelphia]], [[Pennsylvania]], U.S.|death_date=|death_place=|genre={{hlist|[[Contemporary R&B|R&B]]|[[Soul music|soul]]|[[pop music|pop]]|[[reggae]]}}|occupation={{hlist|Singer-songwriter}}|instrument=[[Vocals]]|years_active=2003–present|label={{hlist|[[RCA Records|RCA]]|[[J Records|J]]|[[Arista Records|Arista]]}}|associated_acts={{hlist|[[Frank Ocean]]|[[Missy Elliott]]|[[Salaam Remi]]}}<!--Before adding acts, see [[Template:Infobox musical artist]]-->|website={{url|jazminesullivanmusic.com}}}} {{Databox}} '''Jazmine Marie Sullivan''' (amuru Eprel 9, 1987) bu onye America na-ede ukwe. Amụrụ na zụlitere na Philadelphia, album mbụ ya, E wepụtara ''Fearless'' na 2008 iji nwee ọganihu azụmahịa na nke siri ike. Ndekọ ahụ tolitere <nowiki><i id="mwDw">chaatị</i></nowiki> Album Top R<nowiki>&</nowiki>amp;B/Hip-Hop nke Billboard wee nweta nkwado ọla edo site n'aka ndị ụlọ ọrụ ndekọta nke America (RIAA). Ọ mụrụ ụmụ nwoke anọ, gụnyere " Mkpa U Bad " na " Bust Your Windows ", ha abụọ nọ n'elu 40 nke <nowiki><i id="mwFg">chaatị Billboard</i></nowiki> Hot 100 ; nke mbụ ghọrọ Sullivan nke mbụ na naanị ọnụọgụ mbụ na <nowiki><i id="mwGA">chaatị Billboard</i></nowiki> Hot R<nowiki>&</nowiki>amp;B/Hip-Hop . [[Category:Articles with hCards]] [[Òtù:Infobox musical artist with missing or invalid Background field| ]] [[Usòrò:Jazmine Sullivan 2015.jpg|thumb]] Sullivan sochiri nke a na album studio ya nke abụọ, ''Love Me Back'', na 2010, nke ndị nkatọ nabatara nke ọma. Mgbe ọ gbasịrị ezumike afọ atọ, Sullivan bịanyere aka na RCA Records wee wepụta album studio mbụ ya n'okpuru akara, ''Reality Show'', na 2015, ọ ghọkwara album nke abụọ ya na ọnụ ọgụgụ nke mbụ na Top R & B / Hip-Hop Albums chart. . Na 2021, o wepụtara EP mbụ ya nke ọma, ''Heaux Tales'' nke nwere otu " Bulie Mmetụta Gị ". Sullivan enwetala Grammy Awards abụọ, onyinye onyinye <nowiki><i id="mwJQ">Billboard</i></nowiki> Women in Music Awards, onyinye egwu egwu mkpụrụ obi abụọ, atọ NAACP Image Awards, na onyinye BET abụọ n'oge ọrụ ya. == Ndụ na ọrụ == === 1987–2006: Ndụ mbụ === Nne na nna Jazmine Sullivan bụ Don na Pam Sullivan. <ref name="birthcharts">{{Cite web|url=https://birthcharts.astro-seek.com/birth-chart/jazmine-sullivan-horoscope|title=Jazmine Sullivan Birth Chart Horoscope, Date of Birth, Astro|work=birthcharts.astro-seek.com}}</ref> Nne ya bụ onye bụbu onye ọbụ abụ ndabere maka Philadelphia International Records . <ref name="Ellis">{{Cite web|url=https://www.vibe.com/photos/feature-the-psychology-of-jazmine-sullivan|title=The Psychology of Jazmine Sullivan|author=Ellis|first=Stacy-Ann|date=January 13, 2015|work=Vibe}}</ref> Mgbe ọ dị afọ ise, nna ya rutere n'ọkwa dị ka onye nlekọta maka nnukwu ụlọ Strawberry Historic nke obodo na ngalaba Strawberry Mansion na ezinụlọ ya kwagara n'ime ebe akụkọ ihe mere eme. <ref>{{Cite book|url=https://books.google.com/books?id=hSYEAAAAMBAJ&q=jazmine+sullivan+her+father+landed+a+position+as+a+curator&pg=PA54|title=Vibe|author=Group|first=Vibe Media|date=July 1, 2008|publisher=Vibe Media Group}}</ref> Sullivan bụ onye gụsịrị akwụkwọ na 2005 na ụlọ akwụkwọ sekọndrị Philadelphia maka imepụta nka na ime nka ebe ọ bụ onye isi egwu olu. Sullivan malitere ịbụ abụ dị ka contralto n'ime ukwe ụmụaka, ma emesịa n'òtù ukwe okenye. Sullivan ekpughere egwu ụwa amachaghị na mbụ. <ref>{{Cite web|url=https://www.youtube.com/watch?v=JgGCiC4uwLs|archiveurl=https://web.archive.org/web/20150719231648/https://www.youtube.com/watch?v=JgGCiC4uwLs|archivedate=2015-07-19|title=Jazmine Sullivan performs "Accept What God Allows" on Apollo|work=YouTube|accessdate=January 14, 2015}}</ref> === 2003–2009: Mmalite ọrụ === [[Usòrò:Jazmine_Sullivan.jpg|thumb| Sullivan na-eme ndụ na ihe nkiri na Columbia, South Carolina na 2008.]] Na iri na ise Sullivan bịanyere aka na ''Jive Records'' . O dekọrọ otu ọba egwu, nke a na-ewepụtaghị ma emechaa wepụ ya na label. Sullivan nyere ụda olu maka Kindred the [[Families Need Fathers|Family]] Soul 's song, "Am" yana ụda ndabere na egwu "Party's Over", na aha egwu na 2003 mpụta mbụ ha ''nyefere n'ịhụnanya .'' <ref>{{Cite web|url=http://allhiphop.com/2008/08/05/jazmine-sullivan-more-than-the-next-lauryn-hill/|title=Jazmine Sullivan: More Than the Next Lauryn Hill|work=allhiphop.com|publisher=All Hip Hop|author=Iandoli|first=Kathy|accessdate=July 27, 2014}}</ref> <ref>Kindred The Family Soul - Surrender To Love (CD liner notes). Hidden Beach Recordings/Epic Records. EK 86491</ref> O bu ụzọ zute onye rapper Missy Elliott n'oge nnọkọ ahụ; Elliott gara n'ihu wepụta ma ọtụtụ n'ime album mbụ ya, ''enweghị atụ egwu'' na egwu na ''Love Me Back.'' <ref>{{Cite book|author=Sullivan, Jazmine, 1987- James, Stori. Sincere, Josephine. Bremner, Freedom. Crockett, Alison. Cooper, Damon. Maiysha. Suter, Alexis P. S.Maily. Miata, Mia.|title=Soul in the city.|date=2004|publisher=Glory Records|oclc=320957015}}</ref> Sullivan dere ma dekọọ ya na ndị na-emepụta Cool &amp;amp; Dre egwu akpọrọ " Kwuo m " na ndị na-emepụta Cool &amp;amp; Dre ; Enyere ya enyi nwanyị Dre Christina Milian n'oge ahụ maka album nke atọ ya, ''So Amazin''' . <ref>{{Cite web|url=https://www.livexlive.com/artist/jazmine-sullivan|title=Jazmine Sullivan - LiveXLive - Premium Live Music|work=LiveXLive.com|accessdate=November 5, 2011}}</ref> Egwu a ghọrọ onye ndu otu, na-arị elu na nọmba 13 na egwu R&B/Hip-Hop dị ọkụ yana iru nọmba 21 na eserese Hot 100 . <ref>{{Cite web|url=https://www.billboard.com/music/christina-milian|title=Christina Milian Chart History|work=Billboard}}</ref> Sullivan's breakthrough song, " Need U Bad " wepụtara na Mee 2008. <ref name="allhiphop.com">{{Cite news|url=https://allhiphop.com/news/sunday-selection-jazmine-sullivan-need-u-bad-MgTy34Z7S0OJ94NifRoFTg/|title=Sunday Selection: Jazmine Sullivan - "Need U Bad"|work=AllHipHop.com|date=June 15, 2008|archive-date=May 1, 2019|access-date=April 7, 2022|archive-url=https://web.archive.org/web/20190501181843/https://allhiphop.com/news/sunday-selection-jazmine-sullivan-need-u-bad-MgTy34Z7S0OJ94NifRoFTg/|url-status=dead}}</ref> The song featured additional vocals by Missy Elliott and Sandy "Pepa" Denton of Salt-n-Pepa, emesia debuted na nọmba 37 na Billboard Hot 100 na nọ n'elu Hot R &amp;amp; B / [[Hip hop music|Hip Hop]] Songs maka 34 izu. <ref>{{Cite web|url=https://www.billboard.com/music/jazmine-sullivan/chart-history|title=Jazmine Sullivan Chart History|work=Billboard|publisher=Nielsen Business Media, Inc.|accessdate=October 28, 2010}}</ref> == Ụdị egwu na nka == N'otu aka ahụ, olu Sullivan na-agbanwe n'etiti "mmepụta ọgbara ọhụrụ" na "ụda mmetụta 1980" nke ndị nkatọ egwu na-ekwu na-enye ya "ụda hip hop ụlọ akwụkwọ ochie ". <ref>{{Cite web|url=https://blackmusicscholar.com/jazmine-sullivan/|title=Jazmine Sullivan|date=November 3, 2017|work=Black Music Scholar|accessdate=April 7, 2022|archivedate=May 8, 2021|archiveurl=https://web.archive.org/web/20210508195452/https://blackmusicscholar.com/jazmine-sullivan/}}</ref> <ref>{{Cite journal|author=Williams|first=Justin A.|title=The Construction of Jazz Rap as High Art in Hip-Hop Music|date=July 5, 2017|journal=From Soul to Hip Hop|pages=149–173|doi=10.4324/9781315093819-6}}</ref> Ụdị olu ya bụ contralto . <ref>{{Cite news|url=https://www.bostonglobe.com/arts/music/2015/04/21/sullivan-shares-her-stirring-reality-royale/WOp1QlCXgmbzkzi259IgLL/story.html|title=Jazmine Sullivan shares her stirring 'Reality' at Royale|work=[[The Boston Globe]]|date=April 21, 2015|accessdate=March 15, 2018|first=Maura|author=Johnston}}</ref> Olu ya nwere ike siri ike na ndekọ niile ma jikọta nke ọma n'etiti A2 na G5 .  ya nwere "olu dị nro ". <ref>{{Cite web|url=https://www.instyle.com/news/jazmine-sullivan-interview-raspy-voice|title=Jazmine Sullivan on Her Famously Raspy Voice and Wanting to Sound Like Mariah Carey|date=July 15, 2015|work=InStyle.com|language=en}}</ref> Ọ kọwara ụdị edemede ya dị ka “mgbagha azụ”, n'ịtụ aka na egwu ya gbasara mmekọrịta dara ada bụ nke na-akparị anụ ahụ na nke mmụọ. <ref>{{Cite web|url=https://pitchfork.com/thepitch/1016-jazmine-sullivan-on-songwritings-labor-of-love/|title=Jazmine Sullivan on Songwriting's Labor of Love|date=February 9, 2016|work=Pitchfork|accessdate=May 1, 2016}}</ref> <ref>{{Cite web|url=https://www.essence.com/news/jazmine-sullivan-opens-about-finding-joy-after-abuse/|title=Jazmine Sullivan Opens Up About Finding Joy After Abuse|work=Essence|language=en-US|accessdate=August 15, 2017}}</ref> Egwu ya na-egosipụta nzaghachi ya na mmekọrịta ndị a nke ọma na egwu ya " Bust Your Windows ". <ref>{{Cite web|url=https://revolt.tv/stories/2016/08/04/apparently-jazmine-sullivans-bust-windows-wasnt-poppin-song-3517d33cc0|title=Apparently Jazmine Sullivan's "Bust Your Windows" wasn't just a poppin' song|date=August 4, 2016|work=REVOLT TV|language=en|accessdate=April 7, 2022|archivedate=May 1, 2019|archiveurl=https://web.archive.org/web/20190501224453/https://revolt.tv/stories/2016/08/04/apparently-jazmine-sullivans-bust-windows-wasnt-poppin-song-3517d33cc0}}</ref> Ọ na-amasị ya ide banyere mmetụta ọ na-enwe, nke n'aka nke ya, na-ewe otu ụbọchị ma ọ bụ ihe ruru otu ọnwa iji mezue. <ref>{{Cite web|url=https://newsok.com/article/feed/1212142/jazmine-sullivan-to-beyonce-lets-make-lemonade-together/|title=Jazmine Sullivan to Beyonce: Let's make lemonade together!|date=April 28, 2017|work=NewsOK.com}}</ref> N'oge ndekọ nke album Reality Show, Sullivan jiri oge dị ukwuu na-emegharị ma na-edegharị ya, na ndị na-emepụta ihe ga-amanye ya ka ọ hapụ album ahụ iji gbochie nkwụsị oge. <ref>{{Cite web|url=https://www.greensboro.com/entertainment/jazmine-sullivan-grammy-nods-and-getting-her-groove-back/article_fc0a41c7-67da-5ca7-ab52-3097b192e53a.html|title=Jazmine Sullivan: Grammy nods and getting her groove back|author=Press|first=Melanie J. Sims The Associated|work=Greensboro News and Record|accessdate=February 4, 2016}}</ref> A maara Sullivan nke ọma maka ide egwu nke ya nke na-eme ka ama ama ya na ndị nkatọ na ndị na-akwado ya. <ref>{{Cite web|url=https://www.vulture.com/2016/02/toughest-song-i-wrote-jazmine-sullivan-brand-new.html|title=The Toughest Song I Wrote: Jazmine Sullivan on What Happens When a Kendrick Feature Falls Through|date=February 8, 2016|work=Vulture.com|accessdate=February 14, 2016}}</ref> Edepụtara egwu Sullivan " Bust Your Windows " na nọmba 137 na ndepụta National Public Radio nke abụ 200 Kachasị Kasị Mma Site na narị afọ nke 21st ụmụ nwanyị. <ref name="npr.org">{{Cite web|url=https://www.npr.org/2018/07/30/627396669/turning-the-tables-the-200-greatest-songs-by-21st-century-women-part-4|title=The 200 Greatest Songs By 21st Century Women+ (140-121)|work=NPR.org|language=en|accessdate=October 12, 2018}}</ref> == Ndụ onwe onye == Na Mee 11, 2020, Sullivan kwupụtara na nne ya Pam achọpụtala ọrịa kansa na-egbu egbu na Ọktoba 2019. <ref name="Essence 2020">{{Cite web|author=Grant|first=Jasmine|title=Jazmine Sullivan Loves And Uplifts Her Mom As She Battles Breast Cancer|url=https://www.essence.com/love/celebrity-mothers-day-posts-2020/|work=[[Essence (magazine)|Essence]]|date=May 11, 2020|accessdate=June 12, 2020}}</ref> <ref>{{Cite news|title=Jazmine Sullivan's Mother Has Breast Cancer, Singer Shaves Her Head In Solidarity [VIDEO]|url=https://classipress.co.ke/jazmine-sullivans-mother-has-breast-cancer-singer-shaves-her-head-in-solidarity-video/|accessdate=June 12, 2020|work=[[MadameNoire]]|date=May 11, 2020|archive-date=June 12, 2020|archive-url=https://web.archive.org/web/20200612231510/https://classipress.co.ke/jazmine-sullivans-mother-has-breast-cancer-singer-shaves-her-head-in-solidarity-video/|url-status=dead}}</ref> N'akwụkwọ ozi Instagram ya, o dere, sị: "Ọ bụrụ na ịbụ nwa gị nwanyị kụziiri m otu ihe bụ ka esi arụ ọrụ na ihe jọrọ njọ, na-egbu mgbu ma mee ka ọ bụrụ ọrụ nkà". <ref name="Essence 2020" /> == Ihe ngosi == * ''Atụghị egwu'' (2008) * ''Hụrụ m n'anya azụ'' (2010) * ''Ihe ngosi eziokwu'' (2015) * ''Akụkọ Heaux'' (2021) == Njegharị egwu egwu == ; Isi akụkọ * Njem ihe ngosi nke eziokwu (2015) * Njegharị Heaux Tales (2022) ; Nchịkọta isiokwu * Afọ nke njem ndị Gentlemen (2009) == Ihe nrite na nhọpụta == {| class="wikitable sortable plainrowheaders" ! scope="col" |Organization ! scope="col" |Year ! scope="col" |Category ! scope="col" |Nominated work ! scope="col" |Result ! class="unsortable" scope="col" |{{Abbr|Ref.|References}} |- ! rowspan="3" scope="row" |American Music Awards | rowspan="3" |2021 |Favorite Soul/R&amp;amp;B Female Artist |Herself | {{Nom}} | rowspan="3" align="center" |<ref>{{Cite web|url=https://www.billboard.com/articles/news/awards/9652065/2021-ama-nominations-list-american-music-awards|title=Olivia Rodrigo Leads 2021 American Music Awards Nominations: Full List}}</ref> |- |Favorite Soul/R&amp;amp;B Album |''Heaux Tales'' | {{Nom}} |- |Favorite Soul/R&amp;amp;B Song |"Pick Up Your Feelings" | {{Nom}} |- ! rowspan="6" scope="row" |BET Awards | rowspan="3" |2009 |Best Female R&amp;amp;B Artist | rowspan="3" |Herself | {{Nom}} | rowspan="3" style="text-align:center;" |<ref>{{Cite web|url=https://latimesblogs.latimes.com/awards/2009/06/best-male-rbthe-dreamjamie-foxxryan-lesliene-yot-pain--best-female-rb-artistbeyonc%C3%A9-knowleskeyshia-colekeri-hilsonjennifer-h.html|title=BET Awards 2009 list of winners|date=June 18, 2009|work=LA Times Blogs - Awards Tracker|accessdate=May 1, 2013}}</ref><ref>{{Cite web|url=https://www.bet.com/shows/bet-awards/2009/nominees.html?cid=facebook|title=BET Awards 2009 Winners & Nominees|work=BET.com|accessdate=May 1, 2019|archive-date=September 20, 2020|archive-url=https://web.archive.org/web/20200920205133/https://www.bet.com/shows/bet-awards/2009/nominees.html?cid=facebook|url-status=dead}}</ref> |- |Best New Artist | {{Nom}} |- |J Award | {{Won}} |- |2015 |Centric Award |"Dumb" | {{Nom}} | style="text-align:center;" | |- | rowspan="2" |2021 |Album of the Year |''Heaux Tales'' | {{Won}} | rowspan="2" style="text-align:center;" |<ref>{{Cite web|author=Nordyke|first=Kimberly|title=BET Awards: Winners List (Updating Live)|url=https://www.hollywoodreporter.com/tv/tv-news/bet-awards-2021-winners-list-1234974508/|work=[[The Hollywood Reporter]]|accessdate=June 28, 2021|date=June 27, 2021}}</ref> |- |Best Female R&B Artist |Herself | {{Nom}} |- ! scope="row" |<nowiki><i id="mwAiA">Billboard</i></nowiki> Women in Music |2010 |Rising Star Award |Herself | {{Won}} | style="text-align:center;" |<ref>{{Cite web|url=https://www.billboard.com/articles/news/949865/jazmine-sullivan-thrilled-to-succeed-gaga-as-billboards-rising-star|title=Jazmine Sullivan Thrilled to Succeed Gaga As Billboard's Rising Star|work=Billboard|accessdate=May 1, 2011}}</ref> |- ! rowspan="15" scope="row" |Grammy Awards | rowspan="5" |2009 |Best New Artist |Herself | {{Nom}} | rowspan="5" style="text-align:center;" |<ref>{{Cite news|url=https://www.usatoday.com/life/music/awards/grammys/2008-12-03-grammy-nominations_N.htm|title=Nominations for the 51st Grammy Awards|work=[[USA Today]]|date=February 4, 2009|accessdate=June 29, 2012}}</ref> |- |Best Female R&amp;amp;B Vocal Performance |"Need U Bad" | {{Nom}} |- |Best Traditional R&amp;amp;B Performance |"In Love With Another Man" | {{Nom}} |- |Best R&amp;amp;B Song |"Bust Your Windows" | {{Nom}} |- |Best Contemporary R&amp;amp;B Album |''Fearless'' | {{Nom}} |- | rowspan="2" |2010 |Best Female R&B Vocal Performance | rowspan="2" |"Lions, Tigers &amp;amp; Bears" | {{Nom}} | rowspan="2" style="text-align:center;" |<ref>{{Cite web|url=https://www.npr.org/2010/01/29/123139144/one-diva-at-a-time-r-b-at-the-grammys|title=One Diva At A Time: R&B At The Grammys|work=[[NPR]]|language=en|accessdate=July 13, 2012}}</ref> |- |Best R&B Song | {{Nom}} |- |2011 |Best Female R&B Vocal Performance |"Holding You Down (Goin' in Circles)" | {{Nom}} | style="text-align:center;" |<ref>{{Cite web|url=https://hiphopnc.com/1251361/2011-grammy-nominations-jazmine-rihanna-sade-fantasia-nicki-up-for-awards/|title=2011 Grammy Nominations! Jazmine, Rihanna, Sade, Fantasia & Nicki Up For Awards!|date=December 2, 2010|work=K97.5|accessdate=January 19, 2011}}</ref> |- | rowspan="3" |2016 |Best Traditional R&B Performance | rowspan="2" |"Let It Burn" | {{Nom}} | rowspan="3" style="text-align:center;" |<ref>{{Cite web|url=https://people.com/awards/grammys-2016-jazmine-sullivans-reality-show/|title=You Almost Didn't Get to Hear Jazmine Sullivan's Grammy-Nominated Album|work=[[People (magazine)|People]]|accessdate=September 12, 2016}}</ref> |- |Best R&B Song | {{Nom}} |- |Best R&amp;amp;B Album |''Reality Show'' | {{Nom}} |- |2020 |Best Traditional R&B Performance |"Built for Love" | {{Nom}} | style="text-align:center;" | |- | rowspan="3" |2022 |Best R&amp;amp;B Performance | rowspan="2" |"Pick Up Your Feelings" | {{Won}}{{efn|Tied with [[Silk Sonic]] for "[[Leave the Door Open]]".}} | rowspan="3" style="text-align:center;" |<ref>{{Cite web|url=https://www.grammy.com/grammys/news/2022-grammys-complete-winners-nominees-nominations-list|title=2022 GRAMMYs Awards Show: Complete Nominations List|work=Grammy|accessdate=November 23, 2021|archive-date=December 20, 2021|archive-url=https://web.archive.org/web/20211220010438/https://www.grammy.com/Grammys/news/2022-Grammys-complete-winners-nominees-nominations-list|url-status=dead}}</ref> |- |Best R&amp;amp;B Song | {{Nom}} |- |Best R&amp;amp;B Album |''Heaux Tales'' | {{Won}} |- ! rowspan="9" scope="row" |NAACP Image Awards |2009 |Outstanding New Artist |Herself | {{Nom}} | style="text-align:center;" |<ref>{{Cite web|url=https://variety.com/2009/biz/awards/bees-flies-high-at-image-awards-1117998104/|title='Bees' flies high at Image Awards|author=Hite|first=N'neka|date=January 7, 2009|work=Variety|language=en|accessdate=May 1, 2019}}</ref><ref>{{Cite news|url=https://www.reuters.com/article/us-imageawards-idUSTRE51C12F20090213|title="Dreamgirl" Hudson dominates NAACP Image awards|date=February 13, 2009|work=Reuters|accessdate=May 1, 2019|language=en}}</ref> |- | rowspan="2" |2016 |Outstanding Female Artist |Herself | {{Nom}} | rowspan="2" style="text-align:center;" |<ref name="NAACP 2016">{{Cite web|url=https://www.billboard.com/articles/news/6792632/naacp-image-awards-nominees-2016|title=Janet Jackson Leads 2016 NAACP Image Awards Music Nominations|work=Billboard|accessdate=May 31, 2016}}</ref><ref>{{Cite web|url=https://www.hollywoodreporter.com/lists/2016-naacp-image-award-winners-862137|title=NAACP Image Awards: The Complete Winners List|work=The Hollywood Reporter|accessdate=September 12, 2016}}</ref> |- | rowspan="2" |Outstanding Song |"Let It Burn" | {{Nom}} |- |2018 |"Insecure" | {{Nom}} | style="text-align:center;" | |- |2021 | rowspan="2" |Outstanding Female Artist | rowspan="2" |Herself | {{Nom}} | style="text-align:center;" |<ref>{{Cite web|title=2021 NAACP Image Awards: The Complete Winners List|url=https://www.etonline.com/2021-naacp-image-awards-winners-list-162717|work=[[E! Online]]|accessdate=June 28, 2021|date=March 29, 2021|archivedate=April 15, 2021|archiveurl=https://web.archive.org/web/20210415125256/https://www.etonline.com/2021-naacp-image-awards-winners-list-162717}}</ref> |- | rowspan="4" |2022 | {{Won}} | rowspan="4" style="text-align:center;" |<ref>{{Cite web|author=Spivey|first=Kemberlie|date=2022-01-19|title=2022 NAACP Image Awards Nominations: The Full List|url=https://www.forbes.com/sites/kemberliespivey/2022/01/18/2022-naacp-image-awards-nominations-the-full-list/|accessdate=2022-01-20|work=[[Forbes]]|language=en}}</ref><ref>{{Cite web|title=Nominees Archive|url=https://naacpimageawards.net/nominees/|accessdate=2022-02-27|work=NAACP Image Awards|language=en-US|archivedate=2017-12-06|archiveurl=https://web.archive.org/web/20171206053924/http://www.naacpimageawards.net/nominees}}</ref> |- |Outstanding Album |''Heaux Tales'' | {{Won}} |- |Outstanding Duo, Group or Collaboration (Traditional) |"Girl Like Me" <small>(featuring H.E.R.</small><small>)</small> | {{Nom}} |- |Outstanding Soul/R&B Song |"Pick Up Your Feelings” | {{Won}} |- ! rowspan="8" scope="row" |Soul Train Music Awards |2009 |Best New Artist |Herself | {{Nom}} | style="text-align:center;" |<ref>{{Cite web|title=2009 Soul Train Awards|url=https://www.rap-up.com/2009/11/04/2009-soul-train-awards/|work=Rap Up|access-date=2022-04-07|archive-url=https://web.archive.org/web/20220516144002/https://www.rap-up.com/2009/11/04/2009-soul-train-awards/|archive-date=2022-05-16|url-status=dead}}</ref> |- |2017 |Best Collaboration |"Insecure" <small>(with Bryson Tiller)</small> | {{Nom}} | style="text-align:center;" |<ref>{{Cite web|url=http://www.billboard.com/articles/columns/hip-hop/8005601/soul-train-awards-2017-nominees-solange-bruno-mars-bet|title=Solange, Bruno Mars Lead 2017 Soul Train Awards Nominations|publisher=Billboard|date=October 17, 2017|accessdate=October 17, 2017}}</ref> |- | rowspan="6" |2021 |Song of the Year | rowspan="3" |"Pick Up Your Feelings" |{{Nom}} | rowspan="6" |<ref>{{Cite web|title=H.E.R. Is Top Nominee at 2021 Soul Train Awards; Maxwell & Ashanti to Receive Special Awards: Exclusive|url=https://www.billboard.com/articles/news/awards/9654359/her-2021-soul-train-awards-nominees/?utm_medium=social&utm_source=twitter|accessdate=2021-11-02|work=Billboard|language=en-US}}</ref> |- |Video of the Year | {{Nom}} |- |The Ashford and Simpson Songwriter of the Year Award | {{Nom}} |- |Best Collaboration |"Girl Like Me" <small>(featuring H.E.R.</small><small>)</small> | {{Nom}} |- |Best R&amp;amp;B/Soul Female Artist |Herself | {{Won}} |- |Album of the Year |''Heaux Tales'' | {{Won}} |} == Hụkwa == * Ndepụta nke nọmba Billboard-otu ọba R&amp;amp;B nke 2008 * Ndepụta nke R&amp;amp;B nọmba-otu otu nke 2008 (US ) == Ihe ndetu == {{Notelist}} == Ntụaka == {{Reflist}} <references /> == Njikọ mpụga == * Official website [[Òtù:Mmadụ ndi di ndụ]] [[Òtù:Pages with unreviewed translations]] r8av5jqcwqw6j8cy0bqyetcmjwcva45 Joyce Banda 0 12758 736847 735454 2026-10-08T06:12:21Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736847 wikitext text/x-wiki {{Infobox officeholder | honorific-prefix = [[Her Excellency]] | name = Joyce Banda | image = President of Malawi Joyce Banda (8985928177).jpg | caption = Banda in 2013 | office = 4th [[President of Malawi]] | vicepresident = [[Khumbo Kachali]] | term_start = 7 April 2012 | term_end = 31 May 2014 | predecessor = [[Bingu wa Mutharika]] | successor = [[Peter Mutharika]] | office1 = [[Vice-President of Malawi|Vice President of Malawi]]<ref>{{Cite web |url=http://www.opc.gov.mw/index.php/presidency/menu-showcase-2/dr-joyce-banda |title=Archived copy |access-date=25 April 2018 |archive-url=https://web.archive.org/web/20180426082920/http://www.opc.gov.mw/index.php/presidency/menu-showcase-2/dr-joyce-banda |archive-date=26 April 2018 |url-status=dead |accessdate=11 April 2022 |archivedate=26 April 2018 |archiveurl=https://web.archive.org/web/20180426082920/http://www.opc.gov.mw/index.php/presidency/menu-showcase-2/dr-joyce-banda }}</ref> | president1 = [[Bingu wa Mutharika]] | term_start1 = 29 May 2009 | term_end1 = 7 April 2012 | predecessor1 = [[Cassim Chilumpha]] | successor1 = [[Khumbo Kachali]] | office2 = [[Minister of Foreign Affairs (Malawi)|Minister of Foreign Affairs]] | president2 = [[Bingu wa Mutharika]] | term_start2 = 1 June 2006 | term_end2 = 29 May 2009 | predecessor2 = [[George Chaponda]] | successor2 = [[Etta Banda]] | office3 = Minister of Gender, Child Welfare, and Community Service | president3 = [[Bingu wa Mutharika]] | term_start3 = 2004 | term_end3 = 2006 | birth_name = Joyce Hilda Ntila | birth_date = {{birth date and age|1950|4|12|df=y}} | birth_place = [[Malemia, Zomba|Malemia]], [[Nyasaland]]<br />(now [[Malawi]]) | death_date = | death_place = | party = [[United Democratic Front (Malawi)|United Democratic Front]] (Before 2004)<br />[[Democratic Progressive Party (Malawi)|Democratic Progressive Party]] (2004–2010)<br />[[People's Party (Malawi)|People's Party]] (2011–present) | spouse = Roy Kachale (Before 1981)<br />[[Richard Banda]] | children = 5 | alma_mater = [[Columbus University (Louisiana)|Columbus University]]<br />[[Atlantic International University]]<br />[[Royal Roads University]] }}{{Databox}} '''Joyce Hilda Banda''' (née '''Ntila''' ; amụrụ 12 Eprel 1950 <ref>{{Cite web|url=https://mwnation.com/ew%E2%80%99s-big-interview-joyce-banda/|title=EW's big Interview: Joyce Banda|publisher=The Nation|date=21 September 2014|accessdate=5 February 2019|archivedate=26 September 2017|archiveurl=https://web.archive.org/web/20170926005214/http://mwnation.com/ew%E2%80%99s-big-interview-joyce-banda/}}</ref> ) bụ onye ndọrọ ndọrọ ọchịchị [[Malawi]] bụ onye isi ala Malawi site na 7 Eprel 2012 ruo 31 Mee 2014. Banda weghaara ọkwa dịka onye isi ala na-esochi ọnwụ mberede nke Onye isi ala Bingu wa Mutharika . Ọ bụ onye hiwere ma bụrụ onye ndu nke People's Party, otu ndọrọ ndọrọ ọchịchị nke e kere n'afọ 2011. <ref>{{Cite web|author=Malawi|first=People's Party|title=People's Party|url=http://www.peoples-party-malawi.org/|publisher=People's Party Malawi|accessdate=10 April 2012|archiveurl=https://web.archive.org/web/20120415140346/http://www.peoples-party-malawi.org/|archivedate=15 April 2012}}</ref> Onye nkuzi na onye na-akwado ikike ụmụ nwanyị, ọ bụ onye minista nke mba ofesi site na 2006 ruo 2009 na osote onye isi ala Malawi site na Mee 2009 ruo Eprel 2012. <ref>{{Cite web|url=https://www.bbc.co.uk/news/world-africa-17644009|title=Joyce Banda sworn in as new Malawi president|publisher=The BBC|date=7 April 2012|accessdate=7 April 2012}}</ref> Ọ rụrụ ọrụ dị iche iche dị ka onye otu nzuko omeiwu na onye minista na-ahụ maka ọdịmma nwoke na nwanyị na ọdịmma ụmụaka tupu ọ ghọọ onye isi ala nke mba Malawi. <ref name=":0"/> Tupu ya arụọ ọrụ na ndọrọ ndọrọ ọchịchị, ọ bụ onye hiwere Joyce Banda Foundation, ọ bụkwa onye tọrọ ntọala National Association of Business Women (NABW), Young Women Leaders Network nakwa Hunger Project. Banda bụ onye isi ala nke anọ nke Malawi <ref name="Mwagiru">{{Cite journal|author=Mwagiru|first=Ciugu|date=18 April 2012|title=Malawi's Joyce Banda and the rise of women in African politics|url=http://www.monitor.co.ug/artsculture/Reviews/-/691232/1388740/-/diw45/-/|journal=[[Daily Monitor]]|accessdate=19 April 2012}}</ref> na onye isi ala nwanyị mbụ ya na nwanyị nke abụọ bụrụ onye isi mgbe Elizabeth II gasịrị . Ọ bụ nwanyị nke abụọ ghọrọ onye isi ala na kọntinent Africa, <ref name=":0"/> ka Ellen Johnson Sirleaf nke Liberia gasịrị. Ọ bụkwa osote onye isi ala nwanyị mbụ nke mba ahụ. <ref name="Tribune">{{Cite journal|author=Olamitoke|first=Toluwani|date=14 April 2012|title=As Fate Throws Leadership in Joyce Banda's Path...Becomes Malawi's First Female President|url=http://www.tribune.com.ng/sat/index.php/women-affairs/7087-as-fate-throws-leadership-in-joyce-bandas-pathbecomes-malawis-first-female-president.html|journal=[[Nigerian Tribune]]|accessdate=14 April 2012|archive-date=14 April 2012|archive-url=https://web.archive.org/web/20120414171037/http://www.tribune.com.ng/sat/index.php/women-affairs/7087-as-fate-throws-leadership-in-joyce-bandas-pathbecomes-malawis-first-female-president.html|url-status=dead}}</ref> Na June 2014, Forbes kpọrọ President Banda dị ka nwanyị nke iri anọ kachasị ike n'ụwa na nwanyị kachasị ike na Africa. <ref name="Forbes14">{{Cite web|title=The World's 100 Most Powerful Women|url=https://www.forbes.com/power-women/list/#tab:overall|work=Forbes|accessdate=24 June 2014}}</ref> N'October 2014, etinyere ya na ụmụ nwanyị otu narị nke ụlọọrụ BBC . <ref>{{Cite web|url=https://www.bbc.com/news/world-29758792|title=Who are the 100 Women 2014?|work=BBC|date=26 October 2014}}</ref> == Ndụ onwe na ezinụlọ == A mụrụ Joyce Hilda Ntila <ref name="Tenthani">{{Cite journal|author=Tenthani|first=Raphael|title=Joyce Banda: Malawi's first female president|journal=BBC News, Blantyre|date=10 April 2012|url=http://m.bbc.co.uk/news/world-africa-17662916|accessdate=15 April 2012|archive-date=1 May 2014|archive-url=https://web.archive.org/web/20140501023103/http://m.bbc.co.uk/news/world-africa-17662916|url-status=dead}}</ref> na 12 Eprel 1950 na Malemia, obodo dị na mpaghara Zomba nke Nyasaland (ugbu a Malawi). <ref>{{Cite web|title=Malawian president quietly celebrates 62nd birthday|url=http://www.nyasatimes.com/malawi/2012/04/12/malawian-president-quietly-celebrates-62nd-birthday/|publisher=Nyasa Times|accessdate=14 April 2012|archiveurl=https://web.archive.org/web/20120414023610/http://www.nyasatimes.com/malawi/2012/04/12/malawian-president-quietly-celebrates-62nd-birthday/|archivedate=14 April 2012}}</ref> <ref name="bdayparty">{{Cite web|title=JB Celebrates Her 62 Birthday in Private|url=http://www.malawivoice.com/2012/04/12/jb-celebrates-her-62-birthday-in-private-67799/|publisher=Malawi Voice|accessdate=14 April 2012|archiveurl=https://web.archive.org/web/20120414080836/http://www.malawivoice.com/2012/04/12/jb-celebrates-her-62-birthday-in-private-67799/|archivedate=14 April 2012}}</ref> Nna ya bụ onye uwe ojii na-gu egwu brass. Ọ malitere ọrụ ya dị ka odeakwụkwọ ma ghọọ onye a ma ama n'oge ọchịchị aka ike nke Hastings Banda (ha enweghị njikọ). <ref name="Mponda">{{Cite web|author=Mponda|first=Felix|title=Joyce Banda poised for Malawi presidency|work=Google hosted news: AFP|date=6 April 2012|url=https://www.google.com/hostednews/afp/article/ALeqM5jOpjFWpYrm2b4Zl0peP6slJ4dB3A?docId=CNG.d8ee654dd734a2011258c4f87f9da37b.b21|accessdate=20 April 2012}}</ref> O nwere asambodo nke ụlọ akwụkwọ Cambridge, nzere bachelọ nke Arts na nkuzi nwata sitere na Mahadum Columbus (ụlọ akwụkwọ agụmakwụkwọ dị anya nke a na-akwadoghị), <ref name="Tribune"/> na nzere bachelọ nke Social Studies na Gender Studies sitere na Mahadum Atlantic International (nke a bụkwa ụlọakwụkwọ mmụta dị anya) na Diploma na Management nke NGO sitere na International Labour Organisation (ILO) Center na Turin, Italy. Ugbu a, ọ na-agụ akwụkwọ maka Master of Arts Degree in Leadership na Royal Roads University na [[Kánada|Canada]] . <ref>{{Cite web|url=http://www.malawi.gov.mw/index.php?option=com_content&view=article&id=84&Itemid=197|title=The President's Profile|archiveurl=https://web.archive.org/web/20121112091140/http://www.malawi.gov.mw/index.php?option=com_content&view=article&id=84&Itemid=197|archivedate=12 November 2012}}</ref> Ọ nwetara nzere doctorate na 2013 site na Mahadum Jeonju . <ref>{{Cite web|url=http://www.newstimeafrica.com/archives/30690|title=Korean University honour Malawi President: Now Dr. Joyce Banda}}</ref> Ọ lụrụ Roy Kachale, bụ́ onye ya na ya mụrụ ụmụ atọ. Mgbe ọ dị afọ iri abụọ na ise, ọ biri na Nairobi, [[Kenya]] . <ref name="Nairobi">{{Cite journal|author=Sigei|first=Julius|title=How Nairobi shaped future president|journal=Sunday Nation|date=15 April 2012|url=http://www.nation.co.ke/News/How+Nairobi+shaped+future+president+/-/1056/1386170/-/item/1/-/c4548d/-/index.html|accessdate=15 April 2012|archive-date=15 April 2012|archive-url=https://web.archive.org/web/20120415032159/http://www.nation.co.ke/News/How+Nairobi+shaped+future+president+/-/1056/1386170/-/item/1/-/c4548d/-/index.html|url-status=dead}}</ref> Na 1975, otu òtù ụmụ nwanyị na-eto eto na Kenya kpaliri Banda ịkpọrọ ụmụ ya atọ hapụ ihe ọ kọwara dị ka alụmdi na nwunye mkparị. <ref>{{Cite web|author=Raphael Tenthani|url=http://www.businessday.co.za/articles/Content.aspx?id=169626|title=Malawi's new leader takes charge with energy|publisher=BusinessDay|date=13 April 2012|accessdate=23 May 2012|archivedate=17 April 2012|archiveurl=https://web.archive.org/web/20120417191744/http://www.businessday.co.za/articles/Content.aspx?id=169626}}</ref> Alụmdi na nwunye ya na Roy Kachele biri na 1981. Ọ lụrụ Richard Banda, onye ọka ikpe Malawi lara ezumike nká, onye ya na ya nwere ụmụ abụọ. <ref name="energy">{{Cite web|author=Tenthani|first=Raphael|title=Malawi's new president takes charge with energy|work=ABC News, Associated Press, 2nd page|date=13 April 2012|url=https://abcnews.go.com/International/wireStory/malawis-president-takes-charge-energy-16129884#.T4zdcNUzCSo|accessdate=16 April 2012}}</ref> <ref name="Al Jazeera">{{Cite web|author=Mutasa|first=Haru|title=Malawi to begin treason trial of ex-officials|work=Al Jazeera|date=10 April 2013|url=http://www.aljazeera.com/news/africa/2013/04/201341073057327861.html|accessdate=10 April 2013}}</ref> N'agbata 1985 na 1997 Banda jisiri ma guzobe azụmaahịa na otu dị iche iche gụnyere Ndekani Garments (1985), Akajuwe Enterprises (1992), na Kaligidza Bakery (1995). Ihe ịga nke ọma ya kpaliri ya inyere ụmụ nwanyị ndị ọzọ aka inweta nnwere onwe n'ego ma mebie usoro mmegbu na ịda ogbenye. Ọ bụ nwanne Anjimile Oponyo, onye bụbu onye isi oche nke <ref name="Friedman">{{Cite journal|author=Friedman|first=Roger|authorlink=Roger Friedman|title=Madonna May Have Problems with the New President of Malawi—She Fired Her Sister|journal=Forbes Online|date=9 April 2012|url=https://www.forbes.com/sites/rogerfriedman/2012/04/09/madonna-may-have-problems-with-the-new-president-of-malawi-she-fired-her-sister/|accessdate=17 April 2012|archive-url=https://web.archive.org/web/20120414012415/http://www.forbes.com/sites/rogerfriedman/2012/04/09/madonna-may-have-problems-with-the-new-president-of-malawi-she-fired-her-sister/|archive-date=14 April 2012|url-status=dead}}</ref> Raising Malawi Academy for Girls, nke [[Madonna]] kwadoro. <ref name="Madonna">{{Cite journal|author=Fekadu|first=Mesfin|title=Madonna: I'm happy Joyce Banda is Malawi's leader|journal=Boston Globe|date=13 April 2012|url=http://www.boston.com/ae/celebrity/articles/2012/04/13/madonna_im_happy_joyce_banda_is_malawis_leader/|accessdate=17 April 2012|archive-url=https://web.archive.org/web/20120416171917/http://www.boston.com/ae/celebrity/articles/2012/04/13/madonna_im_happy_joyce_banda_is_malawis_leader/|archive-date=16 April 2012|url-status=dead}}</ref> == Ndụ ndọrọ ndọrọ ọchịchị == === Ọkwa ọha (1999-2009) === Joyce Banda banyere ndọrọ ndọrọ ọchịchị na 1999. Ọ meriri oche ndị omeiwu na ntuli aka onye kwuo uche ya nke atọ nke Malawi dịka onye so na pati President Bakili Muluzi a kpọrọ United Democratic Front . Ọ nọchitere anya mpaghara Zomba Malosa . Muluzi họpụtara ya ka ọ bụrụ onye minista na-ahụ maka okike na ọrụ obodo. <ref name="Mponda"/> Dị ka onye jị ọkwa Minista, ọ lụrụ ọgụ iji wepụta Iwu Ime Ihe Ike n'Ụlọ, nke dara afọ asaa. Ọ haziri National Platform for Action on Orphans and vulnerable children na Zero Tolerance Campaign Against Child Abuse. <ref name="unfpa">[https://web.archive.org/web/20101202061622/http://www.americansforunfpa.org/netcommunity/page.aspx?pid=353 Friends of UNFPA] {{webarchive|url=https://web.archive.org/web/20101202061622/http://www.americansforunfpa.org/netcommunity/page.aspx?pid=353 |date=2 December 2010 }}. Americansforunfpa.org. Retrieved 10 April 2012.</ref> N'afọ 2004, a họpụtara ya ọzọ dịka onye otu Muluzi's Party. Bingu wa Mutharika ghọrọ Onye isi ala . N'agbanyeghị na Banda abụghị onye otu ya, Mutharika họpụtara ya ka ọ bụrụ onye minista na-ahụ maka mba ofesi na 2006. Banda kwagara ịgbanwe nnabata Malawi maka ọchịchị ziri ezi nke China site na Republic of China (na Taiwan) gaa na [[China|Republic of China]] na ala; o kwuru na ngbanwe ahụ ga-ewetara Malawi uru akụ na ụba. <ref name="Mponda"/> Na 2010, China rụchara ụlọ omeiwu ọhụrụ na Lilongwe. <ref name="parliament">{{Cite web|title=China hands over new parliament building to Malawi|work=People's Daily Online, English|publisher=Xinhua|date=22 May 2010|url=http://english.people.com.cn/90001/90776/90883/6994852.html|accessdate=22 April 2012}}</ref> === Osote onye isi ala (2009-2012) === Banda zọrọ ọkwa nke onye osote onye isi dika onye otu nke Democratic Progressive Party (DPP) na ntuli aka onye isi ala nke 2009, na-eso Mutharika, onye ndoro-ndoro ochichi DPP. <ref>[http://www.int.iol.co.za/index.php?set_id=1&click_id=84&art_id=nw20090517062152198C571749 "Women are ready to stand in Malawi poll"], Sapa-AFP (''IOL''), 17 May 2009.</ref> Ọ rụrụ ọrụ dịka osote onye isi ala nwanyị mbụ Malawi. N'ụzọ dị ịtụnanya nke DPP, a chụrụ Joyce Banda na osote onye isi oche nke abụọ Khumbo Kachali n'ọrụ dị ka osote onye isi oche nke DPP na 12 Disemba 2010 maka mmemme 'megidere Patị ahụ' nke na-enweghị nkọwa. <ref name="google">{{Cite web|url=https://www.google.com/hostednews/afp/article/ALeqM5hL67jrYgDT7owjKuvbRyuFCXkkqg?docId=CNG.52397de5df64c519397daac1afa54385.ed1|title=AFP: Malawi ruling party fires two vice presidents|date=11 December 2010|accessdate=7 April 2012}}</ref> N'ịgbalị ịchụpụ ya, Onye isi ala gara n'ihu na-enye Callista Mutharika ọrụ ndị ọ na-arụbu, bụ onye a gụnyere n'ụlọ ọrụ na September 2011. <ref name="snub">{{Cite web|url=http://www.afriquejet.com/malawi-cabinet-snub-2011090921991.html|title=Malawi: Mutharika's estranged deputy 'unmoved' by Malawi cabinet snub|publisher=Afriquejet.com|accessdate=7 April 2012|archiveurl=https://web.archive.org/web/20120612062217/http://www.afriquejet.com/malawi-cabinet-snub-2011090921991.html|archivedate=12 June 2012}}</ref> Ụlọ ikpe gbochiri mbọ Mutharika ịchụ ya dị ka osote onye isi ala n'ihi usoro iwu. Nke a gụnyere ịgbalị ijide ụgbọ ala gọọmentị ya na igbochi ya idebanye aha pati ọhụrụ ya. <ref>{{Cite web|url=http://www.maravipost.com/malawi-politics/society/5522-new-natl-congress-party-on-the-cards-court-orders-pps-registration.html|title=Archived copy|work=www.maravipost.com|accessdate=13 January 2022|archiveurl=https://web.archive.org/web/20200531055912/http://www.maravipost.com/malawi-politics/society/5522-new-natl-congress-party-on-the-cards-court-orders-pps-registration.html|archivedate=31 May 2020}}</ref> <ref>{{Cite web|url=http://www.mwnation.com/index.php?option%3Dcom_content%26view%3Darticle%26id%3D20460%3Acourt-rescues-malawi-vps-vehicles%26catid%3D1%3Anational-news%26Itemid%3D3|title=Archived copy|accessdate=11 September 2011|archiveurl=https://web.archive.org/web/20140607015632/http://www.mwnation.com/index.php?option=com_content&view=article&id=20460%3Acourt-rescues-malawi-vps-vehicles&catid=1%3Anational-news&Itemid=3|archivedate=7 June 2014}}</ref> Na 8 Septemba 2011, a hapụrụ ọrụ osote onye isi ala na ngbanwe nke ụlọ ọrụ. N'agbanyeghị nke a, ọ ka bụ osote onye isi ala nke iwu kwadoro n'ihi na ọ bụ iwu nyere ọkwa ahụ. <ref name="snub" /> Onye na-ekwuchitere DPP bụ Hetherwick Ntaba gbara ya ume ka ọ gbaa arụkwaghịm dịka osote onye isi ala. [[Usòrò:Joyce_Banda_Department_for_International_Development_photo_crop.jpg|thumb| Banda na 2012]] === Akụkụ dị na DPP === Mmekọrịta dị n'etiti Banda na Onye isi ala Bingu wa Mutharika abụrụla nke na-esiwanye ike n'ihi mgbalị Mutharika gbalịsiri ike idowe nwanne ya nwoke, Peter Mutharika, dị ka onye ga-anọchi ya. <ref name="google"/> N'agbanyeghị na a chụrụ ya n'ọrụ dị ka osote onye isi oche nke DPP yana osote onye isi ala nke abụọ Khumbo Kachali, ọ gara n'ihu na-eje ozi dị ka osote onye isi ala Malawi dị ka e depụtara n'akwụkwọ iwu. <ref name="google" /> Nkwagharị a mere ka arụkwaghịm nke ukwuu dị na DPP, ebe e nwere nguzobe nke netwọk ndị kwadoro nkwado ya ka ọ bụrụ onye isi ala Malawi na nhoputa ndi ochichi nke 2014. <ref name="woes">{{Cite web|url=http://www.afriquejet.com/news/africa-news/malawi:-vice-president%27s-woes-dominate-malawi-media-2010121864614.html|accessdate=18 December 2010|archiveurl=https://web.archive.org/web/20101220022503/http://www.afriquejet.com/news/africa-news/malawi%3A-vice-president%27s-woes-dominate-malawi-media-2010121864614.html|archivedate=20 December 2010}}</ref> Ndị DPP gọrọ agọ na e nwere arụkwaghịm ọtụtụ mmadụ ma kwusie ike na ọ bụ naanị mmadụ ole na ole gbara arụkwaghịm. <ref name="woes" /> === People's Party === Joyce Banda bụ onye hiwere na onye ndu nke People's Party, nke e guzobere na 2011 mgbe a chụpụrụ Banda na DPP na-achị achị mgbe ọ jụrụ ịkwado nwanne nwanne President Mutharika Peter Mutharika dịka onye ga-anọchi anya onyeisi oche maka ntuli aka 2014. <ref>Jomo, Frank. (13 December 2010) [https://www.bloomberg.com/news/2010-12-13/malawi-s-vice-president-joyce-banda-expelled-from-ruling-party.html Malawi’s Vice President Joyce Banda Expelled From Ruling Party]. Bloomberg. Retrieved 10 April 2012.</ref> <ref>{{Cite web|url=http://www.nyasatimes.com/politics/people%E2%80%99s-party-file-for-registration.html|accessdate=22 July 2011|archiveurl=https://web.archive.org/web/20110515105420/http://www.nyasatimes.com/politics/people%E2%80%99s-party-file-for-registration.html|archivedate=15 May 2011}}</ref> === Onye isi ala (2012 - Mee 2014) === ==== Mgbanwe nke ike ==== Na 5 Eprel 2012, Onye isi ala Mutharika nwụrụ. <ref name="ceremony">{{Cite web|author=Administrator|title=Her Excellency Mrs. Joyce Banda is the New President of Malawi|publisher=Embassy of the Republic of Malawi to Belgium, France, the Netherlands, Italy, Luxembourg, Switzerland and Mission to the European Union|date=11 April 2012|url=http://www.embassymalawi.be/index.php?option=com_content&view=article&id=87%3Aher-excellency-mrs-joyce-banda-is-the-new-president-of-malawi&catid=1%3Alatest-news&lang=|accessdate=22 April 2012}}</ref> Mgbe ọ nwụsịrị, gọọmentị emeghị ka ọha mara na onye isi ala anwụọla n'oge. Nke a butere egwu nke nsogbu iwu na Malawi . <ref>{{Cite web|author=Faith Karimi|url=http://articles.cnn.com/2012-04-06/africa/world_africa_malawi-president_1_malawians-president-bingu-wa-mutharika-patricia-kaliati?_s=PM:AFRICA|title=Potential crisis looms in Malawi amid reports of president's death|publisher=Articles.cnn.com|date=6 April 2012|accessdate=23 May 2012|archiveurl=https://web.archive.org/web/20120515054125/http://articles.cnn.com/2012-04-06/africa/world_africa_malawi-president_1_malawians-president-bingu-wa-mutharika-patricia-kaliati?_s=PM%3AAFRICA|archivedate=15 May 2012}}</ref> <ref>{{Cite web|url=http://www.onenewspage.co.uk/n/World/74r755rd3/Bingu-Wa-Mutharika-death-leaves-Malawi-in.htm|title=Bingu Wa Mutharika's death leaves Malawi in constitutional crisis – One News Page [UK&#93;|publisher=Onenewspage.co.uk|date=6 April 2012|accessdate=23 May 2012|archivedate=8 September 2012|archiveurl=https://archive.today/20120908002515/http://www.onenewspage.co.uk/n/World/74r755rd3/Bingu-Wa-Mutharika-death-leaves-Malawi-in.htm}}</ref> <ref>[https://archive.today/20130127043447/http://www.kitv.com/news/national/Banda-sworn-in-as-Malawi-president/-/8905418/10322828/-/14mg6em/-/ Banda sworn in as Malawi president | National News – KITV Home]. Kitv.com. Retrieved 10 April 2012.</ref> Agence France-Presse kọrọ akụkọ na onye bụbu onye isi ala Malawi bu Bakili Muluzi na-ekwusi ike na "usoro iwu kwadoro", na-ekwu na osote onye isi ala ga-ewere ikike ozugbo dịka iwu si kwado. “A na m akpọ oku ka e nwee usoro iwu kwadoro, maka udo na ịdị n'otu na-aga n'ihu. Iwu Malawi doro anya na osote onye isi ala na-eweghara ọchịchị" mgbe onye isi oche na-enweghị ike ịchịisi ọzọ. Anyị aghaghị izere ọnọdụ ebe enwere ọgba aghara. Ka anyi soro ihe iwu kwadoro. Anyị enweghị nhọrọ ọzọ ma ọ bụghị ịgbaso ihe dị n'iwu. Ọ dị ezigbo mkpa na udo na ịdị jụụ ga-adịrịrị.” <ref>Godfrey Mapondera, David Smith, [https://www.theguardian.com/world/2012/apr/06/malawi-president-reported-dead Malawi faces power struggle after president reported dead], ''Guardian'', 6 April 2012</ref> Ndị ọrụ nchekwa Malawi chọkwara ka usoro iwu na-achị. <ref>[https://www.google.com/hostednews/ap/article/ALeqM5i0Nf2obDaNyqrpBEMUZftxE0wsVQ?docId=bdc060664dfb409aaf384dec2651a5bc The Associated Press: Malawi's VP sworn in as president amid uncertainty], ''AP'', 10 April 2012.</ref> Malawi Law Society kwadoro na n'okpuru ngalaba 83(4) nke akwụkwọ iwu Malawi, ọ bụ ya bụ onye ga-anọchi anya onyeisi ala ahụ. Na 7 Eprel, ndị otu Malawi chọrọ ka ụlọ ikpe gbochie Banda ịbụ onye isi ala. N'aka nke ya, ọ kpọrọ onyeisi ndị agha, bụ́ General Henry Odillo, na ekwentị ma jụọ ma ọ̀ ga-akwado ya. O kwetara wee mee ka ndị agha guzoro n’ụlọ ya. <ref name="army">{{Cite journal|author=Smith|first=David|title=Malawi's Joyce Banda puts women's rights at centre of new presidency|journal=The Guardian|date=29 April 2012|url=https://www.theguardian.com/world/2012/apr/29/malawi-president-joyce-banda-women-rights|issn=0261-3077|accessdate=30 April 2012}}</ref> Joyce Banda weghaara ọchịchị na 7 Eprel 2012 dị ka Onye isi ala Malawi, nwanyị mbụ na-ejide ọkwa ahụ. <ref name="swornin">[http://www.aljazeera.com/news/africa/2012/04/201247111815207836.html Joyce Banda sworn in as president of Malawi – Africa], ''Al Jazeera English'', 4 October 2011</ref> Onye ọka ikpe Lovemore Munlo nọrọ dika onye isi oche nke emume a mere na ụlọ omebe iwu dị na Lilongwe . <ref name="ceremony"/> Mgbe ọ ṅụsịrị iyi, Banda rịọrọ maka ịdị n'otu mba. "Achọrọ m ka anyị niile jiri olileanya na mmụọ nke ịdị n'otu wee gaa n'ọdịnihu. . . Enwere m olileanya na anyị ga-eguzo n'otu n'otu, enwere m olileanya na dị ka mba na-atụ egwu Chineke, anyị na-ekwe ka Chineke bịa n'ihu anyị, n'ihi na ọ bụrụ na anyị emeghị otú ahụ, anyị dara ada." <ref name="swornin" /> Ndị mgbasa ozi Malawi na mba ụwa kọrọ banyere nraranye Joyce Banda nke ọma. Ha kpọrọ ya mmeri maka ọchịchị onye kwuo uche ya. Akwụkwọ akụkọ ''Malawi Sunday Times'' kwuru na nraranye onye isi ala ọhụrụ enyela aka n'ịkwado omenala onye kwuo uche ya na mba ahụ. <ref name="Mwagiru"/> ==== Nhọpụta ndị minista na mfu nke ntuli aka onye isi ala 2014 ==== Na 26 Eprel 2012, Onye isi ala Banda họpụtara ụlọ ọrụ ya, nke mejupụtara ndị ozi iri abụọ na atọ na ndị osote onye ozi itoolu. O nyere onwe ya ọtụtụ nnukwu ọrụ iji wee jigidesie ike ya dịka onye ndu obodo. <ref name="newcabinet">{{Cite web|author=Mapondera|first=Derek|title=Malawi's Pres Joyce Banda sacks predecessor's brother, hires new cabinet which includes ex-leader's son|work=The Maravi Post|date=26 April 2012|url=http://www.maravipost.com/malawi-national-news/malawi-political-news/855-malawi-s-pres-joyce-banda-sacks-predecessor-s-brother,-hires-new-cabinet-which-includes-ex-leader-s-son.html|archiveurl=https://web.archive.org/web/20210118064944/http://www.maravipost.com/malawi-national-news/malawi-political-news/855-malawi-s-pres-joyce-banda-sacks-predecessor-s-brother,-hires-new-cabinet-which-includes-ex-leader-s-son.html|archivedate=18 January 2021|accessdate=26 April 2012}}</ref> Na 10 Ọktoba 2013, ụbọchị ole na ole ka o si na njem ọ gara na UN lọta, Onye isi ala Joyce Banda chụrụ ụlọ ọrụ ya na-esochi akụkọkasịrị ne Capital Hill Cashgate . <ref>{{Cite web|url=https://www.bbc.co.uk/news/world-africa-24484557|title=Malawi's Joyce Banda sacks cabinet amid corruption row|work=BBC News|date=10 October 2013|accessdate=28 December 2013}}</ref> <ref>{{Cite web|url=https://www.reuters.com/article/malawi-cabinet-idUSL6N0I03M020131010|title=Malawi president dissolves cabinet in wake of graft scandal|publisher=Reuters|date=10 October 2013|accessdate=30 December 2013}}</ref> Na 15 Ọktọba, ahọpụtara ọkwa ọhụrụ ydịoiche iche ebe nye minista na-ahụ maka ego Ken Lipenga na Mịnịsta na-ahụ maka ikpe ziri ezi Ralph Kasambara ka ewepụrụ na'ọkwa minista ha. Na May 2014, e meriri Joyce Banda nke ukwuu na ntuli aka nke onye isi ala. Ọ dara na mbọ ọ na-eme imebi ntuli aka ahụ. Ọ gaghị ememe ndọnye n'oche nke onye meriri, Peter Mutharika, mana ọ kelere ya. <ref>{{Cite news|url=https://www.bbc.com/news/world-africa-27648964|title=Malawi election: Peter Mutharika sworn in as president|date=31 May 2014|work=BBC News|accessdate=25 January 2015}}</ref> Ọ biri na mpụga Malawi malite na 2014. Ekwuputara akwụkwọ ikike maka ijide ya n'ihe metụtara nrụrụ aka n'oge ọ na-arụ ọrụ dịka onye isi ala na 31 Julaị 2017, n'agbanyeghị na ọ nọgidere na mpụga obodo ahụ. <ref>[https://web.archive.org/web/20170801110321/http://af.reuters.com/article/topNews/idAFKBN1AH3KK-OZATP "Malawi issues arrest warrant for former president over graft scandal"], Reuters, 1 August 2017.</ref> Ọ gọrọ agọ maka ebubo ahụ ma kwuo na ya ga-alọghachi izara ọnụ ya. <ref>[https://web.archive.org/web/20170802141807/https://af.reuters.com/article/topNews/idAFKBN1AI0RC-OZATP "Malawi's former president says "innocent" of graft, will return home"], Reuters, 2 August 2017.</ref> ==== Mmekọrịta mba ụwa ==== N'oge ọchịchị Mutharika, Malawi batara n'ọnọdụ akụ na ụba dara ogbenye n'ihi ọnọdụ mmekọrịta mba ọzọ n'okpuru ọchịchị Mutharika . N'ime afọ ikpeazụ nke ọchịchị Mutharika, Britain, United States, Germany, Norway, European Union, World Bank, na African Development Bank kwụsịrị enyemaka ego. Ha ekwupụtala nchegbu gbasara mbuso agha Mutharika busoro ọchịchị onye kwuo uche ya n'ime mba ahụ yana atumatu ya na-esiwanye ike. Na March 2012, Mutharika gwara ndị mba ọzọ na-enye onyinye ka ha "gaa hell." O boro ha ebubo na ha na-akpa nkata iwetu ọchịchị ya. <ref name="Somerville">{{Cite web|author=Somerville|first=Keith|title=Malawi: New president must build support and mend donor relations (analysis)|work=African Arguments|publisher=The Norwegian Council for Africa|date=10 April 2012|url=http://www.afrika.no/Detailed/21370.html|accessdate=20 April 2012|archiveurl=https://web.archive.org/web/20121027212215/http://www.afrika.no/Detailed/21370.html|archivedate=27 October 2012}}</ref> Otu n'ime ihe ịma aka Banda dị ka onye isi ala bụ iweghachi mmekọrịta mba ụwa na ndị na-enye onyinye. O nwekwara ihe ịma aka nke iweghachi mmekọrịta Malawi na mba ndị gbara ha gburugburu dị ka [[Mozambique]], na mpaghara mba ndị ọzọ dịka [[Botswana]] . N'ime izu mbụ nke onye isi ala ya, Banda malitere mbuso agha ndọrọ ndọrọ ọchịchị iji mezie mmekọrịta mba ụwa nke Malawi. <ref name="JB"> {{Cite web|author=Munthali|first=Kondwani|title=JB cleans up Capital Hill|work=[[The Nation (Malawi)]]|date=11 April 2012|url=http://www.malawitoday.com/news/124476-joyce-banda-starts-cleaning-capital-hill|accessdate=22 April 2012|archiveurl=https://web.archive.org/web/20130914030353/http://www.malawitoday.com/news/124476-joyce-banda-starts-cleaning-capital-hill|archivedate=14 September 2013}} </ref> Ọ gwara Henry Bellingham nke Ọfịs Ofesi nke United Kingdom okwu. O mesiri ya obi ike na a ga-eziga onye nnọchi anya Britain ọhụrụ "n'ime obere oge enwere ike." Ọ gwara odeakwụkwọ mba Amerịka bụ Hillary Clinton okwu. Clinton kwere nkwa ịmaliteghachi mkparịta ụka na onyinye nke nde dọla narị atọ na iri ise ozugbo enwere ike. Banda kwuputara atụmatụ ya ịgwa Baroness Ashton nke ụlọ ọrụ mba ofesi nke European Union na onye nnọchi anya IMF nke Malawi, Ruby Randall. Ya na onye isi ala Zambia Michael Sata enyekwara aka maka ịmaliteghachi mmekọrịta chiri anya. <ref name="JB" /> Opekempe n'otu akụkụ iji mee ka ndị na-enye onyinye nwee obi ụtọ, nchịkwa Banda jụkwara na June 2012 ịnabata nzukọ ndị Africa Union nke July n'ihi na AU siri ọnwụ na a ga-enye onye isi ala [[Sudan]] Omar al-Bashir mmesi obi ike na Malawi ga-ajụ inye ya akwụkwọ ikike ijide nke ụlọ ikpe mpụ mba ụwa dere megide ya; ndị Cabinet kpebiri na ha agaghị anabata ọnọdụ ndị dị otú ahụ. <ref>{{Cite web|title=Malawi not to host summit after row over Sudan leader|work=[[BBC News]]|publisher=BBC|date=8 June 2012|url=https://www.bbc.co.uk/news/world-africa-18364947|accessdate=8 June 2012}}</ref> Onye isi ala Banda bu onye Forbes kpọrọ dịka nwanyị nke iri anọ kachasị ike n'ụwa, aha Africa kachasị elu na ndepụta ahụ. <ref name="Forbes14"/> ==== Amụma ụlọ ==== [[Usòrò:Flag_of_Malawi.svg|áká_ịkẹngạ|thumb|200x200px| Emebere ọkọlọtọ Malawi na 1964 ma ndị omeiwu gụgharịrị ya na 2012.]] [[Usòrò:Flag_of_Malawi_(2010–2012).svg|áká_ịkẹngạ|thumb|200x200px| Ọkọlọtọ 2010–2012 na-ewughi ewu nke Malawi]] Na 18 Mee 2012, Banda kwupụtara ebumnuche ya ịkagbu mmachibido iwu Malawi nke nwoke idina nwoke. Ekwuru na okwu a nwere nkwado nke ọtụtụ ndị omeiwu. Ọ bụrụ na ọ gaa nke ọma, ọ ga-eme Malawi mba Africa nke abụọ kwadoro mmekọ nwoke na nwoke nakwa mmekọ nwanyị na nwanyị n'iwu kemgbe 1994. <ref>{{Cite web|url=https://www.bbc.co.uk/news/world-africa-18118350|title=Malawi to overturn homosexual ban, Joyce Banda says|date=18 May 2012|work=BBC News|accessdate=18 May 2012}}</ref> Amnesty International kọrọ na mbido Nọvemba 2012 na Malawi akwụsịla iwu ndị na-emegide nwoke idina nwoke na-echere ntuli aka. <ref>{{Cite news|url=http://www.cnn.com/2012/11/06/world/africa/malawi-antigay-laws/index.html|title=Amnesty: Malawi suspends anti-gay laws|date=6 November 2012|accessdate=17 January 2013}}</ref> Na ndụmọdụ nke International Monetary Fund, na May 2012 Banda wedara Malawi kwacha, ihe Mutharika jụrụ ime. Nkwuwapụta nke mbelata kwacha site na pasent iri atọ na atọ megide dọla nke mba United Steeti, mgbalị iji nweta ego ndị nyere onyinye, kpalitere "ịzụta ihe nke ụjọ" na obodo Malawi, BBC News kọrọ. <ref>{{Cite news|url=https://www.bbc.co.uk/news/world-africa-17982062|title=Malawi devalues kwacha by 33%, leading to panic-buying|date=7 May 2012|accessdate=17 January 2013}}</ref> Mgbe ọ ghọrọ Onye isi ala, Banda kpebiri ire ụgbọ elu onye isi ala ma nye onyinye nke pasent iri atọ nke ụgwọ ọnwa ya iji wee mee ka kansul Malawi maka Ndị Nkwarụ rite uru ahụ. <ref name=":0">{{Cite web|date=2016-08-01|title=Joyce Banda|url=https://www.wilsoncenter.org/person/joyce-banda|accessdate=2019-05-08|work=[[Wilson Center]]|language=en}}</ref> Otú ọ dị, ego e nwetara n'ahịa ụgbọ elu ahụ bu nke edetughi. Nkọwa nke Joyce Banda nyere bụ na e resịrị ụgbọ elu ahụ nye ụlọ ọrụ ngwá agha dị na South Africa bụ ndị Gọọmenti Malawi ji ụgwọ dị ukwuu na ya mere eji ụgbọ elu ahụ kwụọ ụgwọ a. Ọnweghị akwụkwọ ma ọ bụ ihe akaebe ewepụtara iji kwado nzọrọ ahụ. <ref>{{Cite web|author=Wanga Gwede|url=http://www.nyasatimes.com/2014/03/10/jb-mkwezalamba-differ-on-malawi-jetgate-who-is-fooling-who/|title=JB, Mkwezalamba differ on Malawi jetgate: Who is fooling who?|publisher=Nyasa Times|date=10 March 2014|accessdate=6 March 2015|archiveurl=https://web.archive.org/web/20150227034401/http://www.nyasatimes.com/2014/03/10/jb-mkwezalamba-differ-on-malawi-jetgate-who-is-fooling-who/|archivedate=27 February 2015}}</ref> Na 17 Jenụwarị 2013, ọtụtụ puku ndị Malawi mere mkpesa na Blantyre megide ịrị elu nke ihe a na-ere n'ahia mgbe Banda na onye isi IMF Christine Lagarde, gbachitere ọnụ ahịa kwacha ma kwuo na ọ gaghị atụgharị mkpebi ahụ. <ref>{{Cite news|url=http://www.nyasatimes.com/malawi/2013/01/06/jb-says-wont-reverse-malawi-kwacha-devaluation-imf-chief-defends-move/|title=JB says won't reverse Malawi Kwacha devaluation|date=6 January 2013|accessdate=17 January 2013|archive-date=11 January 2013|archive-url=https://web.archive.org/web/20130111085601/http://www.nyasatimes.com/malawi/2013/01/06/jb-says-wont-reverse-malawi-kwacha-devaluation-imf-chief-defends-move/|url-status=dead}}</ref> <ref>{{Cite news|url=http://uk.reuters.com/article/uk-malawi-protests-idUKBRE90G0O120130117|work=Reuters|date=17 January 2013|accessdate=17 January 2013|title=Malawi sees first major protest under President Banda|archive-date=16 January 2016|archive-url=https://web.archive.org/web/20160116082442/http://uk.reuters.com/article/uk-malawi-protests-idUKBRE90G0O120130117|url-status=dead}}</ref> ==== Atụmatụ nke onye isi ala ==== Onye isi ala Banda egosila nkwụsi ike na ahụike nne na ikike ịmụ nwa, ọkachasị site na nkwado ya maka ịbụ nne nwere nchekwa na Malawi. O gosiputara nkwado ya site na iguzobe atụmatụ Presidential Initiative on Health Maternal and Safe Motherhood. N'ime naanị afọ abụọ, atụmatụ a gosipụtara mbelata nke ọnụọgụ ọnwụ nke nne site na ọnwụ narị isii na ịrị asaa na ise n'ime otu narị puku dị ndụ ruo ọnwụ narị anọ na ịrị isii n'ime otu narị puku ọmụmụ dị ndụ. <ref name=":0"/> ==== Ọkọlọtọ ==== Mgbe gọọmentị Mutharika gbanwere ọkọlọtọ na 2010, enwere mmegide ọha. Ọtụtụ otu na-agbagha izi ezi nke ọkọlọtọ ahụ. Na 28 Mee 2012, Banda duuru ndị omeiwu nke mba ahụ ịtụ vootu ka eweghachi ọkọlọtọ ahụ n'ọkọlọtọ nnwere onwe ya, nke ewepụtara na 1964. Ndị otu niile, ma ewezuga DPP, kwadoro ịlaghachi na ọkọlọtọ nnwere onwe. <ref>{{Cite web|title=Malawi MPs vote to fly old rising sun flag|work=BBC News Africa|date=29 May 2012|url=https://www.bbc.co.uk/news/world-africa-18255188|accessdate=8 June 2012}}</ref> === Ndụ ya mgbe o rituru n'ọkwa onye isi ala === Banda nọrọ na mmapu nke onwe ya na mba United Steeti dị ka onye ama ama na Woodrow Wilson Center na Center for Global Development ruo afọ atọ, tupu ịlaghachi na Malawi na 2018. <ref>[https://www.reuters.com/article/us-malawi-politics/former-malawi-president-joyce-banda-returns-from-exile-idUSKBN1HU2G8 Former Malawi president Joyce Banda returns from exile], [[Reuters]]</ref> Ka ọ dị ugbu a, ọ nweghị ebubo e boro Banda n'ihu ọha. Banda banyere nhoputa ndi ochichi nke 2019 dika onye ndoro-ndoro ochichi ndi mmadu, ma wepu onwe ya n'ịzọ ọkwa ahụ onwa abuo tupu ntuli aka; <ref>[https://www.reuters.com/article/us-malawi-election/ex-president-banda-pulls-out-of-malawi-presidential-race-idUSKCN1QV2R3 Ex-president Banda pulls out of Malawi presidential race] Reuters, 14 March 2019</ref> o mechara kwado onye ndoro-ndoro ochichi mmegide Lazarus Chakwera. <ref>{{Cite web|url=https://www.voanews.com/a/joyce-banda-withdraws-from-malawi-presidential-race/4831130.html|title=Joyce Banda Withdraws from Malawi Presidential Race|date=15 March 2019|work=VOA|language=en}}</ref> <ref>{{Cite web|url=https://ewn.co.za/2019/03/18/malawi-ex-leader-banda-seals-another-opposition-pact|title=Malawi ex-leader Banda seals another opposition pact|date=18 March 2019|work=AFP via Eyewitness News South Africa|language=en}}</ref> Ka a kagburu ntuli aka onye isi ala nke 2019, ọ kwadoro Chakwera ọzọ na mmeghari nke afọ 2020 . Akpọrọ nwa Banda Roy Kahele-Banda ka ọ bụrụ onye minista nke ụlọ ọrụ na ọchịchị Chakwera. == Joyce Banda Foundation == Tupu ọ bụrụ osote onye isi ala, ọ bụ onye hiwere ma bụrụkwa onye isi oche nke Joyce Banda Foundation . <ref>{{Cite web|url=http://www.joycebandafoundation.org/|title=Joyce Banda Foundation|publisher=Joyce Banda Foundation|accessdate=1 November 2012|archiveurl=https://web.archive.org/web/20130425052618/http://www.joycebandafoundation.org/|archivedate=25 April 2013}}</ref> maka agụmakwụkwọ ka mma, ntọala ọrụ ebere na-enyere ụmụaka Malawi na ụmụ mgbei aka site na agụmakwụkwọ. Ọ bụ nchịkọta nke ụlọ akwụkwọ praịmarị na nke sekọndrị na mpaghara Chimwankhunda nke Blantyre . Ọ gụnyere ebe nlekọta ụmụ mgbei nke nwere ebe isii na ụmụaka narị isii. Ọ na-enyere obodo ndị gbara ya gburugburu aka site n'inye ụmụ nwanyị iri anọ na otu ndị ntorobịa iri obere kredit. O nyere ihe karịrị ndị ọrụ ugbo pụkụ iri mkpụrụ maka ọkụkọ ugbo ma nyekwa onyinye ndị ọzọ. Ntọala ahụ arụọla ụlọọgwụ anọ n'ime obodo anọ n'ime obodo narị abụọ ndi ọ na-enyere aka. Ntọala ahụ na-enyekwa aka na mmepe ime obodo. O nwere mmekorita ya na Jack Brewer Foundation, ntọala mmepe zuru ụwa ọnụ nke NFL star, Jack Brewer hiwere. == Òtù Ụmụ nwanyị Azụmahịa Mba == Banda bụ onye guzobere National Association of Business Women na Malawi nke e hiwere n'afọ 1990. Ọ bụ ntọala anaghị akwụ ụgwọ edebanyere aha ya na Malawi. <ref>{{Cite web|url=https://www.un.org/africa/osaa/ngodirectory2/dest/countries/printNGO.asp?lang=ENG&country=29&ngo=MALW27|title=National Association of Business Women|publisher=United Nations|accessdate=7 April 2012|archiveurl=https://web.archive.org/web/20121026124825/http://www.un.org/africa/osaa/ngodirectory2/dest/countries/printNGO.asp?lang=ENG&country=29&ngo=MALW27|archivedate=26 October 2012}}</ref> Otu a bu n'obi ibupụ ụmụ nwanyị n'ime ịda ogbenye site n'ịkwalite ikike ha na inye ha ike n'ụzọ akụ na ụba. <ref name="hivos">{{Cite web|url=http://www.hivos.nl/dut/community/partner/10003036|title=National Association of Business Women / Partners / Home – Ontwikkelingsorganisatie Hivos|language=nl|publisher=Hivos.nl|date=31 December 2008|accessdate=7 April 2012|archiveurl=https://web.archive.org/web/20120304054222/http://www.hivos.nl/dut/community/partner/10003036|archivedate=4 March 2012}}</ref> Nke a bụ njikọ mmekọrịta nke ụmụ nwanyị pụkụ ịrị atọ, nke raara onwe ya nye ịkwado azụmahịa ụmụ nwanyị na ịkwado ụmụ nwanyị chọrọ isonye na azụmahịa. Ihe omume ya gụnyere ọzụzụ azụmaahịa, ọzụzụ teknụzụ, idekọ ndekọ na nka njikwa. <ref name="hivos" /> Ha na-arụ ọrụ n'ịmepụta mkparịta ụka na ndị na-eme iwu iji mee ka atumatu dị mma nye ndị inyom na-azụ ahịa. <ref name="intracen">{{Cite web|url=http://www.intracen.org/womenandtrade/|title=Women and Trade – Home page|publisher=Intracen.org|date=17 December 2011|accessdate=7 April 2012}}</ref> Onye isi ya ugbu a bụ Mary Malunga. <ref name="intracen" /> Ntọala ahụ enweela mmekorita ya na ụlọọrụ di na mba Netherlands a kpọrọ Humanist Institute for Development Cooperation ( Hivos ) na Hague kemgbe 2003. <ref name="hivos" /> == Atụmatụ ọdịmma mmadụ na mmepe == Banda etinyela aka n'ọtụtụ ọrụ ntọala ya na ụmụ nwanyị kemgbe ọ dị afọ iri abụọ na ise iji weta mgbanwe amụma, ọkachasị na agụmakwụkwọ. Ọ tọrọ ntọala Joyce Banda Foundation for Better Education. Ọ tọrọ ntọala Network Young Women Leaders Network, National Association of Business Women nakwa amụma Hunger Project na Malawi. Enyere ya (ya na Onye isi ala Joaquim Chissano nke Mozambique) ihe nrite n'afọ 1997 nke Africa Prize for Leadership for the Sustainable End of Hunger n'ihi Hunger Project, otu na-abụghị nke gọọmentị di na New York. O ji ego nrite nyere aka wuo ntọala Joyce Banda maka ụmụaka. N'afọ 2006, ọ natara ihe nrite mba ụwa maka ahụike na ugwu ụmụ nwanyị maka nraranye ya n'ikike ụmụ nwanyị Malawi sitere n'aka ndị Americans for United Nations Population Fund. Ọ jere ozi dị ka onye kọmishọna maka "Ịmekọrịta Ụwa e Kewara" n'akụkụ ndị mmadụ dị ka Bishop Desmond Tutu, nakwa onye komishona nke United Nations Commissioner Human Rights, Mary Robinson. Banda bụkwa onye so na bọọdụ ndụmọdụ maka agụmakwụkwọ na Washington DC, yana na bọọdụ ndụmọdụ maka Federation of World Peace and Love in Taiwan (China). <ref name="malawi">[http://www.malawi.gov.mw/information1/New%20Malawi/joycebpro.htm]{{dead link|date=April 2012}}</ref> Dịka akụkụ nke mmegharị gọọmentị na Ọktoba 2012, Banda belatara pasent iri atọ n'ụgwọ ọnwa ya. O kwuputakwara na a ga-ere ụgbọ elu onyeisiala. === Kansụl ndị isi ụwa maka ahụike ịmụ nwa === Na 2010, Banda ghọrọ onye otu Global Leaders Council for Reproductive Health, <ref name="womendeliver">{{Cite web|url=http://www.womendeliver.org/updates/entry/the-launch-of-the-global-leaders-council-for-reproductive-health/|title=Updates " The Launch of the Global Leaders Council for Reproductive Health|publisher=Women Deliver|date=21 September 2010|accessdate=1 November 2012|archiveurl=https://web.archive.org/web/20120715020428/http://www.womendeliver.org/updates/entry/the-launch-of-the-global-leaders-council-for-reproductive-health|archivedate=15 July 2012}}</ref> otu ndị nọ ọdụ iri na isii na ndị bụbu ndị isi ala, ndị na-eme iwu dị elu na ndị isi ndị ọzọ kwadoro ịkwalite ahụike ọmụmụ maka mmepe na ọganihu na-adịgide adịgide. <ref name="womendeliver" /> Onye isi oche nke otu a bụ onye bụbụ onye isi ala nke Ireland Mary Robinson, ndị isi a na-achọ ịchịkọta ọchịchọ ndọrọ ndọrọ ọchịchị na ego dị mkpa iji nweta ohere zuru ụwa ọnụ maka ahụike ọmụmụ site na 2015 - isi ihe mgbaru ọsọ UN Millennium Development Goals. <ref name="womendeliver" /> == Otuto == === Ihe nrite mba === * Nwanyị nke Afọ, Malawi, 1997 * Nwanyị nke Afọ, Malawi, 1998 <ref name="malawi" /> * Nyasa Times Multimedia 'Onye nke Afọ', 2010 <ref>{{Cite web|author=Lungu|first=M'theto|title=Media house awards Malawi Veep Joyce Banda 'Person of the Year 2010' accolade|work=The Africa Global Village|date=30 December 2010|url=http://www.africaglobalvillage.com/en/southern-africa/malawi/504-malawi.html|accessdate=17 April 2012|archiveurl=https://archive.today/20130116154347/http://www.africaglobalvillage.com/en/southern-africa/malawi/504-malawi.html|archivedate=16 January 2013}}</ref> === Ihe nrite mba ụwa === * Martin Luther King Drum Major Award, 2012, Washington DC<ref>{{cite web |url=http://www.nyasatimes.com/malawi/2012/06/12/jb-receives-martin-luther-king-drum-major-award/ |title=JB receives Martin Luther King 'Drum Major' award &#124; Malawi news, Malawi – NyasaTimes breaking online news source from Malawi |publisher=Nyasatimes.com |access-date=1 November 2012 |url-status=dead |archive-url=https://web.archive.org/web/20120618191308/http://www.nyasatimes.com/malawi/2012/06/12/jb-receives-martin-luther-king-drum-major-award/ |archive-date=18 June 2012 |df=dmy |accessdate=11 April 2022 |archivedate=18 June 2012 |archiveurl=https://web.archive.org/web/20120618191308/http://www.nyasatimes.com/malawi/2012/06/12/jb-receives-martin-luther-king-drum-major-award/ }}</ref> *Legends Award for Leadership, 2012, Greater African Methodist Episcopal Church<ref>{{cite web |url=http://www.maravipost.com/malawi-national-news/malawi-society/1119-unwavering-pres-banda-gets-legend-award-for-leadership.html |title=Society delivers the latest Malawi breaking news and information on the latest top stories |publisher=Maravipost.com |date=5 April 2012 |access-date=1 November 2012 |url-status=dead |archive-url=https://archive.today/20130128065909/http://www.maravipost.com/malawi-national-news/malawi-society/1119-unwavering-pres-banda-gets-legend-award-for-leadership.html |archive-date=28 January 2013 |df=dmy-all |accessdate=11 April 2022 |archivedate=28 January 2013 |archiveurl=https://archive.is/20130128065909/http://www.maravipost.com/malawi-national-news/malawi-society/1119-unwavering-pres-banda-gets-legend-award-for-leadership.html }}</ref> * Women of Substance Award, 2010, African Women Development Fund<ref>{{cite web|url=http://www.nationmw.net/index.php?option=com_content&view=article&id=10104:another-international-accolade-for-banda&catid=62:national-news&Itemid=59 |title=nationmw.net |publisher=nationmw.net |access-date=1 November 2012}}</ref> * Africa Prize for Leadership for the Sustainable End of Hunger, 1997, Hunger Project of NY<ref name="malawi"/> * International award for entrepreneurship development, 1998, Africa Federation of Woman Entrepreneurs and Economic Commission for Africa (ECA)<ref name="malawi"/> * 100 Heroines award, 1998, Rochester, New York<ref name="malawi"/> * Certificate of Honors, 2001, Federation of World Peace and Love, Taiwan, Republic of China<ref name="malawi"/> === Nkwanye ugwu === * Nwanyị kachasị ike n'ụwa 2014, Magazin Forbes - ọkwa onye nke iri anọ <ref name="Forbes14"/> * Nwanyị kachasị ike n'ụwa 2013, Magazin Forbes - ọkwa onye nke iri anọ na asaa. * Nwanyị kachasị ike n'ụwa 2012, Magazin Forbes - ọkwa onyeotu.e iri asaa na otu * Nwanyị kachasị ike na Africa 2012, Magazin Forbes - ọkwa onye nke mbu. * Nwanyị kachasị ike na Africa 2011, Magazin Forbes - ọkwa onye nke atọ. == Hụkwa == * Nsogbu n'usoro iwu Malawi 2012 * Ndepụta nke ndị otu National Assembly nke Malawi ugbu a == Ọgụgụ ọzọ == * {{Cite journal|title=Constitutional provisions and executive succession: Malawi's 2012 transition in comparative perspective|url=https://archive.org/details/sim_african-affairs_2013-01_112_446/page/111|author=Kim Yi Dionne, Boniface Dulani|journal=[[African Affairs]]|date=January 2013|volume=112|issue=446|pages=111–137|doi=10.1093/afraf/ads067}} == Ebensidee == {{Reflist|colwidth=30em}} == Njikọ mpụga == * [https://www.un.org/ecosocdev/geninfo/afrec/vol11no2/briefs3.htm United Nations 1997 Africa Prize] * {{cite journal | last = Donnelly | first = John | title = Joyce Banda: "Women lacked training, credit and information" | journal = Global Pulse | publisher = Global Post | location = Boston, Mass. | date = 10 October 2011 | url = http://www.globalpost.com/dispatches/globalpost-blogs/global-pulse/joyce-banda-women-lacked-training-credit-and-information | access-date =15 April 2012}} {{s-start}} {{s-off}} {{s-bef|before=[[George Chaponda]]}} {{s-ttl|title=Minister of Foreign Affairs|years=2006–2009}} {{s-aft|after=[[Etta Banda]]}} |- {{s-bef|before=[[Cassim Chilumpha]]}} {{s-ttl|title=[[Vice-President of Malawi|Vice President of Malawi]]|years=2009–2012}} {{s-aft|after=[[Khumbo Kachali]]}} |- {{s-bef|before=[[Bingu wa Mutharika]]}} {{s-ttl|title=[[President of Malawi]]|years=2012–2014}} {{s-aft|after=[[Peter Mutharika]]}} {{s-end}} [[Òtù:Mmadụ ndi di ndụ]] [[Òtù:Pages with unreviewed translations]] ledgu5pg62y8tqlev1lrwmiwx7fw4fb Kofi Adjorlolo 0 14541 736852 515275 2026-10-08T08:35:09Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736852 wikitext text/x-wiki {{Databox}} '''Kofi Adjorlolo''' (amụrụ na Machị 23, 1956 na Keta ) bụ onye Ghana na-eme ihe nkiri na onye na-emepụta ihe. A họpụtala ya otu ugboro maka onye na-eme ihe nkiri kachasị mma na Ghana Movie Awards, na ugboro anọ maka onye na-eme ihe nkiri kachasị mma na ọrụ nkwado, na Ghana Movie Awards, Africa Movie Academy Awards, na [[Africa Magic Viewers' Choice Awards|Africa Magic Viewers Choice Awards]]. Otu n'ime ihe nrite ndị ọ natara bụ International Golden Image award site n'aka onye isi ala Liberia n'oge ahụ bụ [[Ellen Johnson Sirleaf]], na Best Cameo Actor n'afọ 2011 Ghana Movie Awards.<ref>{{Cite news|title=Kofi Adjorlolo, Osu Mantse honoured in Liberia|url=https://www.ghanaweb.com/GhanaHomePage/NewsArchive/Kofi-Adjorlolo-Osu-Mantse-honoured-in-Liberia-562055|accessdate=24 November 2018|work=Ghana Web|date=24 July 2017|archive-url=https://web.archive.org/web/20190424083626/https://www.ghanaweb.com/GhanaHomePage/NewsArchive/Kofi-Adjorlolo-Osu-Mantse-honoured-in-Liberia-562055|archive-date=24 April 2019|url-status=dead}}</ref>   [[Category:Articles with hCards]] == Mmalite ndụ na agụmakwụkwọ == Adjorlolo gụsịrị ụlọ akwụkwọ AME Zion na Keta, [[Ghana]] wee banye na Keta Senior High Technical School tupu ọ nweta asambodo nke isii ya na Ebenezer Secondary school, Dansoman. == Ọrụ == Adjorlolo malitere ọrụ ya dịka onye egwu, na-akpọ ngwá egwu gụnyere opi na akụkụ ahụ.<ref name="Globe">{{Cite news|title=Posh Actor Kofi Adjorlolo Talks About Wealth And Fame|url=http://www.globentertainment.uk/?p=796|accessdate=24 November 2018|work=Globe Entertainment|date=16 December 2013}}</ref> Mgbe ọ dị afọ iri abụọ, ọ gara Naịjirịa ma soro onye egwu Naịjirịa bụ Victor Uwaifo nke Joromi ama ama. Ya na Felix Bell a ma ama na-arụkwa egwu.<ref>{{Cite web|url=https://www.ghanalive.tv/2016/10/14/kofi-adjorlolo-reflects-his-love-for-music/|title=Kofi Adjorlolo reflects his love for music|author=Asante|first=Sophia|date=2016-10-14|work=Ghana Live TV|language=en-US|accessdate=2020-02-01}}</ref> Mgbe ọ laghachiri [[Ghana]], o guzobere otu Osagyefo, ma soro ndị otu Dasebre na-egwu egwu.<ref name="Globe" /> Ọ rụrụ ọrụ dị ka onye ọrụ obodo na onye na-egosi redio na Ghana Broadcasting Corporation na Peace FM.<ref name="Globe" /> O nyere aka n'ịmepụta ụlọ ọrụ redio okpukpe Channel R, ụlọ ọrụ redio HOT 93.9FM na Accra kwanyeere ya ùgwù maka afọ iri atọ nke ije ozi na ụlọ ọrụ showbiz.<ref name="Globe" /><ref>{{Cite web|title=Hot 93.9fm Honours Kofi Adjorlolo|url=http://ghanaradio.co/breaking-news/hot-939fm-honours-kofi-adjorlolo.html|work=Ghana Radio|accessdate=24 November 2018|archivedate=5 January 2025|archiveurl=https://web.archive.org/web/20250105004830/http://www.ghanaradio.co/breaking-news/hot-939fm-honours-kofi-adjorlolo.html}}</ref> Ọ sonyeere ụlọ ọrụ ihe nkiri [[Ghana]] n'afọ 2003. == Ihe nkiri (ahọpụta) == {| class="wikitable sortable" !Afọ !Aha !Ọrụ !Ihe edeturu |- |2003 |''Onye ahọpụtara Nkebi nke 1&2'' |Deacon Prempeh | |- |2006 |''Obi Nne M'' | |A họpụtara ya maka onye na-eme ihe nkiri kachasị mma (ọrụ nkwado) na 2nd Africa Movie Academy Awards |- |2007 |''Princess Tyra'' | | |- |2009 |''Obi nke ụmụ nwoke'' |Bernard | |- |2009 |''Ahụhụ nke Kraịst'' | | |- |2010 |''Anụ ọhịa'' | |A họpụtara ya maka onye na-eme ihe nkiri kachasị mma na ọrụ nkwado (English) na 2010 Ghana Movie Awards |- |2011 |''Njikọ Ndị Na-ejikọta'' |Nna | |- |2011 |''N'otu ebe na Afrịka'' |General Olemba |Onye mmeri, Best Cameo Actor na 2011 Ghana Movie Awards |- |2012 |''Adesuwa'' (A Wasted Lust) | |- |2012 |''Alụghị di ma lụọ di'' |Ranesh | |- |2012 |''Hichapụ Anya mmiri m'' | |A họpụtara ya maka onye na-eme ihe nkiri kachasị mma na ọrụ ndu (English) na 2012 Ghana Movie Awards |- |2014 |''Abọm Ezinụlọ'' | |A họpụtara ya maka onye na-eme ihe nkiri kachasị mma na ọrụ nkwado na 2014 Ghana Movie Awards |- |2014 |''Ihe gbasara ugwu'' | |- |2015 |''[[Code of Silence (2015 film)|Code of Silence]]'' | | |- |2015 |''Ịda'' |Maazị Mazi Mba | |- |2016 |''Ghana Kwesịrị Ịga'' |Nna |A họpụtara ya maka Best Supporting Actor Movie / TV series na 2017 Africa Magic Viewers Choice Awards |- |2017 |''Onye a na-enyo enyo mpụ'' | | |- |2018 |''N'abalị ahụ'' | | |- |2019 |Hero - N'ike mmụọ nsọ site na ndụ na oge pụrụ iche nke Mr. Ulric Cross |Asantehene | |- |2020 |''Aloe Vera''<ref>{{Cite web|date=2020-03-09|title=Film review: Aloe Vera offers some charm in its vibrant retort to irrational tribalism|url=https://citinewsroom.com/2020/03/film-review-aloe-vera-offers-some-charm-in-its-vibrant-retort-to-irrational-tribalism/|accessdate=2021-02-03|work=Citinewsroom - Comprehensive News in Ghana|language=en-US}}</ref> |Papa Aloe | |} == Edemsibịa == {{Reflist}} == Njikọ mpụga == * [https://www.imdb.com/title/tt4218012/?ref_=nmbio_mbio Kofi Adjorlolo] na [[IMDb]] [[Òtù:Mmadụ ndi di ndụ]] mktkzi4p0bemxbk0yeqppx3m38chrdu Module:Uses TemplateStyles 828 18238 736712 622461 2026-09-28T17:59:50Z MusikBot II 14639 Changed protection settings for "[[Template:Uses TemplateStyles]]": [[Wikipedia:High-risk templates|High-risk template or module]]: 2529 transclusions ([[User:MusikBot II/TemplateProtector|more info]]) ([Edit=Require extended confirmed access] (indefinite) [Move=Require extended confirmed access] (indefinite)) 736712 wikitext text/x-wiki <includeonly>{{#invoke:Uses TemplateStyles|main}}</includeonly><noinclude>{{documentation}} <!-- Categories go on the /doc subpage and interwikis go on Wikidata. --> </noinclude> bbov914irrnmmvc6pz3scgivkjsu4ve 736713 736712 2026-10-07T14:40:42Z King ChristLike 13051 1 revision imported from [[:en:Template:Uses_TemplateStyles]] 736712 wikitext text/x-wiki <includeonly>{{#invoke:Uses TemplateStyles|main}}</includeonly><noinclude>{{documentation}} <!-- Categories go on the /doc subpage and interwikis go on Wikidata. --> </noinclude> bbov914irrnmmvc6pz3scgivkjsu4ve 736714 736712 2026-09-28T18:00:00Z MusikBot II 14639 Changed protection settings for "[[Module:Uses TemplateStyles]]": [[Wikipedia:High-risk templates|High-risk template or module]]: 2529 transclusions ([[User:MusikBot II/TemplateProtector|more info]]) ([Edit=Require extended confirmed access] (indefinite) [Move=Require extended confirmed access] (indefinite)) 736714 Scribunto text/plain local yesno = require('Module:Yesno') local mList = require('Module:List') local mTableTools = require('Module:TableTools') local mMessageBox = require('Module:Message box') local TNT = require('Module:TNT') local p = {} local function format(msg, ...) return TNT.format('I18n/Uses TemplateStyles', msg, ...) end local function getConfig() return mw.loadData('Module:Uses TemplateStyles/config') end local function makeEditSup(pageName) return string.format('<sup>&lbrack;[[Special:Edit/%s|e]]&rbrack;</sup>', pageName) end -- Build just the "(sandbox)" suffix using the i18n message, without duplicating the main link. local function makeSandboxSuffix(tsSandboxPrefixed) -- i18n message is: "$1 ([[$2|sandbox]])" -- Passing empty $1 yields " ([[:...|sandbox]])" -> trim leading whitespace to get "(sandbox)" portion. local s = format('sandboxlink', '', ':' .. tsSandboxPrefixed) return (s:gsub('^%s+', '')) end local function renderBox(tStyles) local boxArgs = { type = 'notice', small = true, image = string.format('[[File:Farm-Fresh css add.svg|32px|alt=%s]]', format('logo-alt')) } if #tStyles < 1 then boxArgs.text = string.format('<strong class="error">%s</strong>', format('error-emptylist')) else local cfg = getConfig() local tStylesLinks = {} for i, ts in ipairs(tStyles) do local viewLink = string.format('[[:%s]]', ts) local editSup = makeEditSup(ts) local out = viewLink .. editSup -- Optional sandbox link + sandbox edit link local tsTitle = mw.title.new(ts) if tsTitle and cfg['sandbox_title'] then local tsSandboxTitle = mw.title.new(string.format( '%s:%s/%s/%s', tsTitle.nsText, tsTitle.baseText, cfg['sandbox_title'], tsTitle.subpageText )) if tsSandboxTitle and tsSandboxTitle.exists then local sandboxSuffix = makeSandboxSuffix(tsSandboxTitle.prefixedText) local sandboxEditSup = makeEditSup(tsSandboxTitle.prefixedText) out = out .. ' ' .. sandboxSuffix .. ' ' .. sandboxEditSup end end tStylesLinks[i] = out end local tStylesList = mList.makeList('bulleted', tStylesLinks) boxArgs.text = format( mw.title.getCurrentTitle():inNamespaces(828, 829) and 'header-module' or 'header-template' ) .. '\n' .. tStylesList end return mMessageBox.main('mbox', boxArgs) end local function renderTrackingCategories(args, tStyles, titleObj) if yesno(args.nocat) then return '' end local cfg = getConfig() local cats = {} -- Error category if #tStyles < 1 and cfg['error_category'] then cats[#cats + 1] = cfg['error_category'] end -- TemplateStyles category titleObj = titleObj or mw.title.getCurrentTitle() if (titleObj.namespace == 10 or titleObj.namespace == 828) and not cfg['subpage_blacklist'][titleObj.subpageText] then local category = args.category or cfg['default_category'] if category then cats[#cats + 1] = category end if not yesno(args.noprotcat) and (cfg['protection_conflict_category'] or cfg['padlock_pattern']) then local currentProt = titleObj.protectionLevels["edit"] and titleObj.protectionLevels["edit"][1] or nil local addedLevelCat = false local addedPadlockCat = false for _, ts in ipairs(tStyles) do local tsTitleObj = mw.title.new(ts) local tsProt = tsTitleObj.protectionLevels["edit"] and tsTitleObj.protectionLevels["edit"][1] or nil if cfg['padlock_pattern'] and tsProt and not addedPadlockCat then local content = tsTitleObj:getContent() if not content:find(cfg['padlock_pattern']) then cats[#cats + 1] = cfg['missing_padlock_category'] addedPadlockCat = true end end if cfg['protection_conflict_category'] and currentProt and tsProt ~= currentProt and not addedLevelCat then currentProt = cfg['protection_hierarchy'][currentProt] or 0 tsProt = cfg['protection_hierarchy'][tsProt] or 0 if tsProt < currentProt then addedLevelCat = true cats[#cats + 1] = cfg['protection_conflict_category'] end end end end end for i, cat in ipairs(cats) do cats[i] = string.format('[[Category:%s]]', cat) end return table.concat(cats) end function p._main(args) local cfg = getConfig() if #args == 0 then local prefixed = mw.title.getCurrentTitle().prefixedText prefixed = prefixed:gsub("/doc", "") args[1] = prefixed .. "/" .. cfg["default_subpage_name"] end local tStyles = mTableTools.compressSparseArray(args) local box = renderBox(tStyles) local trackingCategories = renderTrackingCategories(args, tStyles) return box .. trackingCategories end function p.main(frame) local origArgs = frame:getParent().args local args = {} for k, v in pairs(origArgs) do v = v:match('^%s*(.-)%s*$') if v ~= '' then args[k] = v end end return p._main(args) end return p fzxzfes95mnfacwuhc6k9zeaixdtemr 736715 736713 2026-10-07T14:40:42Z King ChristLike 13051 1 revision imported from [[:en:Module:Uses_TemplateStyles]] 736712 wikitext text/x-wiki <includeonly>{{#invoke:Uses TemplateStyles|main}}</includeonly><noinclude>{{documentation}} <!-- Categories go on the /doc subpage and interwikis go on Wikidata. --> </noinclude> bbov914irrnmmvc6pz3scgivkjsu4ve Module:Uses TemplateStyles/config 828 18245 736716 333946 2026-09-28T18:00:00Z MusikBot II 14639 Changed protection settings for "[[Module:Uses TemplateStyles/config]]": [[Wikipedia:High-risk templates|High-risk template or module]]: 2531 transclusions ([[User:MusikBot II/TemplateProtector|more info]]) ([Edit=Require extended confirmed access] (indefinite) [Move=Require extended confirmed access] (indefinite)) 333945 Scribunto text/plain local cfg = {} -- Don’t touch this line. -- Subpage blacklist: these subpages will not be categorized (except for the -- error category, which is always added if there is an error). -- For example “Template:Foo/doc” matches the `doc = true` rule, so it will have -- no categories. “Template:Foo” and “Template:Foo/documentation” match no rules, -- so they *will* have categories. All rules should be in the -- ['<subpage name>'] = true, -- format. cfg['subpage_blacklist'] = { ['doc'] = true, ['sandbox'] = true, ['sandbox2'] = true, ['testcases'] = true, } -- Sandbox title: if the stylesheet’s title is <template>/<stylesheet>.css, the -- stylesheet’s sandbox is expected to be at <template>/<sandbox_title>/<stylesheet>.css -- Set to nil to disable sandbox links. cfg['sandbox_title'] = 'sandbox' -- Error category: this category is added if the module call contains errors -- (e.g. no stylesheet listed). A category name without namespace, or nil -- to disable categorization (not recommended). cfg['error_category'] = 'Uses TemplateStyles templates with errors' -- Default category: this category is added if no custom category is specified -- in module/template call. A category name without namespace, or nil -- to disable categorization. cfg['default_category'] = 'Templates using TemplateStyles' -- Protection conflict category: this category is added if the protection level -- of any stylesheet is lower than the protection level of the template. A category name -- without namespace, or nil to disable categorization (not recommended). cfg['protection_conflict_category'] = 'Templates using TemplateStyles with a different protection level' -- Hierarchy of protection levels, used to determine whether one protection level is lower -- than another and thus should populate protection_conflict_category. No protection is treated as zero cfg['protection_hierarchy'] = { autoconfirmed = 1, extendedconfirmed = 2, templateeditor = 3, sysop = 4 } -- Padlock pattern: Lua pattern to search on protected stylesheets for, or nil -- to disable padlock check. cfg['padlock_pattern'] = '{{pp-' -- Missing padlock category: this category is added if a protected stylesheet -- doesn’t contain any padlock template (specified by the above Lua pattern). -- A category name without namespace (no nil allowed) if the pattern is not nil, -- unused (and thus may be nil) otherwise. cfg['missing_padlock_category'] = 'Templates using TemplateStyles without padlocks' -- Default subpage for the stylesheet if none is given cfg['default_subpage_name'] = 'styles.css' return cfg -- Don’t touch this line. jobuplor7csgdjcx4c6xrtnslslvft4 736717 736716 2026-10-07T14:40:42Z King ChristLike 13051 1 revision imported from [[:en:Module:Uses_TemplateStyles/config]] 333945 Scribunto text/plain local cfg = {} -- Don’t touch this line. -- Subpage blacklist: these subpages will not be categorized (except for the -- error category, which is always added if there is an error). -- For example “Template:Foo/doc” matches the `doc = true` rule, so it will have -- no categories. “Template:Foo” and “Template:Foo/documentation” match no rules, -- so they *will* have categories. All rules should be in the -- ['<subpage name>'] = true, -- format. cfg['subpage_blacklist'] = { ['doc'] = true, ['sandbox'] = true, ['sandbox2'] = true, ['testcases'] = true, } -- Sandbox title: if the stylesheet’s title is <template>/<stylesheet>.css, the -- stylesheet’s sandbox is expected to be at <template>/<sandbox_title>/<stylesheet>.css -- Set to nil to disable sandbox links. cfg['sandbox_title'] = 'sandbox' -- Error category: this category is added if the module call contains errors -- (e.g. no stylesheet listed). A category name without namespace, or nil -- to disable categorization (not recommended). cfg['error_category'] = 'Uses TemplateStyles templates with errors' -- Default category: this category is added if no custom category is specified -- in module/template call. A category name without namespace, or nil -- to disable categorization. cfg['default_category'] = 'Templates using TemplateStyles' -- Protection conflict category: this category is added if the protection level -- of any stylesheet is lower than the protection level of the template. A category name -- without namespace, or nil to disable categorization (not recommended). cfg['protection_conflict_category'] = 'Templates using TemplateStyles with a different protection level' -- Hierarchy of protection levels, used to determine whether one protection level is lower -- than another and thus should populate protection_conflict_category. No protection is treated as zero cfg['protection_hierarchy'] = { autoconfirmed = 1, extendedconfirmed = 2, templateeditor = 3, sysop = 4 } -- Padlock pattern: Lua pattern to search on protected stylesheets for, or nil -- to disable padlock check. cfg['padlock_pattern'] = '{{pp-' -- Missing padlock category: this category is added if a protected stylesheet -- doesn’t contain any padlock template (specified by the above Lua pattern). -- A category name without namespace (no nil allowed) if the pattern is not nil, -- unused (and thus may be nil) otherwise. cfg['missing_padlock_category'] = 'Templates using TemplateStyles without padlocks' -- Default subpage for the stylesheet if none is given cfg['default_subpage_name'] = 'styles.css' return cfg -- Don’t touch this line. jobuplor7csgdjcx4c6xrtnslslvft4 Lola Rae 0 23356 736856 722272 2026-10-08T11:31:54Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736856 wikitext text/x-wiki {{Databox}}   [[Category:Articles with short description]] [[Category:Short description is different from Wikidata]] [[Category:Articles with hCards]] [[Category:Pages using infobox musical artist with associated acts]] [[Category:Articles with short description]] [[Category:Short description is different from Wikidata]] [[Category:Articles with hCards]] [[Category:Pages using infobox musical artist with associated acts]] {{Infobox musical artist|name=Lola Rae|image=|alt=|caption=|birth_name=Rachel Akosua Funmilola Garton|alias=|birth_date={{birth date and age|df=yes|1991|01|20}}|birth_place=[[Obalende]], [[Lagos]], Nigeria|origin=|death_date=<!-- {{death date and age|df=yes|YYYY|MM|DD|YYYY|MM|DD}} (death date 1st) -->|death_place=|genre={{flatlist| *[[Afrobeats]] *[[jazz]] *[[soul music|soul]] *[[Rhythm & blues|R&B]]}}|occupation=Singer|years_active=2010–present|label=|associated_acts={{flatlist| *[[Iyanya]] *[[Tiwa Savage]] *[[Awilo Longomba]] *[[Ice Prince]]}}|website=}} [[Category:Articles with short description]] [[Category:Short description is different from Wikidata]] [[Category:Articles with hCards]] [[Category:Pages using infobox musical artist with associated acts]] '''Rachel Akosua Funmilola Garton''' (nke a maara dị ka '''Lola Rae'''; amụrụ na 20 Jenụwarị 1991) bụ onye na-agụ egwu Naijiria. Ọ nwetara nkwadọ̀ mgbe a tọhapụrụ egwu izizi ya "Watch My Ting Go", nke nwetara otuto dị egwu ma si otú a mee ka a họpụta ya maka Most Promising Female Act to Watch na 2013 Nigeria Entertainment Awards.<ref>{{Cite news|url=https://www.bbc.com/news/world-africa-20632154|title=Nigeria's Lola Rae singer emerges on UK TV talent show|work=[[BBC|The BBC]]|date=6 December 2012|accessdate=4 June 2016}}</ref><ref>{{Cite web|url=http://notjustok.com/2013/06/02/nigerian-entertainment-awards-2013-view-full-nominees-list/|title=Nigeria Entertainment Awards 2013 View Full Nominees List|work=[[notJustOk]]|author=O.|first=Ovie|date=6 December 2012|accessdate=4 June 2016|archivedate=4 March 2016|archiveurl=https://web.archive.org/web/20160304044109/http://notjustok.com/2013/06/02/nigerian-entertainment-awards-2013-view-full-nominees-list/}}</ref> == Ịzụlite na agụmakwụkwọ == A mụrụ Lola Rae n'aka nna onye Britain na nne onye Ghana na [[Obalende]], mpaghara [[Lagos]], Nigeria. Ọ gụrụ akwụkwọ praịmarị na sekọndrị na St. Saviour's School, Ikoyi; na [[Lekki British School|Lekki British International High School]], Lagos, n'otu n'otu.<ref>{{Cite news|url=http://encomium.ng/i-have-always-wanted-to-do-music-lola-rae/|title='I have always wanted to do music' -Lola Rae|work=Ecomium Magazine|author=Wesley-Metigboun|first=Shade|date=30 January 2015|accessdate=4 June 2016}}</ref> Otú ọ dị, ọ hapụrụ Naịjirịa gaa England mgbe ọ dị afọ iri na ise iji mezue agụmakwụkwọ mahadum ya na Central Saint Martins, ebe ọ gụrụ akwá ejiji.<ref>{{Cite web|url=http://www.naijadeevas.com/2012/11/deeva-of-week-lola-rae.html|title=Deeva of the Week – Lola Rae|publisher=NaijaDeevas|date=19 November 2012|accessdate=4 June 2016}}</ref> == Ọrụ == Ọrụ ntụrụndụ Lola Rae malitere dị ka onye na-agba egwú mgbe ọ bụ onye otu egwu egwu "Mystikal" n'afọ 2010. Ndị na-agba egwú Mystikal nyochara maka ''Britain's'' Got Talent ebe Rae bụrụ abụ na asọmpi ahụ ma onye ọka ikpe Simon Cowell họpụtara ndị na-agba egwu Mystikal na ọkara ikpeazụ nkè asọmpi ahụ.<ref>{{Cite web|url=http://zenmagazineafrica.com/lifestyle/lola-rae/|title=Everyone's talking about …..Lola Rae|work=Zen Magazine|author=Nwokolo|first=Arinze|accessdate=4 June 2016|archiveurl=https://web.archive.org/web/20160624002323/http://zenmagazineafrica.com/lifestyle/lola-rae/|archivedate=24 June 2016}}</ref> Na ngwụcha asọmpi ahụ, a bịanyere aka na Syco maka otu afọ. Rae jụrụ oku ọ kpọrọ The X Factor iji chụsoo ọrụ onwe ya dị ka onye na-agụ egwu.<ref>{{Cite news|url=http://www.herald.ng/i-want-to-be-the-female-wizkid-lola-rae/|title="I want to be the female Wizkid" – Lola Rae|work=The Herald News|author=Sokoya|first=Seyi|date=18 August 2013|accessdate=4 June 2016|archive-date=14 September 2016|archive-url=https://web.archive.org/web/20160914075305/http://www.herald.ng/i-want-to-be-the-female-wizkid-lola-rae/|url-status=dead}}</ref><ref>{{Cite news|url=http://www.mobo.com/news-blogs/introducing-afrobeat-superstar-lola-rae|title=Introducing Afrobeat superstar Lola Rae|work=MOBO|date=9 June 2013|accessdate=4 June 2016|archive-date=13 August 2016|archive-url=https://web.archive.org/web/20160813092453/http://www.mobo.com/news-blogs/introducing-afrobeat-superstar-lola-rae|url-status=dead}}</ref> N'abalị iri na itoolu n'ọnwa Nọvemba n'afọ 2012, Rae wepụtara egwu izizi ya bụ Watch My Ting Go na egwu ọzọ akpọrọ High.<ref>{{Cite web|url=http://thegoodlifeea.com/?p=2591|title=LOLA RAE ALL SET TO STIR UP AFRICAN MUSIC|publisher=The Good Life|date=2 March 2015|accessdate=4 June 2016|archivedate=8 August 2016|archiveurl=https://web.archive.org/web/20160808052428/http://thegoodlifeea.com/?p=2591}}</ref><ref>{{Cite news|url=http://www.vanguardngr.com/2015/01/love-crazy-way-iyanya-twists-waist-lola-rae/|title=I love the crazy way Iyanya twists his waist – Lola Rae|work=[[Vanguard (Nigeria)|Vanguard News]]|author=Aina|first=Iyabo|date=29 January 2015|accessdate=4 June 2016}}</ref> A họpụtara ya dị ka "Most Promising Female Act to Watch" na 2013 Nigeria Entertainment Awards. Vidio ya na "Watch My Ting Go" gosipụtara na [[Soundcity TV]] na 8 Jenụwarị 2013 na ngosipụta cameo site na [[Iyanya]] na Emma Nyra.<ref>{{Cite web|url=http://jaguda.com/2013/01/08/new-video-lola-rae-watch-my-ting-go/|title=New Video: Lola Rae – Watch My Ting Go|publisher=Jaguda|author=Ayo Jaguda|date=8 January 2013|accessdate=4 June 2016|archivedate=5 August 2016|archiveurl=https://web.archive.org/web/20160805165625/http://jaguda.com/2013/01/08/new-video-lola-rae-watch-my-ting-go/}}</ref> A họpụtara vidiyo ahụ na 10th Channel O Music Video Awards.<ref>{{Cite web|url=http://channelo.dstv.com/2013/09/channel-o-africa-music-video-awards/|title=2013 Channel O Africa Music Video Awards|work=[[Channel O]]|date=3 September 2013|accessdate=4 June 2016|archiveurl=https://web.archive.org/web/20160324105440/http://channelo.dstv.com/2013/09/channel-o-africa-music-video-awards/|archivedate=24 March 2016}}</ref> N'ịgbaso "Watch My Ting Go", Rae gosipụtara Iyanya na egwú akpọrọ ''Fi Mi Le'' nke mere ka a họpụta ya ọzọ na 2014 Nigeria Entertainment Awards.<ref>{{Cite web|url=https://www.bellanaija.com/2014/05/genevieve-nnaji-don-jazzy-chiwetel-ejiofor-tiwa-savage-bovi-davido-nigeria-entertainment-awards-nominees-list/|title=Genevieve Nnaji, Don Jazzy, Chiwetel Ejiofor, Tiwa Savage, Bovi, Davido – Nigeria Entertainment Awards Nominees List|work=[[BellaNaija]]|date=29 May 2016|accessdate=4 June 2016}}</ref><ref>{{Cite web|url=http://tooxclusive.com/download-mp3/lola-rae-fimile-ft-iyanya/|title=Lola Rae – Fimile Ft. Iyanya|work=[[tooXclusive]]|author=Tyler|date=9 July 2013|accessdate=4 June 2016}}</ref> O mere ihe ngosi dị ka mmasị ịhụnanya Ice [[Ice Prince|Prince]] na vidiyo egwu ya "More".<ref>{{Cite web|url=http://pulse.ng/celebrities/lola-rae-singer-says-she-never-dated-ice-prince-id3501252.html|title=Lola Rae: Singer says she never dated Ice Prince|work=Pulse Nigeria|author=Tayo|first=Ayomide O.|date=20 February 2015|accessdate=4 June 2016|archivedate=1 July 2016|archiveurl=https://web.archive.org/web/20160701035428/http://pulse.ng/celebrities/lola-rae-singer-says-she-never-dated-ice-prince-id3501252.html}}</ref> == Ndụ onwe onye == Na Mee 2018, Rae mụrụ nwa nwanyị.<ref>{{Cite web|date=2018-05-27|title=Tekno, prety girlfriend, Lola Rae blessed with baby girl|url=https://www.vanguardngr.com/2018/05/tekno-lola-blessed-baby/|accessdate=2022-06-20|work=Vanguard News|language=en-GB}}</ref> == Nkọwapụta == === Ndị na-alụbeghị di === ; Dị ka onye na-ese ihe {| class="wikitable plainrowheaders" style="text-align:center;" |+Ndepụta nke ndị na-alụbeghị di dị ka onye na-eduzi ihe, na ọkwa chaatị ahọpụtara na asambodo, na-egosi afọ a tọhapụrụ na aha abọm ! rowspan="2" scope="col" style="width:20em;" |Aha ya ! rowspan="2" scope="col" |Afọ ! colspan="7" scope="col" |Ọnọdụ chaatị kachasị elu ! rowspan="2" scope="col" style="width:12em;" |asambodo ! rowspan="2" scope="col" |Album |- ! scope="col" style="width:3em;font-size:90%;" |NGA ! scope="col" style="width:3em;font-size:90%;" |GHA ! scope="col" style="width:3em;font-size:90%;" |RSA ! scope="col" style="width:3em;font-size:90%;" |AUS ! scope="col" style="width:3em;font-size:90%;" |UK ! scope="col" style="width:3em;font-size:90%;" |US ! scope="col" style="width:3em;font-size:90%;" |USR<nowiki>&</nowiki>amp;B/HH<nowiki><br id="mwaA"></nowiki><nowiki><br></nowiki><nowiki><br></nowiki><nowiki><br></nowiki> |- ! scope="row" |"Lee Ting M Go" | rowspan="2" |2012 |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị | | rowspan="5" |Ndị na-abụghị abọm |- ! scope="row" |"Ọdịdị elu" <span style="font-size:85%;">nke</span><br /><br /><br /><br /> nwere Bridge) |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị | |- ! scope="row" |"(Fi Mi Le" <span style="font-size:85%;">nke</span><br /><br /><br /><br /> gosipụtara <span style="font-size:85%;">[[Iyanya]]</span>) | rowspan="2" |2013 |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị | |- ! scope="row" |"Ọ Maara na Ọ Maara" |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị | |- ! scope="row" |"Ị maara ihe aha m bụ" |2015 |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị | |- ! scope="row" |"Otu Oge" |2016 |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị | |- | colspan="14" style="font-size:90%" |"X" na-egosi ihe ndekọ nke na-enweghị chaatị ma ọ bụ nke a na-ewepụtaghị na mpaghara ahụ. |} ; Dị ka onye na-ese ihe {| class="wikitable plainrowheaders" style="text-align:center;" |+Ndepụta nke ndị na-alụbeghị di dị ka onye na-ese ihe, na ọkwa chaatị ahọpụtara na asambodo, na-egosi afọ a tọhapụrụ na aha abọm ! rowspan="2" scope="col" style="width:20em;" |Aha ya ! rowspan="2" scope="col" |Afọ ! colspan="7" scope="col" |Ọnọdụ chaatị kachasị elu ! rowspan="2" scope="col" style="width:12em;" |asambodo ! rowspan="2" scope="col" |Album |- ! scope="col" style="width:3em;font-size:90%;" |NGA ! scope="col" style="width:3em;font-size:90%;" |GHA ! scope="col" style="width:3em;font-size:90%;" |RSA ! scope="col" style="width:3em;font-size:90%;" |AUS ! scope="col" style="width:3em;font-size:90%;" |UK ! scope="col" style="width:3em;font-size:90%;" |US ! scope="col" style="width:3em;font-size:90%;" |USR<nowiki>&</nowiki>amp;B/HH<nowiki><br id="mwyg"></nowiki><nowiki><br></nowiki><nowiki><br></nowiki><nowiki><br></nowiki> |- ! scope="row" |"Ginger"(BOJ na-egosi Lola Rae)<ref>{{Cite web|url=http://notjustok.com/2013/04/13/boj-ginger-ft-lola-rae-prod-by-studiomagic/|title=BOJ – Ginger ft. Lola Rae (Prod by StudioMagic)|work=notJustOk|author=Demola OG|date=13 April 2013|accessdate=4 June 2016|archivedate=7 August 2016|archiveurl=https://web.archive.org/web/20160807123600/http://notjustok.com/2013/04/13/boj-ginger-ft-lola-rae-prod-by-studiomagic/}}</ref><br /><br /><br /><br /> | rowspan="2" |2013 |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị | | rowspan="5" |Ndị na-abụghị abọm |- ! scope="row" |"Coupe Bibamba (Remix) "(<span style="font-size:85%;">[[Awilo Longomba]]</span> na-egosi Lola Rae)<br /><br /><br /><br /> |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị | |- ! scope="row" |"Egwu(Nizzy na-egosi Lola Rae)<br /><br /><br /><br /> | rowspan="2" |2014 |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị | |- ! scope="row" |"Ọrụ(TeeJay na-egosi Lola Rae)<br /><br /><br /><br /> |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị | |- ! scope="row" |"(Pele Mo"Danagog na-egosi Lola Rae)<br /><br /><br /><br /> |2015 |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị | |- | colspan="14" style="font-size:90%" |"X" na-egosi ihe ndekọ nke na-enweghị chaatị ma ọ bụ nke a na-ewepụtaghị na mpaghara ahụ. |} ; Ndị na-eme mkpọsa {| class="wikitable plainrowheaders" style="text-align:center;" |+Ndepụta nke ndị na-akwalite egwu dị ka onye na-ese ihe, na ọkwa chaatị ahọpụtara na asambodo, na-egosi afọ a tọhapụrụ na aha abọm ! rowspan="2" scope="col" style="width:20em;" |Aha ya ! rowspan="2" scope="col" |Afọ ! colspan="7" scope="col" |Ọnọdụ chaatị kachasị elu ! rowspan="2" scope="col" style="width:12em;" |asambodo ! rowspan="2" scope="col" |Album |- ! scope="col" style="width:3em;font-size:90%;" |NGA ! scope="col" style="width:3em;font-size:90%;" |GHA ! scope="col" style="width:3em;font-size:90%;" |RSA ! scope="col" style="width:3em;font-size:90%;" |AUS ! scope="col" style="width:3em;font-size:90%;" |UK ! scope="col" style="width:3em;font-size:90%;" |US ! scope="col" style="width:3em;font-size:90%;" |USR<nowiki>&</nowiki>amp;B/HH<nowiki><br id="mwASk"></nowiki><nowiki><br></nowiki><nowiki><br></nowiki><nowiki><br></nowiki> |- ! scope="row" |"(Africa Rising"Davido, <span style="font-size:85%;">[[Tiwa Savage]]</span>, <span style="font-size:85%;">Lola Rae</span>, <span style="font-size:85%;">[[Sarkodie (rapper)|Sarkodie]]</span>, <span style="font-size:85%;">[[Diamond Platnumz]]</span> <span style="font-size:85%;">na</span> Mi Casa)<ref>{{Cite web|url=http://notjustok.com/2014/06/25/video-davido-tiwa-savage-lola-rae-sarkodie-diamond-mi-casa-africa-rising/|title=VIDEO: Davido, Tiwa Savage, Lola Rae, Sarkodie, Diamond, Mi Casa – Africa Rising|work=notJustOk|author=Ovie O.|date=25 June 2014|accessdate=4 June 2016|archivedate=7 August 2016|archiveurl=https://web.archive.org/web/20160807135504/http://notjustok.com/2014/06/25/video-davido-tiwa-savage-lola-rae-sarkodie-diamond-mi-casa-africa-rising/}}</ref><br /><br /><br /><br /> |2014 |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị |Ọdịdị | |Ndị na-abụghị abọm |- | colspan="14" style="font-size:90%" |"X" na-egosi ihe ndekọ nke na-enweghị chaatị ma ọ bụ nke a na-ewepụtaghị na mpaghara ahụ. |} == Onyinye na nhọpụta == {| class="wikitable" !Afọ !Ememe mmeri !Ihe nrite !Ọrụ / Ihe Nri !Nsonaazụ !Ref |- | rowspan="2" |2013 |2013 Channel O Africa Music Video Awards |Onye Ọhụrụ Kasị Mma |"Lee Ting M Go" |{{Nom}} |<ref>{{Cite news|url=http://www.nigerianwatch.com/celebritywatch-with-michael-tubes/2417-uk-afrobeat-rising-star-lola-rae-nominated-for-channel-o-music-awards-|title=UK Afrobeat rising star Lola Rae nominated for Channel O Music Awards|work=Nigerian Watch|date=11 September 2011|accessdate=4 June 2016|archive-url=https://web.archive.org/web/20160918141918/http://www.nigerianwatch.com/celebritywatch-with-michael-tubes/2417-uk-afrobeat-rising-star-lola-rae-nominated-for-channel-o-music-awards-|archive-date=18 September 2016|url-status=dead}}</ref> |- |2013 Nigeria Entertainment Awards |Ihe Omume Nwanyị Kasị Na-ekwe Nwe Onwe Gị Ka Ịle | rowspan="2" |Ya onwe ya |{{Nom}} |<ref>{{Cite web|url=http://jaguda.com/2013/06/04/and-the-nominees-are-the-2013-nea-award-nominees/|title=And The Nominees Are…|publisher=Jaguda|date=4 June 2013|accessdate=4 June 2016|archivedate=5 August 2016|archiveurl=https://web.archive.org/web/20160805165412/http://jaguda.com/2013/06/04/and-the-nominees-are-the-2013-nea-award-nominees/}}</ref> |- |2014 |2014 Nigeria Entertainment Awards |Onye na-ese ihe n'afọ na Diaspora |{{Nom}} |<ref>{{Cite news|url=http://www.nigerianeye.com/2014/09/full-list-of-winner-for-nea-awards-2014.html|title=Full list of winners for the NEA Awards 2014|work=The Nigerian Eye|date=3 September 2014|accessdate=4 June 2016}}</ref> |} == Ihe odide == {{Reflist}}{{Authority control}} [[Òtù:Mmadụ ndi di ndụ]] ekmqn12zpzxgl8fgoic3iw2275bxam0 Module:Citation/CS1 828 24495 736704 241990 2026-08-08T13:56:56Z Trappist the monk 14640 synch from sandbox; 736704 Scribunto text/plain require ('strict'); --[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- each of these counts against the Lua upvalue limit ]] local validation; -- functions in Module:Citation/CS1/Date_validation local utilities; -- functions in Module:Citation/CS1/Utilities local z = {}; -- table of tables in Module:Citation/CS1/Utilities local identifiers; -- functions and tables in Module:Citation/CS1/Identifiers local metadata; -- functions in Module:Citation/CS1/COinS local cfg = {}; -- table of configuration tables that are defined in Module:Citation/CS1/Configuration local whitelist = {}; -- table of tables listing valid template parameter names; defined in Module:Citation/CS1/Whitelist --[[------------------< P A G E S C O P E V A R I A B L E S >--------------- declare variables here that have page-wide scope that are not brought in from other modules; that are created here and used here ]] local added_deprecated_cat; -- boolean flag so that the category is added only once local added_vanc_errs; -- boolean flag so we only emit one Vancouver error / category local added_generic_name_errs; -- boolean flag so we only emit one generic name error / category and stop testing names once an error is encountered local added_numeric_name_errs; -- boolean flag so we only emit one numeric name error / category and stop testing names once an error is encountered local added_numeric_name_maint; -- boolean flag so we only emit one numeric name maint category and stop testing names once a category has been emitted local is_preview_mode; -- true when article is in preview mode; false when using 'Preview page with this template' (previewing the module) local is_sandbox; -- true when using sandbox modules to render citation local url_was_archive_today; -- boolean flag set to true when has_archive_today_url() has unset |url= because it held a deprecated archive.today url --[[--------------------------< F I R S T _ S E T >------------------------------------------------------------ Locates and returns the first set value in a table of values where the order established in the table, left-to-right (or top-to-bottom), is the order in which the values are evaluated. Returns nil if none are set. This version replaces the original 'for _, val in pairs do' and a similar version that used ipairs. With the pairs version the order of evaluation could not be guaranteed. With the ipairs version, a nil value would terminate the for-loop before it reached the actual end of the list. ]] local function first_set (list, count) local i = 1; while i <= count do -- loop through all items in list if utilities.is_set( list[i] ) then return list[i]; -- return the first set list member end i = i + 1; -- point to next end end --[[--------------------------< A D D _ V A N C _ E R R O R >---------------------------------------------------- Adds a single Vancouver system error message to the template's output regardless of how many error actually exist. To prevent duplication, added_vanc_errs is nil until an error message is emitted. added_vanc_errs is a Boolean declared in page scope variables above ]] local function add_vanc_error (source, position) if added_vanc_errs then return end added_vanc_errs = true; -- note that we've added this category utilities.set_message ('err_vancouver', {source, position}); end --[[--------------------------< I S _ S C H E M E >------------------------------------------------------------ does this thing that purports to be a URI scheme seem to be a valid scheme? The scheme is checked to see if it is in agreement with http://tools.ietf.org/html/std66#section-3.1 which says: Scheme names consist of a sequence of characters beginning with a letter and followed by any combination of letters, digits, plus ("+"), period ("."), or hyphen ("-"). returns true if it does, else false ]] local function is_scheme (scheme) return scheme and scheme:match ('^%a[%a%d%+%.%-]*:'); -- true if scheme is set and matches the pattern end --[=[-------------------------< I S _ D O M A I N _ N A M E >-------------------------------------------------- Does this thing that purports to be a domain name seem to be a valid domain name? Syntax defined here: http://tools.ietf.org/html/rfc1034#section-3.5 BNF defined here: https://tools.ietf.org/html/rfc4234 Single character names are generally reserved; see https://tools.ietf.org/html/draft-ietf-dnsind-iana-dns-01#page-15; see also [[Single-letter second-level domain]] list of TLDs: https://www.iana.org/domains/root/db RFC 952 (modified by RFC 1123) requires the first and last character of a hostname to be a letter or a digit (see http://tools.ietf.org/html/rfc952 §GRAMMATICAL HOST TABLE SPECIFICATION §§B. Lexical grammar <name>; see http://tools.ietf.org/html/rfc1123#section-2). Between the first and last characters the name may use letters, digits, and the hyphen. Also allowed are IPv4 addresses. IPv6 not supported domain is expected to be stripped of any path so that the last character in the last character of the TLD. tld is two or more alpha characters. Any preceding '//' (from splitting a URL with a scheme) will be stripped here. Perhaps not necessary but retained in case it is necessary for IPv4 dot decimal. There are several tests: the first character of the whole domain name including subdomains must be a letter or a digit internationalized domain name (ASCII characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the TLD) see https://tools.ietf.org/html/rfc3490 single-letter/digit second-level domains in the .org, .cash, and .today TLDs q, x, and z SL domains in the .com TLD i and q SL domains in the .net TLD single-letter SL domains in the ccTLDs (where the ccTLD is two letters) two-character SL domains in gTLDs (where the gTLD is two or more letters) three-plus-character SL domains in gTLDs (where the gTLD is two or more letters) IPv4 dot-decimal address format; TLD not allowed returns true if domain appears to be a proper name and TLD or IPv4 address, else false ]=] local function is_domain_name (domain) if not domain then return false; -- if not set, abandon end domain = domain:gsub ('^//', ''); -- strip '//' from domain name if present; done here so we only have to do it once local sl_domain = domain:match ('[^%.]+') or domain; -- test the second level domain name if not (sl_domain:match ('^%w') and sl_domain:match ('%w$') and -- first and last characters must be letter or digit sl_domain:match ('^[%w%-]+$')) then -- all other characters must be letters, digits, or hyphen-minus return false; end if domain:match ('^%a+:') then -- hack to detect things that look like s:Page:Title where Page: is namespace at Wikisource return false; end local patterns = { -- patterns that look like URLs '%f[%w][%w][%w%-]+[%w]%.%a%a+$', -- three or more character hostname.hostname or hostname.tld '%f[%w][%w][%w%-]+[%w]%.xn%-%-[%w]+$', -- internationalized domain name with ACE prefix '%f[%a][qxz]%.com$', -- assigned one character .com hostname (x.com times out 2015-12-10) '%f[%a][iq]%.net$', -- assigned one character .net hostname (q.net registered but not active 2015-12-10) '%f[%w][%w]%.%a%a$', -- one character hostname and ccTLD (2 chars) '%f[%w][%w][%w]%.%a%a+$', -- two character hostname and TLD '^%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?', -- IPv4 address '[%a%d]+%:?' -- IPv6 address } for _, pattern in ipairs (patterns) do -- loop through the patterns list if domain:match (pattern) then return true; -- if a match then we think that this thing that purports to be a URL is a URL end end for _, d in ipairs (cfg.single_letter_2nd_lvl_domains_t) do -- look for single letter second level domain names for these top level domains if domain:match ('%f[%w][%w]%.' .. d) then return true end end return false; -- no matches, we don't know what this thing is end --[[--------------------------< I S _ U R L >------------------------------------------------------------------ returns true if the scheme and domain parts of a URL appear to be a valid URL; else false. This function is the last step in the validation process. This function is separate because there are cases that are not covered by split_url(), for example is_parameter_ext_wikilink() which is looking for bracketted external wikilinks. ]] local function is_url (scheme, domain) if utilities.is_set (scheme) then -- if scheme is set check it and domain return is_scheme (scheme) and is_domain_name (domain); else return is_domain_name (domain); -- scheme not set when URL is protocol-relative end end --[[--------------------------< S P L I T _ U R L >------------------------------------------------------------ Split a URL into a scheme, authority indicator, and domain. First remove Fully Qualified Domain Name terminator (a dot following TLD) (if any) and any path(/), query(?) or fragment(#). If protocol-relative URL, return nil scheme and domain else return nil for both scheme and domain. When not protocol-relative, get scheme, authority indicator, and domain. If there is an authority indicator (one or more '/' characters immediately following the scheme's colon), make sure that there are only 2. Any URL that does not have news: scheme must have authority indicator (//). TODO: are there other common schemes like news: that don't use authority indicator? Strip off any port and path; ]] local function split_url (url_str) local scheme, authority, domain; url_str = url_str:gsub ('([%a%d])%.?[/%?#].*$', '%1'); -- strip FQDN terminator and path(/), query(?), fragment (#) (the capture prevents false replacement of '//') if url_str:match ('^//%S*') then -- if there is what appears to be a protocol-relative URL domain = url_str:match ('^//(%S*)') elseif url_str:match ('%S-:/*%S+') then -- if there is what appears to be a scheme, optional authority indicator, and domain name scheme, authority, domain = url_str:match ('(%S-:)(/*)(%S+)'); -- extract the scheme, authority indicator, and domain portions if utilities.is_set (authority) then authority = authority:gsub ('//', '', 1); -- replace place 1 pair of '/' with nothing; if utilities.is_set(authority) then -- if anything left (1 or 3+ '/' where authority should be) then return scheme; -- return scheme only making domain nil which will cause an error message end else if not scheme:match ('^news:') then -- except for news:..., MediaWiki won't link URLs that do not have authority indicator; TODO: a better way to do this test? return scheme; -- return scheme only making domain nil which will cause an error message end end domain = domain:gsub ('(%a):%d+', '%1'); -- strip port number if present end return scheme, domain; end --[[--------------------------< L I N K _ P A R A M _ O K >--------------------------------------------------- checks the content of |title-link=, |series-link=, |author-link=, etc. for properly formatted content: no wikilinks, no URLs Link parameters are to hold the title of a Wikipedia article, so none of the WP:TITLESPECIALCHARACTERS are allowed: # < > [ ] | { } _ except the underscore which is used as a space in wiki URLs and # which is used for section links returns false when the value contains any of these characters. When there are no illegal characters, this function returns TRUE if value DOES NOT appear to be a valid URL (the |<param>-link= parameter is ok); else false when value appears to be a valid URL (the |<param>-link= parameter is NOT ok). ]] local function link_param_ok (value) local scheme, domain; if value:find ('[<>%[%]|{}]') then -- if any prohibited characters return false; end scheme, domain = split_url (value); -- get scheme or nil and domain or nil from URL; return not is_url (scheme, domain); -- return true if value DOES NOT appear to be a valid URL end --[[--------------------------< L I N K _ T I T L E _ O K >--------------------------------------------------- Use link_param_ok() to validate |<param>-link= value and its matching |<title>= value. |<title>= may be wiki-linked but not when |<param>-link= has a value. This function emits an error message when that condition exists check <link> for inter-language interwiki-link prefix. prefix must be a MediaWiki-recognized language code and must begin with a colon. ]] local function link_title_ok (link, lorig, title, torig) local orig; if utilities.is_set (link) then -- don't bother if <param>-link doesn't have a value if not link_param_ok (link) then -- check |<param>-link= markup orig = lorig; -- identify the failing link parameter elseif title:find ('%[%[') then -- check |title= for wikilink markup orig = torig; -- identify the failing |title= parameter elseif link:match ('^%a+:') then -- if the link is what looks like an interwiki local prefix = link:match ('^(%a+):'):lower(); -- get the interwiki prefix if cfg.inter_wiki_map[prefix] then -- if prefix is in the map, must have preceding colon orig = lorig; -- flag as error end end end if utilities.is_set (orig) then link = ''; -- unset utilities.set_message ('err_bad_paramlink', orig); -- URL or wikilink in |title= with |title-link=; end return link; -- link if ok, empty string else end --[[--------------------------< C H E C K _ U R L >------------------------------------------------------------ Determines whether a URL string appears to be valid. First we test for space characters. If any are found, return false. Then split the URL into scheme and domain portions, or for protocol-relative (//example.com) URLs, just the domain. Use is_url() to validate the two portions of the URL. If both are valid, or for protocol-relative if domain is valid, return true, else false. Because it is different from a standard URL, and because this module used external_link() to make external links that work for standard and news: links, we validate newsgroup names here. The specification for a newsgroup name is at https://tools.ietf.org/html/rfc5536#section-3.1.4 ]] local function check_url( url_str ) if nil == url_str:match ("^%S+$") then -- if there are any spaces in |url=value it can't be a proper URL return false; end local scheme, domain; scheme, domain = split_url (url_str); -- get scheme or nil and domain or nil from URL; if 'news:' == scheme then -- special case for newsgroups return domain:match('^[%a%d%+%-_]+%.[%a%d%+%-_%.]*[%a%d%+%-_]$'); end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[=[-------------------------< I S _ P A R A M E T E R _ E X T _ W I K I L I N K >---------------------------- Return true if a parameter value has a string that begins and ends with square brackets [ and ] and the first non-space characters following the opening bracket appear to be a URL. The test will also find external wikilinks that use protocol-relative URLs. Also finds bare URLs. The frontier pattern prevents a match on interwiki-links which are similar to scheme:path URLs. The tests that find bracketed URLs are required because the parameters that call this test (currently |title=, |chapter=, |work=, and |publisher=) may have wikilinks and there are articles or redirects like '//Hus' so, while uncommon, |title=[[//Hus]] is possible as might be [[en://Hus]]. ]=] local function is_parameter_ext_wikilink (value) local scheme, domain; if value:match ('%f[%[]%[%a%S*:%S+.*%]') then -- if ext. wikilink with scheme and domain: [xxxx://yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(%a%S*:%S+).*%]')); elseif value:match ('%f[%[]%[//%S+.*%]') then -- if protocol-relative ext. wikilink: [//yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(//%S+).*%]')); elseif value:match ('%a%S*:%S+') then -- if bare URL with scheme; may have leading or trailing plain text scheme, domain = split_url (value:match ('(%a%S*:%S+)')); elseif value:match ('^//%S+') or value:match ('%s//%S+') then -- if protocol-relative bare URL: //yyyyy.zzz; authority indicator (//) must be be preceded nothing or by whitespace scheme, domain = split_url (value:match ('(//%S+)')); -- what is left should be the domain else return false; -- didn't find anything that is obviously a URL end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[[--------------------------< I S _ A R C H I V E _ T O D A Y _ U R L >-------------------------------------- archive.today (and .ph, .is, .md, .li, .fo, .vn) are deprecated. See Wikipedia:Requests_for_comment/Archive.is_RFC_5 (Special:Permalink/1339352976) <val> is a string that may or may not be a url ]] local function is_archive_today_url (val) if is_parameter_ext_wikilink (val) then -- is <val> a url? local tld = val:match ('archive%.(%l+)/'); -- get the tld; real archive.today urls have a '/' after the tld return tld and cfg.archive_today_tlds_t[tld]; -- return true if <tld> is one of the archive.today tlds; nil else end end --[[--------------------------< H A S _ A R C H I V E _ T O D A Y _ U R L >------------------------------------ blank any parameter that holds one of the archive.today tlds (.today, .ph, .is, .md, .li, .fo, .vn) and also blank parameters that are dependent on the offending parameter. input <cite_args_t> is a table of all of this template's parameters This function modifies <cite_args_t> when |url= or its alias |URL= hold an archive.today url, this function sets the flag <url_was_archive_today> which is used later to suppress the missing url error message from {{citation}} when it has |website=<summat> or from the templates {{cite web}}, {{cite podcast}}, {{cite mailing list}} which all require a url. returns nothing ]] local function has_archive_today_url (cite_args_t) local unset_params_t = {}; -- to hold a sequence of parameters to unset from cite_args_t for p, v in pairs (cite_args_t) do -- look at each parameter in the template if is_archive_today_url (v:lower()) then -- if it has a parameter with an archive.today url table.insert (unset_params_t, p); -- add the url-holding parameter name to our list of parameters to unset (may or may not be a legitimate url parameter) if 'url' == p:lower() then -- if this parameter is |url= or |URL= url_was_archive_today = true; -- set a flag so that cite web / podcast / mailinglist don't emit a missing url error message end if p:match ('archive%-?url') and ('usurped' == cite_args_t['url-status'] or 'unfit' == cite_args_t['url-status']) then -- if |archive-url=archive.today and |url-status=unfit/usurped url_was_archive_today = true; -- set a flag so that cite web / podcast / mailinglist don't emit a missing url error message table.insert (unset_params_t, 'url'); -- add the url parameter name to our list of parameters to unset (may or may not be a legitimate url parameter) table.insert (unset_params_t, 'URL'); -- this one because both are possible end if cfg.dependencies_t[p] then -- if this url-holding parameter (<p>) has dependencies for _, dependent in ipairs (cfg.dependencies_t[p]) do -- loop through the url-holding parameter's dependency sequence table.insert (unset_params_t, dependent); -- add dependent parameter to the list to be unset end end end end if 0 < #unset_params_t then -- when there are parameters to unset if not is_preview_mode then -- when in preview mode do not suppress any parameters for _, unset_param in ipairs (unset_params_t) do -- loop through the sequence cite_args_t[unset_param] = nil; -- and unset the url-holding parameter and its dependent parameters to avoid parameter-requires-other-parameter errors end end utilities.set_message ('maint_deprecated_archive'); -- add a maintenance message end end --[[-------------------------< C H E C K _ F O R _ U R L >----------------------------------------------------- loop through a list of parameters and their values. Look at the value and if it has an external link, emit an error message. ]] local function check_for_url (parameter_list, error_list) for k, v in pairs (parameter_list) do -- for each parameter in the list if is_parameter_ext_wikilink (v) then -- look at the value; if there is a URL add an error message table.insert (error_list, utilities.wrap_style ('parameter', k)); end end end --[[--------------------------< S A F E _ F O R _ U R L >------------------------------------------------------ Escape sequences for content that will be used for URL descriptions ]] local function safe_for_url( str ) if str:match( "%[%[.-%]%]" ) ~= nil then utilities.set_message ('err_wikilink_in_url', {}); end return str:gsub( '[%[%]\n]', { ['['] = '&#91;', [']'] = '&#93;', ['\n'] = ' ' } ); end --[[--------------------------< E X T E R N A L _ L I N K >---------------------------------------------------- Format an external link with error checking ]] local function external_link (URL, label, source, access) local domain; local path; local base_url; if not utilities.is_set (label) then label = URL; if utilities.is_set (source) then utilities.set_message ('err_bare_url_missing_title', {utilities.wrap_style ('parameter', source)}); else error (cfg.messages["bare_url_no_origin"]); -- programmer error; valid parameter name does not have matching meta-parameter end end if not check_url (URL) then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); end domain, path = URL:match ('^([/%.%-%+:%a%d]+)([/%?#].*)$'); -- split the URL into scheme plus domain and path if path then -- if there is a path portion path = path:gsub ('[%[%]]', {['['] = '%5b', [']'] = '%5d'}); -- replace '[' and ']' with their percent-encoded values URL = table.concat ({domain, path}); -- and reassemble end base_url = table.concat ({ "[", URL, " ", safe_for_url (label), "]" }); -- assemble a wiki-markup URL if utilities.is_set (access) then -- access level (subscription, registration, limited) base_url = utilities.substitute (cfg.presentation['ext-link-access-signal'], {cfg.presentation[access].class, cfg.presentation[access].title, base_url}); -- add the appropriate icon end return base_url; end --[[--------------------------< D E P R E C A T E D _ P A R A M E T E R >-------------------------------------- Categorize and emit an error message when the citation contains one or more deprecated parameters. The function includes the offending parameter name to the error message. Only one error message is emitted regardless of the number of deprecated parameters in the citation. added_deprecated_cat is a Boolean declared in page scope variables above ]] local function deprecated_parameter(name) if not added_deprecated_cat then added_deprecated_cat = true; -- note that we've added this category utilities.set_message ('err_deprecated_params', {name}); -- add error message end end --[=[-------------------------< K E R N _ Q U O T E S >-------------------------------------------------------- Apply kerning to open the space between the quote mark provided by the module and a leading or trailing quote mark contained in a |title= or |chapter= parameter's value. This function will positive kern either single or double quotes: "'Unkerned title with leading and trailing single quote marks'" " 'Kerned title with leading and trailing single quote marks' " (in real life the kerning isn't as wide as this example) Double single quotes (italic or bold wiki-markup) are not kerned. Replaces Unicode quote marks in plain text or in the label portion of a [[L|D]] style wikilink with typewriter quote marks regardless of the need for kerning. Unicode quote marks are not replaced in simple [[D]] wikilinks. Call this function for chapter titles, for website titles, etc.; not for book titles. ]=] local function kern_quotes (str) local wl_type, label, link; wl_type, label, link = utilities.is_wikilink (str); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] if 1 == wl_type then -- [[D]] simple wikilink with or without quote marks if mw.ustring.match (str, '%[%[[\"“”\'‘’].+[\"“”\'‘’]%]%]') then -- leading and trailing quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); str = utilities.substitute (cfg.presentation['kern-right'], str); elseif mw.ustring.match (str, '%[%[[\"“”\'‘’].+%]%]') then -- leading quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); elseif mw.ustring.match (str, '%[%[.+[\"“”\'‘’]%]%]') then -- trailing quote marks str = utilities.substitute (cfg.presentation['kern-right'], str); end else -- plain text or [[L|D]]; text in label variable label = mw.ustring.gsub (label, '[“”]', '\"'); -- replace “” (U+201C & U+201D) with " (typewriter double quote mark) label = mw.ustring.gsub (label, '[‘’]', '\''); -- replace ‘’ (U+2018 & U+2019) with ' (typewriter single quote mark) local cap = mw.ustring.match (label, "^([\"\'][^\'].+)"); -- match leading double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-left'], cap); end cap = mw.ustring.match (label, "^(.+[^\'][\"\'])$") -- match trailing double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-right'], cap); end if 2 == wl_type then str = utilities.make_wikilink (link, label); -- reassemble the wikilink else str = label; end end return str; end --[[--------------------------< F O R M A T _ S C R I P T _ V A L U E >---------------------------------------- |script-title= holds title parameters that are not written in Latin-based scripts: Chinese, Japanese, Arabic, Hebrew, etc. These scripts should not be italicized and may be written right-to-left. The value supplied by |script-title= is concatenated onto Title after Title has been wrapped in italic markup. Regardless of language, all values provided by |script-title= are wrapped in <bdi>...</bdi> tags to isolate RTL languages from the English left to right. |script-title= provides a unique feature. The value in |script-title= may be prefixed with a two-character ISO 639-1 language code and a colon: |script-title=ja:*** *** (where * represents a Japanese character) Spaces between the two-character code and the colon and the colon and the first script character are allowed: |script-title=ja : *** *** |script-title=ja: *** *** |script-title=ja :*** *** Spaces preceding the prefix are allowed: |script-title = ja:*** *** The prefix is checked for validity. If it is a valid ISO 639-1 language code, the lang attribute (lang="ja") is added to the <bdi> tag so that browsers can know the language the tag contains. This may help the browser render the script more correctly. If the prefix is invalid, the lang attribute is not added. At this time there is no error message for this condition. Supports |script-title=, |script-chapter=, |script-<periodical>= ]] local function format_script_value (script_value, script_param) local lang=''; -- initialize to empty string local name; if script_value:match('^%l%l%l?%s*:') then -- if first 3 or 4 non-space characters are script language prefix lang = script_value:match('^(%l%l%l?)%s*:%s*%S.*'); -- get the language prefix or nil if there is no script if not utilities.is_set (lang) then utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing title part']}); -- prefix without 'title'; add error message return ''; -- script_value was just the prefix so return empty string end -- if we get this far we have prefix and script name = cfg.lang_tag_remap[lang] or mw.language.fetchLanguageName( lang, cfg.this_wiki_code ); -- get language name so that we can use it to categorize if utilities.is_set (name) then -- is prefix a proper ISO 639-1 language code? script_value = script_value:gsub ('^%l+%s*:%s*', ''); -- strip prefix from script -- is prefix one of these language codes? if utilities.in_array (lang, cfg.script_lang_codes) then utilities.add_prop_cat ('script', {name, lang}) else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['unknown language code']}); -- unknown script-language; add error message end lang = ' lang="' .. lang .. '" '; -- convert prefix into a lang attribute else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['invalid language code']}); -- invalid language code; add error message lang = ''; -- invalid so set lang to empty string end else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing prefix']}); -- no language code prefix; add error message end script_value = utilities.substitute (cfg.presentation['bdi'], {lang, script_value}); -- isolate in case script is RTL return script_value; end --[[--------------------------< S C R I P T _ C O N C A T E N A T E >------------------------------------------ Initially for |title= and |script-title=, this function concatenates those two parameter values after the script value has been wrapped in <bdi> tags. ]] local function script_concatenate (title, script, script_param) if utilities.is_set (script) then script = format_script_value (script, script_param); -- <bdi> tags, lang attribute, categorization, etc.; returns empty string on error if utilities.is_set (script) then title = title .. ' ' .. script; -- concatenate title and script title end end return title; end --[[--------------------------< W R A P _ M S G >-------------------------------------------------------------- Applies additional message text to various parameter values. Supplied string is wrapped using a message_list configuration taking one argument. Supports lower case text for {{citation}} templates. Additional text taken from citation_config.messages - the reason this function is similar to but separate from wrap_style(). ]] local function wrap_msg (key, str, lower) if not utilities.is_set ( str ) then return ""; end if true == lower then local msg; msg = cfg.messages[key]:lower(); -- set the message to lower case before return utilities.substitute ( msg, str ); -- including template text else return utilities.substitute ( cfg.messages[key], str ); end end --[[----------------< W I K I S O U R C E _ U R L _ M A K E >------------------- Makes a Wikisource URL from Wikisource interwiki-link. Returns the URL and appropriate label; nil else. str is the value assigned to |chapter= (or aliases) or |title= or |title-link= ]] local function wikisource_url_make (str) local wl_type, D, L; local ws_url, ws_label; local wikisource_prefix = table.concat ({'https://', cfg.this_wiki_code, '.wikisource.org/wiki/'}); wl_type, D, L = utilities.is_wikilink (str); -- wl_type is 0 (not a wikilink), 1 (simple wikilink), 2 (complex wikilink) if 0 == wl_type then -- not a wikilink; might be from |title-link= str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 1 == wl_type then -- simple wikilink: [[Wikisource:ws article]] str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 2 == wl_type then -- non-so-simple wikilink: [[Wikisource:ws article|displayed text]] ([[L|D]]) str = L:match ('^[Ww]ikisource:(.+)') or L:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_label = D; -- get ws article name from display portion of interwiki link ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title without namespace from link portion of wikilink }); end end if ws_url then ws_url = mw.uri.encode (ws_url, 'WIKI'); -- make a usable URL ws_url = ws_url:gsub ('%%23', '#'); -- undo percent-encoding of fragment marker end return ws_url, ws_label, L or D; -- return proper URL or nil and a label or nil end --[[----------------< F O R M A T _ P E R I O D I C A L >----------------------- Format the three periodical parameters: |script-<periodical>=, |<periodical>=, and |trans-<periodical>= into a single Periodical meta-parameter. ]] local function format_periodical (script_periodical, script_periodical_source, periodical, trans_periodical) if not utilities.is_set (periodical) then periodical = ''; -- to be safe for concatenation else periodical = utilities.wrap_style ('italic-title', periodical); -- style end periodical = script_concatenate (periodical, script_periodical, script_periodical_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (trans_periodical) then trans_periodical = utilities.wrap_style ('trans-italic-title', trans_periodical); if utilities.is_set (periodical) then periodical = periodical .. ' ' .. trans_periodical; else -- here when trans-periodical without periodical or script-periodical periodical = trans_periodical; utilities.set_message ('err_trans_missing_title', {'periodical'}); end end return periodical; end --[[------------------< F O R M A T _ C H A P T E R _ T I T L E >--------------- Format the four chapter parameters: |script-chapter=, |chapter=, |trans-chapter=, and |chapter-url= into a single chapter meta- parameter (chapter_url_source used for error messages). ]] local function format_chapter_title (script_chapter, script_chapter_source, chapter, trans_chapter, trans_chapter_source, chapter_url, chapter_url_source, no_quotes, access) local ws_url, ws_label, L = wikisource_url_make (chapter); -- make a wikisource URL and label from a wikisource interwiki link if ws_url then ws_label = ws_label:gsub ('_', ' '); -- replace underscore separators with space characters chapter = ws_label; end if not utilities.is_set (chapter) then chapter = ''; -- to be safe for concatenation else if false == no_quotes then chapter = kern_quotes (chapter); -- if necessary, separate chapter title's leading and trailing quote marks from module provided quote marks chapter = utilities.wrap_style ('quoted-title', chapter); end end chapter = script_concatenate (chapter, script_chapter, script_chapter_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (chapter_url) then chapter = external_link (chapter_url, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate elseif ws_url then chapter = external_link (ws_url, chapter .. '&nbsp;', 'ws link in chapter'); -- adds bare_url_missing_title error if appropriate; space char to move icon away from chap text; TODO: better way to do this? chapter = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, chapter}); end if utilities.is_set (trans_chapter) then trans_chapter = utilities.wrap_style ('trans-quoted-title', trans_chapter); if utilities.is_set (chapter) then chapter = chapter .. ' ' .. trans_chapter; else -- here when trans_chapter without chapter or script-chapter chapter = trans_chapter; utilities.set_message ('err_trans_missing_title', {trans_chapter_source:match ('trans%-?(.+)')}); -- when no chapter, get matching name from trans-<param> end end return chapter; end --[[----------------< H A S _ I N V I S I B L E _ C H A R S >------------------- This function searches a parameter's value for non-printable or invisible characters. The search stops at the first match. This function will detect the visible replacement character when it is part of the Wikisource. Detects but ignores nowiki and math stripmarkers. Also detects other named stripmarkers (gallery, math, pre, ref) and identifies them with a slightly different error message. See also coins_cleanup(). Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker that was detected along with its position (or, for multi-byte characters, the position of its first byte) in the parameter value. ]] local function has_invisible_chars (param, v) local position; -- position of invisible char or starting position of stripmarker local capture; -- used by stripmarker detection to hold name of the stripmarker local stripmarker; -- boolean set true when a stripmarker is found capture = string.match (v, '[%w%p ]*'); -- test for values that are simple ASCII text and bypass other tests if true if capture == v then -- if same there are no Unicode characters return; end for _, invisible_char in ipairs (cfg.invisible_chars) do local char_name = invisible_char[1]; -- the character or group name local pattern = invisible_char[2]; -- the pattern used to find it position, _, capture = mw.ustring.find (v, pattern); -- see if the parameter value contains characters that match the pattern if position and (cfg.invisible_defs.zwj == capture) then -- if we found a zero-width joiner character if mw.ustring.find (v, cfg.indic_script) then -- it's ok if one of the Indic scripts position = nil; -- unset position elseif cfg.emoji_t[mw.ustring.codepoint (v, position+1)] then -- is zwj followed by a character listed in emoji{}? position = nil; -- unset position end end if position then if 'nowiki' == capture or 'math' == capture or -- nowiki and math stripmarkers (not an error condition) ('templatestyles' == capture and utilities.in_array (param, {'id', 'quote'})) then -- templatestyles stripmarker allowed in these parameters stripmarker = true; -- set a flag elseif true == stripmarker and cfg.invisible_defs.del == capture then -- because stripmakers begin and end with the delete char, assume that we've found one end of a stripmarker position = nil; -- unset; for now, ignore linter warning else local err_msg; if capture and not (cfg.invisible_defs.del == capture or cfg.invisible_defs.zwj == capture) then err_msg = utilities.substitute (cfg.messages.invisible_1, {capture, char_name}); -- <capture> here is stripmarker name else err_msg = utilities.substitute (cfg.messages.invisible_2, char_name); end utilities.set_message ('err_invisible_char', {err_msg, utilities.wrap_style ('parameter', param), position}); -- add error message return; -- and done with this parameter end end end end --[[-------------------< A R G U M E N T _ W R A P P E R >---------------------- Argument wrapper. This function provides support for argument mapping defined in the configuration file so that multiple names can be transparently aliased to single internal variable. ]] local function argument_wrapper ( args ) local origin = {}; return setmetatable({ ORIGIN = function ( self, k ) local dummy = self[k]; -- force the variable to be loaded; for now, ignore linter warning return origin[k]; end }, { __index = function ( tbl, k ) if origin[k] ~= nil then return nil; end local v; local list = cfg.aliases[k]; if type( list ) == 'table' then v, origin[k] = utilities.select_one ( args, list, 'err_redundant_parameters' ); if origin[k] == nil then origin[k] = ''; -- Empty string, not nil end elseif list ~= nil then v, origin[k] = args[list], list; else -- maybe let through instead of raising an error? -- v, origin[k] = args[k], k; error( cfg.messages['unknown_argument_map'] .. ': ' .. k); end -- Empty strings, not nil; if v == nil then v = ''; origin[k] = ''; end -- tbl = rawset( tbl, k, v ); rawset( tbl, k, v ); return v; end, }); end --[[--------------------------< N O W R A P _ D A T E >------------------------- When date is YYYY-MM-DD format wrap in nowrap span: <span ...>YYYY-MM-DD</span>. When date is DD MMMM YYYY or is MMMM DD, YYYY then wrap in nowrap span: <span ...>DD MMMM</span> YYYY or <span ...>MMMM DD,</span> YYYY DOES NOT yet support MMMM YYYY or any of the date ranges. ]] local function nowrap_date (date) local cap; local cap2; if date:match("^%d%d%d%d%-%d%d%-%d%d$") then date = utilities.substitute (cfg.presentation['nowrap1'], date); elseif date:match("^%a+%s*%d%d?,%s+%d%d%d%d$") or date:match ("^%d%d?%s*%a+%s+%d%d%d%d$") then cap, cap2 = string.match (date, "^(.*)%s+(%d%d%d%d)$"); date = utilities.substitute (cfg.presentation['nowrap2'], {cap, cap2}); end return date; end --[[--------------------------< S E T _ T I T L E T Y P E >--------------------- This function sets default title types (equivalent to the citation including |type=<default value>) for those templates that have defaults. Also handles the special case where it is desirable to omit the title type from the rendered citation (|type=none). ]] local function set_titletype (cite_class, title_type) if utilities.is_set (title_type) then if 'none' == cfg.keywords_xlate[title_type] then title_type = ''; -- if |type=none then type parameter not displayed end return title_type; -- if |type= has been set to any other value use that value end return cfg.title_types [cite_class] or ''; -- set template's default title type; else empty string for concatenation end --[[--------------------------< S A F E _ J O I N >----------------------------- Joins a sequence of strings together while checking for duplicate separation characters. ]] local function safe_join( tbl, duplicate_char ) local f = {}; -- create a function table appropriate to type of 'duplicate character' if 1 == #duplicate_char then -- for single byte ASCII characters use the string library functions f.gsub = string.gsub f.match = string.match f.sub = string.sub else -- for multi-byte characters use the ustring library functions f.gsub = mw.ustring.gsub f.match = mw.ustring.match f.sub = mw.ustring.sub end local str = ''; -- the output string for _, value in ipairs( tbl ) do if value == nil then value = ''; end if str == '' then -- if output string is empty str = value; -- assign value to it (first time through the loop) elseif value ~= '' then local comp; -- what does 'comp' mean? if value:sub(1, 1) == '<' then -- special case of values enclosed in spans and other markup. comp = value:gsub( "%b<>", "" ); -- remove HTML markup (<span>string</span> -> string) else comp = value; end -- typically duplicate_char is sepc if f.sub(comp, 1, 1) == duplicate_char then -- is first character same as duplicate_char? why test first character? -- Because individual string segments often (always?) begin with terminal punct for the -- preceding segment: 'First element' .. 'sepc next element' .. etc.? local trim = false; local end_chr = f.sub(str, -1, -1); -- get the last character of the output string -- str = str .. "<HERE(enchr=" .. end_chr .. ")" -- debug stuff? if end_chr == duplicate_char then -- if same as separator str = f.sub(str, 1, -2); -- remove it elseif end_chr == "'" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "''" then -- if last three chars of str are sepc'' str = f.sub(str, 1, -4) .. "''"; -- remove them and add back '' elseif f.sub(str, -5, -1) == duplicate_char .. "]]''" then -- if last five chars of str are sepc]]'' trim = true; -- why? why do this and next differently from previous? elseif f.sub(str, -4, -1) == duplicate_char .. "]''" then -- if last four chars of str are sepc]'' trim = true; -- same question end elseif end_chr == "]" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "]]" then -- if last three chars of str are sepc]] wikilink trim = true; elseif f.sub(str, -3, -1) == duplicate_char .. '"]' then -- if last three chars of str are sepc"] quoted external link trim = true; elseif f.sub(str, -2, -1) == duplicate_char .. "]" then -- if last two chars of str are sepc] external link trim = true; elseif f.sub(str, -4, -1) == duplicate_char .. "'']" then -- normal case when |url=something & |title=Title. trim = true; end elseif end_chr == " " then -- if last char of output string is a space if f.sub(str, -2, -1) == duplicate_char .. " " then -- if last two chars of str are <sepc><space> str = f.sub(str, 1, -3); -- remove them both end end if trim then if value ~= comp then -- value does not equal comp when value contains HTML markup local dup2 = duplicate_char; if f.match(dup2, "%A" ) then dup2 = "%" .. dup2; end -- if duplicate_char not a letter then escape it value = f.gsub(value, "(%b<>)" .. dup2, "%1", 1 ) -- remove duplicate_char if it follows HTML markup else value = f.sub(value, 2, -1 ); -- remove duplicate_char when it is first character end end end str = str .. value; -- add it to the output string end end return str; end --[[--------------------------< I S _ S U F F I X >----------------------------- returns true if suffix is properly formed Jr, Sr, or ordinal in the range 1–9. Puncutation not allowed. ]] local function is_suffix (suffix) if utilities.in_array (suffix, {'Jr', 'Sr', 'Jnr', 'Snr', '1st', '2nd', '3rd'}) or suffix:match ('^%dth$') then return true; end return false; end --[[--------------------< I S _ G O O D _ V A N C _ N A M E >------------------- For Vancouver style, author/editor names are supposed to be rendered in Latin (read ASCII) characters. When a name uses characters that contain diacritical marks, those characters are to be converted to the corresponding Latin character. When a name is written using a non-Latin alphabet or logogram, that name is to be transliterated into Latin characters. The module doesn't do this so editors may/must. This test allows |first= and |last= names to contain any of the letters defined in the four Unicode Latin character sets [http://www.unicode.org/charts/PDF/U0000.pdf C0 Controls and Basic Latin] 0041–005A, 0061–007A [http://www.unicode.org/charts/PDF/U0080.pdf C1 Controls and Latin-1 Supplement] 00C0–00D6, 00D8–00F6, 00F8–00FF [http://www.unicode.org/charts/PDF/U0100.pdf Latin Extended-A] 0100–017F [http://www.unicode.org/charts/PDF/U0180.pdf Latin Extended-B] 0180–01BF, 01C4–024F |lastn= also allowed to contain hyphens, spaces, and apostrophes. (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) |firstn= also allowed to contain hyphens, spaces, apostrophes, and periods This original test: if nil == mw.ustring.find (last, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%'%.]+[2-6%a]*$") then was written outside of the code editor and pasted here because the code editor gets confused between character insertion point and cursor position. The test has been rewritten to use decimal character escape sequence for the individual bytes of the Unicode characters so that it is not necessary to use an external editor to maintain this code. \195\128-\195\150 – À-Ö (U+00C0–U+00D6 – C0 controls) \195\152-\195\182 – Ø-ö (U+00D8-U+00F6 – C0 controls) \195\184-\198\191 – ø-ƿ (U+00F8-U+01BF – C0 controls, Latin extended A & B) \199\132-\201\143 – DŽ-ɏ (U+01C4-U+024F – Latin extended B) ]] local function is_good_vanc_name (last, first, suffix, position) if not suffix then if first:find ('[,%s]') then -- when there is a space or comma, might be first name/initials + generational suffix first = first:match ('(.-)[,%s]+'); -- get name/initials suffix = first:match ('[,%s]+(.+)$'); -- get generational suffix end end if utilities.is_set (suffix) then if not is_suffix (suffix) then add_vanc_error (cfg.err_msg_supl.suffix, position); return false; -- not a name with an appropriate suffix end end if nil == mw.ustring.find (last, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%'%.]*$") then add_vanc_error (cfg.err_msg_supl['non-Latin char'], position); return false; -- not a string of Latin characters; Vancouver requires Romanization end; return true; end --[[--------------------------< R E D U C E _ T O _ I N I T I A L S >------------------------------------------ Attempts to convert names to initials in support of |name-list-style=vanc. Names in |firstn= may be separated by spaces or hyphens, or for initials, a period. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35062/. Vancouver style requires family rank designations (Jr, II, III, etc.) to be rendered as Jr, 2nd, 3rd, etc. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35085/. This code only accepts and understands generational suffix in the Vancouver format because Roman numerals look like, and can be mistaken for, initials. This function uses ustring functions because firstname initials may be any of the Unicode Latin characters accepted by is_good_vanc_name (). ]] local function reduce_to_initials (first, position) if first:find (',', 1, true) then return first; -- commas not allowed; abandon end local name, suffix = mw.ustring.match (first, "^(%u+) ([%dJS][%drndth]+)$"); if not name then -- if not initials and a suffix name = mw.ustring.match (first, "^(%u+)$"); -- is it just initials? end if name then -- if first is initials with or without suffix if 3 > mw.ustring.len (name) then -- if one or two initials if suffix then -- if there is a suffix if is_suffix (suffix) then -- is it legitimate? return first; -- one or two initials and a valid suffix so nothing to do else add_vanc_error (cfg.err_msg_supl.suffix, position); -- one or two initials with invalid suffix so error message return first; -- and return first unmolested end else return first; -- one or two initials without suffix; nothing to do end end end -- if here then name has 3 or more uppercase letters so treat them as a word local initials_t = {}; -- table to hold initials local i = 1; -- counter for number of initials local names_t = mw.text.split (first, '[%s%-]+'); -- split into a sequence of names and possible suffix while names_t[i] do -- loop through the sequence if 1 < i and names_t[i]:match ('[%dJS][%drndth]+%.?$') then -- if not the first name, and looks like a suffix (may have trailing dot) names_t[i] = names_t[i]:gsub ('%.', ''); -- remove terminal dot if present if is_suffix (names_t[i]) then -- if a legitimate suffix table.insert (initials_t, ' ' .. names_t[i]); -- add a separator space, insert at end of initials sequence break; -- and done because suffix must fall at the end of a name end -- no error message if not a suffix; possibly because of Romanization end if 3 > i then table.insert (initials_t, mw.ustring.sub (names_t[i], 1, 1)); -- insert the initial at end of initials sequence end i = i + 1; -- bump the counter end return table.concat (initials_t); -- Vancouver format does not include spaces. end --[[--------------------------< I N T E R W I K I _ P R E F I X E N _ G E T >---------------------------------- extract interwiki prefixen from <value>. Returns two one or two values: false – no prefixen nil – prefix exists but not recognized project prefix, language prefix – when value has either of: :<project>:<language>:<article> :<language>:<project>:<article> project prefix, nil – when <value> has only a known single-letter prefix nil, language prefix – when <value> has only a known language prefix accepts single-letter project prefixen: 'd' (wikidata), 's' (wikisource), and 'w' (wikipedia) prefixes; at this writing, the other single-letter prefixen (b (wikibook), c (commons), m (meta), n (wikinews), q (wikiquote), and v (wikiversity)) are not supported. ]] local function interwiki_prefixen_get (value, is_link) if not value:find (':%l+:') then -- if no prefix return false; -- abandon; boolean here to distinguish from nil fail returns later end local prefix_patterns_linked_t = { -- sequence of valid interwiki and inter project prefixen '^%[%[:([dsw]):(%l%l+):', -- wikilinked; project and language prefixes '^%[%[:(%l%l+):([dsw]):', -- wikilinked; language and project prefixes '^%[%[:([dsw]):', -- wikilinked; project prefix '^%[%[:(%l%l+):', -- wikilinked; language prefix } local prefix_patterns_unlinked_t = { -- sequence of valid interwiki and inter project prefixen '^:([dsw]):(%l%l+):', -- project and language prefixes '^:(%l%l+):([dsw]):', -- language and project prefixes '^:([dsw]):', -- project prefix '^:(%l%l+):', -- language prefix } local cap1, cap2; for _, pattern in ipairs ((is_link and prefix_patterns_linked_t) or prefix_patterns_unlinked_t) do cap1, cap2 = value:match (pattern); if cap1 then break; -- found a match so stop looking end end if cap1 and cap2 then -- when both then :project:language: or :language:project: (both forms allowed) if 1 == #cap1 then -- length == 1 then :project:language: if cfg.inter_wiki_map[cap2] then -- is language prefix in the interwiki map? return cap1, cap2; -- return interwiki project and interwiki language end else -- here when :language:project: if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return cap2, cap1; -- return interwiki project and interwiki language end end return nil; -- unknown interwiki language elseif not (cap1 or cap2) then -- both are nil? return nil; -- we got something that looks like a project prefix but isn't; return fail elseif 1 == #cap1 then -- here when one capture return cap1, nil; -- length is 1 so return project, nil language else -- here when one capture and its length it more than 1 if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return nil, cap1; -- return nil project, language end end end --[[--------------------------< L I S T _ P E O P L E >-------------------------- Formats a list of people (authors, contributors, editors, interviewers, translators) names in the list will be linked when |<name>-link= has a value |<name>-mask- does NOT have a value; masked names are presumed to have been rendered previously so should have been linked there when |<name>-mask=0, the associated name is not rendered ]] local function list_people (control, people, etal) local sep; local namesep; local format = control.format; local maximum = control.maximum; local name_list = {}; if 'vanc' == format then -- Vancouver-like name styling? sep = cfg.presentation['sep_nl_vanc']; -- name-list separator between names is a comma namesep = cfg.presentation['sep_name_vanc']; -- last/first separator is a space else sep = cfg.presentation['sep_nl']; -- name-list separator between names is a semicolon namesep = cfg.presentation['sep_name']; -- last/first separator is <comma><space> end if sep:sub (-1, -1) ~= " " then sep = sep .. " " end if utilities.is_set (maximum) and maximum < 1 then return "", 0; end -- returned 0 is for EditorCount; not used for other names for i, person in ipairs (people) do if utilities.is_set (person.last) then local mask = person.mask; local one; local sep_one = sep; if utilities.is_set (maximum) and i > maximum then etal = true; break; end if mask then local n = tonumber (mask); -- convert to a number if it can be converted; nil else if n then one = 0 ~= n and string.rep("&mdash;", n) or nil; -- make a string of (n > 0) mdashes, nil else, to replace name person.link = nil; -- don't create link to name if name is replaces with mdash string or has been set nil else one = mask; -- replace name with mask text (must include name-list separator) sep_one = " "; -- modify name-list separator end else one = person.last; -- get surname local first = person.first -- get given name if utilities.is_set (first) then if ("vanc" == format) then -- if Vancouver format one = one:gsub ('%.', ''); -- remove periods from surnames (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) if not person.corporate and is_good_vanc_name (one, first, nil, i) then -- and name is all Latin characters; corporate authors not tested first = reduce_to_initials (first, i); -- attempt to convert first name(s) to initials end end one = one .. namesep .. first; end end if utilities.is_set (person.link) then one = utilities.make_wikilink (person.link, one); -- link author/editor end if one then -- if <one> has a value (name, mdash replacement, or mask text replacement) local proj, tag = interwiki_prefixen_get (one, true); -- get the interwiki prefixen if present if 'w' == proj and ('Wikipedia' == mw.site.namespaces.Project['name']) then proj = nil; -- for stuff like :w:de:<article>, :w is unnecessary TODO: maint cat? end if proj then local proj_name = ({['d'] = cfg.messages.wikidata, ['s'] = cfg.messages.wikisource, ['w'] = cfg.messages.wikipedia})[proj]; -- :w (wikipedia) for linking from a non-wikipedia project if proj_name then one = one .. utilities.wrap_style ('interproj', proj_name); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interproj-linked-name', proj); -- categorize it; <proj> is sort key tag = nil; -- unset; don't do both project and language end end if tag == cfg.this_wiki_code then tag = nil; -- stuff like :en:<article> at en.wiki is pointless TODO: maint cat? end if tag then local lang = cfg.lang_tag_remap[tag] or cfg.mw_languages_by_tag_t[tag]; if lang then -- error messaging done in extract_names() where we know parameter names one = one .. utilities.wrap_style ('interwiki', lang); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interwiki-linked-name', tag); -- categorize it; <tag> is sort key end end table.insert (name_list, one); -- add it to the list of names table.insert (name_list, sep_one); -- add the proper name-list separator end end end local count = #name_list / 2; -- (number of names + number of separators) divided by 2 if 0 < count then if 1 < count and not etal then if 'amp' == format then name_list[#name_list-2] = " & "; -- replace last separator with ampersand text elseif 'and' == format then if 2 == count then name_list[#name_list-2] = cfg.presentation.sep_nl_and; -- replace last separator with 'and' text else name_list[#name_list-2] = cfg.presentation.sep_nl_end; -- replace last separator with '(sep) and' text end end end name_list[#name_list] = nil; -- erase the last separator end local result = table.concat (name_list); -- construct list if etal and utilities.is_set (result) then -- etal may be set by |display-authors=etal but we might not have a last-first list result = result .. sep .. cfg.messages['et al']; -- we've got a last-first list and etal so add et al. end return result, count; -- return name-list string and count of number of names (count used for editor names only) end --[[--------------------< M A K E _ C I T E R E F _ I D >----------------------- Generates a CITEREF anchor ID if we have at least one name or a date. Otherwise returns an empty string. namelist is one of the contributor-, author-, or editor-name lists chosen in that order. year is Year or anchor_year. ]] local function make_citeref_id (namelist, year) local names={}; -- a table for the one to four names and year for i,v in ipairs (namelist) do -- loop through the list and take up to the first four last names names[i] = v.last if i == 4 then break end -- if four then done end table.insert (names, year); -- add the year at the end local id = table.concat(names); -- concatenate names and year for CITEREF id if utilities.is_set (id) then -- if concatenation is not an empty string return "CITEREF" .. id; -- add the CITEREF portion else return ''; -- return an empty string; no reason to include CITEREF id in this citation end end --[[--------------------------< C I T E _ C L A S S _A T T R I B U T E _M A K E >------------------------------ construct <cite> tag class attribute for this citation. <cite_class> – config.CitationClass from calling template <mode> – value from |mode= parameter ]] local function cite_class_attribute_make (cite_class, mode) local class_t = {}; table.insert (class_t, 'citation'); -- required for blue highlight if 'citation' ~= cite_class then table.insert (class_t, cite_class); -- identify this template for user css table.insert (class_t, utilities.is_set (mode) and mode or 'cs1'); -- identify the citation style for user css or javascript else table.insert (class_t, utilities.is_set (mode) and mode or 'cs2'); -- identify the citation style for user css or javascript end for _, prop_key in ipairs (z.prop_keys_t) do table.insert (class_t, prop_key); -- identify various properties for user css or javascript end return table.concat (class_t, ' '); -- make a big string and done end --[[---------------------< N A M E _ H A S _ E T A L >-------------------------- Evaluates the content of name parameters (author, editor, etc.) for variations on the theme of et al. If found, the et al. is removed, a flag is set to true and the function returns the modified name and the flag. This function never sets the flag to false but returns its previous state because it may have been set by previous passes through this function or by the associated |display-<names>=etal parameter ]] local function name_has_etal (name, etal, nocat, param) if utilities.is_set (name) then -- name can be nil in which case just return local patterns = cfg.et_al_patterns; -- get patterns from configuration for _, pattern in ipairs (patterns) do -- loop through all of the patterns if name:match (pattern) then -- if this 'et al' pattern is found in name name = name:gsub (pattern, ''); -- remove the offending text etal = true; -- set flag (may have been set previously here or by |display-<names>=etal) if not nocat then -- no categorization for |vauthors= utilities.set_message ('err_etal', {param}); -- and set an error if not added end end end end return name, etal; end --[[---------------------< N A M E _ I S _ N U M E R I C >---------------------- Add an error message and category when <name> parameter value does not contain letters. Add a maintenance category when <name> parameter value has numeric characters mixed with characters that are not numeric characters; could be letters and/or punctuation characters. This function will only emit one error and one maint message for the current template. Does not emit both error and maint messages/categories for the same parameter value. returns nothing ]] local function name_is_numeric (name, name_alias, list_name) local patterns = { '^%D+%d', -- <name> must have digits preceded by other characters '^%D*%d+%D+', -- <name> must have digits followed by other characters } if not added_numeric_name_errs and mw.ustring.match (name, '^[%A]+$') then -- if we have not already set an error message and <name> does not have any alpha characters utilities.set_message ('err_numeric_names', name_alias); -- add an error message added_numeric_name_errs = true; -- set the flag so we emit only one error message return; -- when here no point in further testing; abandon end if not added_numeric_name_maint then -- if we have already set a maint message for _, pattern in ipairs (patterns) do -- spin through list of patterns if mw.ustring.match (name, pattern) then -- digits preceded or followed by anything but digits; %D+ includes punctuation utilities.set_message ('maint_numeric_names', cfg.special_case_translation [list_name]); -- add a maint cat for this template added_numeric_name_maint = true; -- set the flag so we emit only one maint message return; -- when here no point in further testing; abandon end end end end --[[-----------------< N A M E _ H A S _ M U L T _ N A M E S >------------------ Evaluates the content of last/surname (authors etc.) parameters for multiple names. Multiple names are indicated if there is more than one comma or any "unescaped" semicolons. Escaped semicolons are ones used as part of selected HTML entities. If the condition is met, the function adds the multiple name maintenance category. Same test for first except that commas should not appear in given names (MOS:JR says that the generational suffix does not take a separator character). Titles, degrees, postnominals, affiliations, all normally comma separated don't belong in a citation. <name> – name parameter value <list_name> – AuthorList, EditorList, etc <limit> – number of allowed commas; 1 (default) for surnames; 0 for given names returns nothing ]] local function name_has_mult_names (name, list_name, limit) local _, commas, semicolons, nbsps; limit = limit and limit or 1; if utilities.is_set (name) then _, commas = name:gsub (',', ''); -- count the number of commas _, semicolons = name:gsub (';', ''); -- count the number of semicolons -- nbsps probably should be its own separate count rather than merged in -- some way with semicolons because Lua patterns do not support the -- grouping operator that regex does, which means there is no way to add -- more entities to escape except by adding more counts with the new -- entities _, nbsps = name:gsub ('&nbsp;',''); -- count nbsps -- There is exactly 1 semicolon per &nbsp; entity, so subtract nbsps -- from semicolons to 'escape' them. If additional entities are added, -- they also can be subtracted. if limit < commas or 0 < (semicolons - nbsps) then utilities.set_message ('maint_mult_names', cfg.special_case_translation [list_name]); -- add a maint message end end end --[=[-------------------------< I S _ G E N E R I C >---------------------------------------------------------- Compares values assigned to various parameters according to the string provided as <item> in the function call. <item> can have on of two values: 'generic_names' – for name-holding parameters: |last=, |first=, |editor-last=, etc 'generic_titles' – for |title= There are two types of generic tests. The 'accept' tests look for a pattern that should not be rejected by the 'reject' test. For example, |author=[[John Smith (author)|Smith, John]] would be rejected by the 'author' reject test. But piped wikilinks with 'author' disambiguation should not be rejected so the 'accept' test prevents that from happening. Accept tests are always performed before reject tests. Each of the 'accept' and 'reject' sequence tables hold tables for en.wiki (['en']) and local.wiki (['local']) that each can hold a test sequence table The sequence table holds, at index [1], a test pattern, and, at index [2], a boolean control value. The control value tells string.find() or mw.ustring.find() to do plain-text search (true) or a pattern search (false). The intent of all this complexity is to make these searches as fast as possible so that we don't run out of processing time on very large articles. Returns true when a reject test finds the pattern or string false when an accept test finds the pattern or string nil else ]=] local function is_generic (item, value) local str_lower = { -- use string.lower() for en.wiki (['en']) and use mw.ustring.lower() or local.wiki (['local']) ['en'] = string.lower, ['local'] = mw.ustring.lower, } local str_find = { -- use string.find() for en.wiki (['en']) and use mw.ustring.find() or local.wiki (['local']) ['en'] = string.find, ['local'] = mw.ustring.find, } local function test (val, test_t, wiki) -- local function to do the testing; <wiki> selects lower() and find() functions val = test_t[2] and str_lower[wiki](value) or val; -- when <test_t[2]> set to 'true', plaintext search using lowercase value return str_find[wiki] (val, test_t[1], 1, test_t[2]); -- return nil when not found or matched end local test_types_t = {'accept', 'reject'}; -- test accept patterns first, then reject patterns local wikis_t = {'en', 'local'}; -- do tests for each of these keys; en.wiki first, local.wiki second for _, test_type in ipairs (test_types_t) do -- for each test type for _, generic_value in pairs (cfg.special_case_translation[item][test_type]) do -- spin through the list of generic value fragments to accept or reject for _, wiki in ipairs (wikis_t) do if generic_value[wiki] then if test (value, generic_value[wiki], wiki) then -- go do the test return ('reject' == test_type); -- param value rejected, return true; false else end end end end end end --[[--------------------------< N A M E _ I S _ G E N E R I C >------------------------------------------------ calls is_generic() to determine if <name> is a 'generic name' listed in cfg.generic_names; <name_alias> is the parameter name used in error messaging ]] local function name_is_generic (name, name_alias) if not added_generic_name_errs and is_generic ('generic_names', name) then utilities.set_message ('err_generic_name', name_alias); -- set an error message added_generic_name_errs = true; end end --[[--------------------------< N A M E _ C H E C K S >-------------------------------------------------------- This function calls various name checking functions used to validate the content of the various name-holding parameters. ]] local function name_checks (last, first, list_name, last_alias, first_alias) local accept_name; if utilities.is_set (last) then last, accept_name = utilities.has_accept_as_written (last); -- remove accept-this-as-written markup when it wraps all of <last> if not accept_name then -- <last> not wrapped in accept-as-written markup name_has_mult_names (last, list_name); -- check for multiple names in the parameter name_is_numeric (last, last_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (last, last_alias); -- check for names found in the generic names list end end if utilities.is_set (first) then first, accept_name = utilities.has_accept_as_written (first); -- remove accept-this-as-written markup when it wraps all of <first> if not accept_name then -- <first> not wrapped in accept-as-written markup name_has_mult_names (first, list_name, 0); -- check for multiple names in the parameter; 0 is number of allowed commas in a given name name_is_numeric (first, first_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (first, first_alias); -- check for names found in the generic names list end local wl_type, D = utilities.is_wikilink (first); if 0 ~= wl_type then first = D; utilities.set_message ('err_bad_paramlink', first_alias); end end return last, first; -- done end --[[----------------------< E X T R A C T _ N A M E S >------------------------- Gets name list from the input arguments Searches through args in sequential order to find |lastn= and |firstn= parameters (or their aliases), and their matching link and mask parameters. Stops searching when both |lastn= and |firstn= are not found in args after two sequential attempts: found |last1=, |last2=, and |last3= but doesn't find |last4= and |last5= then the search is done. This function emits an error message when there is a |firstn= without a matching |lastn=. When there are 'holes' in the list of last names, |last1= and |last3= are present but |last2= is missing, an error message is emitted. |lastn= is not required to have a matching |firstn=. When an author or editor parameter contains some form of 'et al.', the 'et al.' is stripped from the parameter and a flag (etal) returned that will cause list_people() to add the static 'et al.' text from Module:Citation/CS1/Configuration. This keeps 'et al.' out of the template's metadata. When this occurs, an error is emitted. ]] local function extract_names(args, list_name) local names = {}; -- table of names local last; -- individual name components local first; local link; local mask; local i = 1; -- loop counter/indexer local n = 1; -- output table indexer local count = 0; -- used to count the number of times we haven't found a |last= (or alias for authors, |editor-last or alias for editors) local etal = false; -- return value set to true when we find some form of et al. in an author parameter local last_alias, first_alias, link_alias; -- selected parameter aliases used in error messaging while true do last, last_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'err_redundant_parameters', i ); -- search through args for name components beginning at 1 first, first_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'err_redundant_parameters', i ); link, link_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ); mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); if last then -- error check |lastn= alias for unknown interwiki link prefix; done here because this is where we have the parameter name local project, language = interwiki_prefixen_get (last, true); -- true because we expect interwiki links in |lastn= to be wikilinked if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', last_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? last = utilities.remove_wiki_link (last); -- remove wikilink markup; show display value only end end if link then -- error check |linkn= alias for unknown interwiki link prefix local project, language = interwiki_prefixen_get (link, false); -- false because wiki links in |author-linkn= is an error if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', link_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? link = nil; -- unset so we don't link link_alias = nil; end end last, etal = name_has_etal (last, etal, false, last_alias); -- find and remove variations on et al. first, etal = name_has_etal (first, etal, false, first_alias); -- find and remove variations on et al. last, first = name_checks (last, first, list_name, last_alias, first_alias); -- multiple names, extraneous annotation, etc. checks if first and not last then -- if there is a firstn without a matching lastn local alias = first_alias:find ('given', 1, true) and 'given' or 'first'; -- get first or given form of the alias utilities.set_message ('err_first_missing_last', { first_alias, -- param name of alias missing its mate first_alias:gsub (alias, {['first'] = 'last', ['given'] = 'surname'}), -- make param name appropriate to the alias form }); -- add this error message elseif not first and not last then -- if both firstn and lastn aren't found, are we done? count = count + 1; -- number of times we haven't found last and first if 2 <= count then -- two missing names and we give up break; -- normal exit or there is a two-name hole in the list; can't tell which end else -- we have last with or without a first link = link_title_ok (link, link_alias, last, last_alias); -- check for improper wiki-markup if first then link = link_title_ok (link, link_alias, first, first_alias); -- check for improper wiki-markup end names[n] = {last = last, first = first, link = link, mask = mask, corporate = false}; -- add this name to our names list (corporate for |vauthors= only) n = n + 1; -- point to next location in the names table if 1 == count then -- if the previous name was missing utilities.set_message ('err_missing_name', {list_name:match ("(%w+)List"):lower(), i - 1}); -- add this error message end count = 0; -- reset the counter, we're looking for two consecutive missing names end i = i + 1; -- point to next args location end return names, etal; -- all done, return our list of names and the etal flag end --[[--------------------------< N A M E _ T A G _ G E T >------------------------------------------------------ attempt to decode |language=<lang_param> and return language name and matching tag; nil else. This function looks for: <lang_param> as a tag in cfg.lang_tag_remap{} <lang_param> as a name in cfg.lang_name_remap{} <lang_param> as a name in cfg.mw_languages_by_name_t <lang_param> as a tag in cfg.mw_languages_by_tag_t when those fail, presume that <lang_param> is an IETF-like tag that MediaWiki does not recognize. Strip all script, region, variant, whatever subtags from <lang_param> to leave just a two or three character language tag and look for the new <lang_param> in cfg.mw_languages_by_tag_t{} on success, returns name (in properly capitalized form) and matching tag (in lowercase); on failure returns nil ]] local function name_tag_get (lang_param) local lang_param_lc = mw.ustring.lower (lang_param); -- use lowercase as an index into the various tables local name; local tag; name = cfg.lang_tag_remap[lang_param_lc]; -- assume <lang_param_lc> is a tag; attempt to get remapped language name if name then -- when <name>, <lang_param> is a tag for a remapped language name if cfg.lang_name_remap[name:lower()][2] ~= lang_param_lc then utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added return name, cfg.lang_name_remap[name:lower()][2]; -- so return name and tag from lang_name_remap[name]; special case to xlate sr-ec and sr-el to sr-cyrl and sr-latn end return name, lang_param_lc; -- so return <name> from remap and <lang_param_lc> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- still assuming that <lang_param_lc> is a tag; strip script, region, variant subtags name = cfg.lang_tag_remap[tag]; -- attempt to get remapped language name with language subtag only if name then -- when <name>, <tag> is a tag for a remapped language name return name, tag; -- so return <name> from remap and <tag> end if cfg.lang_name_remap[lang_param_lc] then -- not a remapped tag, assume <lang_param_lc> is a name; attempt to get remapped language tag return cfg.lang_name_remap[lang_param_lc][1], cfg.lang_name_remap[lang_param_lc][2]; -- for this <lang_param_lc>, return a (possibly) new name and appropriate tag end name = cfg.mw_languages_by_tag_t[lang_param_lc]; -- assume that <lang_param_lc> is a tag; attempt to get its matching language name if name then return name, lang_param_lc; -- <lang_param_lc> is a tag so return it and <name> end tag = cfg.mw_languages_by_name_t[lang_param_lc]; -- assume that <lang_param_lc> is a language name; attempt to get its matching tag if tag then return cfg.mw_languages_by_tag_t[tag], tag; -- <lang_param_lc> is a name so return the name from the table and <tag> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- is <lang_param_lc> an IETF-like tag that MediaWiki doesn't recognize? <tag> gets the language subtag; nil else if tag then name = cfg.mw_languages_by_tag_t[tag]; -- attempt to get a language name using the shortened <tag> if name then return name, tag; -- <lang_param_lc> is an unrecognized IETF-like tag so return <name> and language subtag end end end --[[-------------------< L A N G U A G E _ P A R A M E T E R >------------------ Gets language name from a provided two- or three-character ISO 639 code. If a code is recognized by MediaWiki, use the returned name; if not, then use the value that was provided with the language parameter. When |language= contains a recognized language (either code or name), the page is assigned to the category for that code: Category:Norwegian-language sources (no). For valid three-character code languages, the page is assigned to the single category for '639-2' codes: Category:CS1 ISO 639-2 language sources. Languages that are the same as the local wiki are not categorized. MediaWiki does not recognize three-character equivalents of two-character codes: code 'ar' is recognized but code 'ara' is not. This function supports multiple languages in the form |language=nb, French, th where the language names or codes are separated from each other by commas with optional space characters. ]] local function language_parameter (lang) local tag; -- some form of IETF-like language tag; language subtag with optional region, sript, vatiant, etc subtags local lang_subtag; -- ve populates |language= with mostly unecessary region subtags that MediaWiki does not recognize; this is the base language subtag local name; -- the language name local language_list = {}; -- table of language names to be rendered local names_t = mw.text.split (lang, '%s*,%s*'); -- names should be a comma separated list for _, lang in ipairs (names_t) do -- reuse lang here because we don't yet know if lang is a language name or a language tag; for now, ignore linter warning name, tag = name_tag_get (lang); -- attempt to get name/tag pair for <lang>; <name> has proper capitalization; <tag> is lowercase if utilities.is_set (tag) then lang_subtag = tag:gsub ('^(%a%a%a?)%-.*', '%1'); -- for categorization, strip any IETF-like tags from language tag if cfg.this_wiki_code ~= lang_subtag then -- when the language is not the same as this wiki's language if 2 == lang_subtag:len() then -- and is a two-character tag utilities.add_prop_cat ('foreign-lang-source', {name, tag}, lang_subtag); -- categorize it; tag appended to allow for multiple language categorization else -- or is a recognized language (but has a three-character tag) utilities.add_prop_cat ('foreign-lang-source-2', {lang_subtag}, lang_subtag); -- categorize it differently TODO: support multiple three-character tag categories per cs1|2 template? end elseif cfg.local_lang_cat_enable then -- when the language and this wiki's language are the same and categorization is enabled utilities.add_prop_cat ('local-lang-source', {name, lang_subtag}); -- categorize it end else name = lang; -- return whatever <lang> has so that we show something utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added end table.insert (language_list, name); end name = utilities.make_sep_list (#language_list, language_list); if (1 == #language_list) and (lang_subtag == cfg.this_wiki_code) then -- when only one language, find lang name in this wiki lang name; for |language=en-us, 'English' in 'American English' return ''; -- if one language and that language is this wiki's return an empty string (no annotation) end return (" " .. wrap_msg ('language', name)); -- otherwise wrap with '(in ...)' --[[ TODO: should only return blank or name rather than full list so we can clean up the bunched parenthetical elements Language, Type, Format ]] end --[[-----------------------< S E T _ C S _ S T Y L E >-------------------------- Gets the default CS style configuration for the given mode. Returns default separator and either postscript as passed in or the default. In CS1, the default postscript and separator are '.'. In CS2, the default postscript is the empty string and the default separator is ','. ]] local function set_cs_style (postscript, mode) if utilities.is_set(postscript) then -- emit a maintenance message if user postscript is the default cs1 postscript -- we catch the opposite case for cs2 in set_style if mode == 'cs1' and postscript == cfg.presentation['ps_' .. mode] then utilities.set_message ('maint_postscript'); end else postscript = cfg.presentation['ps_' .. mode]; end return cfg.presentation['sep_' .. mode], postscript; end --[[--------------------------< S E T _ S T Y L E >----------------------------- Sets the separator and postscript styles. Checks the |mode= first and the #invoke CitationClass second. Removes the postscript if postscript == none. ]] local function set_style (mode, postscript, cite_class) local sep; if 'cs2' == mode then sep, postscript = set_cs_style (postscript, 'cs2'); elseif 'cs1' == mode then sep, postscript = set_cs_style (postscript, 'cs1'); elseif 'citation' == cite_class then sep, postscript = set_cs_style (postscript, 'cs2'); else sep, postscript = set_cs_style (postscript, 'cs1'); end if cfg.keywords_xlate[postscript:lower()] == 'none' then -- emit a maintenance message if user postscript is the default cs2 postscript -- we catch the opposite case for cs1 in set_cs_style if 'cs2' == mode or ('cs1' ~= mode and 'citation' == cite_class) then -- {{citation |title=Title |mode=cs1 |postscript=none}} should not emit maint message utilities.set_message ('maint_postscript'); end postscript = ''; end return sep, postscript end --[=[-------------------------< I S _ P D F >----------------------------------- Determines if a URL has the file extension that is one of the PDF file extensions used by [[MediaWiki:Common.css]] when applying the PDF icon to external links. returns true if file extension is one of the recognized extensions, else false ]=] local function is_pdf (url) return url:match ('%.pdf$') or url:match ('%.PDF$') or url:match ('%.pdf[%?#]') or url:match ('%.PDF[%?#]') or url:match ('%.PDF&#035') or url:match ('%.pdf&#035'); end --[[--------------------------< S T Y L E _ F O R M A T >----------------------- Applies CSS style to |format=, |chapter-format=, etc. Also emits an error message if the format parameter does not have a matching URL parameter. If the format parameter is not set and the URL contains a file extension that is recognized as a PDF document by MediaWiki's commons.css, this code will set the format parameter to (PDF) with the appropriate styling. ]] local function style_format (format, url, fmt_param, url_param) if utilities.is_set (format) then format = utilities.wrap_style ('format', format); -- add leading space, parentheses, resize if not utilities.is_set (url) then utilities.set_message ('err_format_missing_url', {fmt_param, url_param}); -- add an error message end elseif is_pdf (url) then -- format is not set so if URL is a PDF file then format = utilities.wrap_style ('format', 'PDF'); -- set format to PDF else format = ''; -- empty string for concatenation end return format; end --[[---------------------< G E T _ D I S P L A Y _ N A M E S >------------------ Returns a number that defines the number of names displayed for author and editor name lists and a Boolean flag to indicate when et al. should be appended to the name list. When the value assigned to |display-xxxxors= is a number greater than or equal to zero, return the number and the previous state of the 'etal' flag (false by default but may have been set to true if the name list contains some variant of the text 'et al.'). When the value assigned to |display-xxxxors= is the keyword 'etal', return a number that is one greater than the number of authors in the list and set the 'etal' flag true. This will cause the list_people() to display all of the names in the name list followed by 'et al.' In all other cases, returns nil and the previous state of the 'etal' flag. inputs: max: A['DisplayAuthors'] or A['DisplayEditors'], etc; a number or some flavor of etal count: #a or #e list_name: 'authors' or 'editors' etal: author_etal or editor_etal This function sets an error message when |display-xxxxors= value greater than or equal to number of names but not when <max> comes from {{cs1 config}} global settings. When using global settings, <param> is set to the keyword 'cs1 config' which is used to supress the normal error. Error is suppressed because it is to be expected that some citations in an article will have the same or fewer names that the limit specified in {{cs1 config}}. ]] local function get_display_names (max, count, etal, param) if utilities.is_set (max) then if 'etal' == cfg.keywords_xlate[max:lower():gsub("[ '%.]", '')] then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings max = count + 1; -- number of authors + 1 so display all author name plus et al. etal = true; -- overrides value set by extract_names() elseif max:match ('^%d+$') then -- if is a string of numbers max = tonumber (max); -- make it a number if (max >= count) and ('cs1 config' ~= param) then -- error when local |display-xxxxors= value greater than or equal to number of names; not an error when using global setting utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; end else -- not a valid keyword or number utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; -- unset; as if |display-xxxxors= had not been set end end return max, etal; end --[[----------< E X T R A _ T E X T _ I N _ P A G E _ C H E C K >--------------- Adds error if |page=, |pages=, |quote-page=, |quote-pages= has what appears to be some form of p. or pp. abbreviation in the first characters of the parameter content. check page for extraneous p, p., pp, pp., pg, pg. at start of parameter value: good pattern: '^P[^%.P%l]' matches when page begins PX or P# but not Px where x and X are letters and # is a digit bad pattern: '^[Pp][PpGg]' matches when page begins pp, pP, Pp, PP, pg, pG, Pg, PG ]] local function extra_text_in_page_check (val, name) if not val:match (cfg.vol_iss_pg_patterns.good_ppattern) then for _, pattern in ipairs (cfg.vol_iss_pg_patterns.bad_ppatterns) do -- spin through the selected sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message ('err_extra_text_pages', name); -- add error message return; -- and done end end end end --[[--------------------------< E X T R A _ T E X T _ I N _ V O L _ I S S _ C H E C K >------------------------ Adds error if |volume= or |issue= has what appears to be some form of redundant 'type' indicator. Applies to both; this function looks for issue text in both |issue= and |volume= and looks for volume-like text in |voluem= and |issue=. For |volume=: 'V.', or 'Vol.' (with or without the dot) abbreviations or 'Volume' in the first characters of the parameter content (all case insensitive). 'V' and 'v' (without the dot) are presumed to be roman numerals so are allowed. For |issue=: 'No.', 'I.', 'Iss.' (with or without the dot) abbreviations, or 'Issue' in the first characters of the parameter content (all case insensitive); numero styling: 'n°' with degree sign U+00B0, and № precomposed numero sign U+2116. Single character values ('v', 'i', 'n') allowed when not followed by separator character ('.', ':', '=', or whitespace character) – param values are trimmed of whitespace by MediaWiki before delivered to the module. <val> is |volume= or |issue= parameter value <name> is |volume= or |issue= parameter name for error message <selector> is 'v' for |volume=, 'i' for |issue= sets error message on failure; returns nothing ]] local function extra_text_in_vol_iss_check (val, name, selector) if not utilities.is_set (val) then return; end local handler = 'v' == selector and 'err_extra_text_volume' or 'err_extra_text_issue'; local accept_val; -- for now, ignore linter warning val, accept_val = utilities.has_accept_as_written (val); --if accept_val then -- if uncomment this, |volume=((vol. 1)) suppresses error -- return; --end --val = mw.text.unstripNoWiki (val); -- if uncomment this, |volume=<nowiki>vol. 1</nowiki> shows error val = val:lower(); -- force parameter value to lower case for _, pattern in ipairs (cfg.vol_iss_pg_patterns.vi_patterns_t) do -- spin through the sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message (handler, name); -- add error message return; -- and done end end end --[=[-------------------------< G E T _ V _ N A M E _ T A B L E >---------------------------------------------- split apart a |vauthors= or |veditors= parameter. This function allows for corporate names, wrapped in doubled parentheses to also have commas; in the old version of the code, the doubled parentheses were included in the rendered citation and in the metadata. Individual author names may be wikilinked |vauthors=Jones AB, [[E. B. White|White EB]], ((Black, Brown, and Co.)) ]=] local function get_v_name_table (vparam, output_table, output_link_table) local _, accept = utilities.has_accept_as_written (vparam); if accept then utilities.add_prop_cat ('vanc-accept'); -- add properties category end local name_table = mw.text.split(vparam, "%s*,%s*"); -- names are separated by commas local wl_type, label, link; -- wl_type not used here; just a placeholder local i = 1; while name_table[i] do if name_table[i]:match ('^%(%(.*[^%)][^%)]$') then -- first segment of corporate with one or more commas; this segment has the opening doubled parentheses local name = name_table[i]; i = i + 1; -- bump indexer to next segment while name_table[i] do name = name .. ', ' .. name_table[i]; -- concatenate with previous segments if name_table[i]:match ('^.*%)%)$') then -- if this table member has the closing doubled parentheses break; -- and done reassembling so end i = i + 1; -- bump indexer end table.insert (output_table, name); -- and add corporate name to the output table table.insert (output_link_table, ''); -- no wikilink else wl_type, label, link = utilities.is_wikilink (name_table[i]); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] table.insert (output_table, label); -- add this name if 1 == wl_type then table.insert (output_link_table, label); -- simple wikilink [[D]] else table.insert (output_link_table, link); -- no wikilink or [[L|D]]; add this link if there is one, else empty string end end i = i + 1; end return output_table; end --[[--------------------------< P A R S E _ V A U T H O R S _ V E D I T O R S >-------------------------------- This function extracts author / editor names from |vauthors= or |veditors= and finds matching |xxxxor-maskn= and |xxxxor-linkn= in args. It then returns a table of assembled names just as extract_names() does. Author / editor names in |vauthors= or |veditors= must be in Vancouver system style. Corporate or institutional names may sometimes be required and because such names will often fail the is_good_vanc_name() and other format compliance tests, are wrapped in doubled parentheses ((corporate name)) to suppress the format tests. Supports generational suffixes Jr, 2nd, 3rd, 4th–6th. This function sets the Vancouver error when a required comma is missing and when there is a space between an author's initials. ]] local function parse_vauthors_veditors (args, vparam, list_name) local names = {}; -- table of names assembled from |vauthors=, |author-maskn=, |author-linkn= local v_name_table = {}; local v_link_table = {}; -- when name is wikilinked, targets go in this table local etal = false; -- return value set to true when we find some form of et al. vauthors parameter local last, first, link, mask, suffix; local corporate = false; vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period) v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); -- names are separated by commas for i, v_name in ipairs(v_name_table) do first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor local accept_name; v_name, accept_name = utilities.has_accept_as_written (v_name); -- remove accept-this-as-written markup when it wraps all of <v_name> if accept_name then last = v_name; corporate = true; -- flag used in list_people() elseif string.find(v_name, "%s") then if v_name:find('[;%.]') then -- look for commonly occurring punctuation characters; add_vanc_error (cfg.err_msg_supl.punctuation, i); end local lastfirst_t = mw.text.split(v_name, "%s+"); first = table.remove (lastfirst_t); -- removes and returns value of last element in table which should be initials or generational suffix if not mw.ustring.match (first, '^%u+$') then -- mw.ustring here so that later we will catch non-Latin characters suffix = first; -- not initials so assume that whatever we got is a generational suffix first = table.remove (lastfirst_t); -- get what should be the initials from the table end last = table.concat (lastfirst_t, ' '); -- returns a string that is the concatenation of all other names that are not initials and generational suffix if not utilities.is_set (last) then first = ''; -- unset last = v_name; -- last empty because something wrong with first add_vanc_error (cfg.err_msg_supl.name, i); end if mw.ustring.match (last, '%a+%s+%u+%s+%a+') then add_vanc_error (cfg.err_msg_supl['missing comma'], i); -- matches last II last; the case when a comma is missing end if mw.ustring.match (v_name, ' %u %u$') then -- this test is in the wrong place TODO: move or replace with a more appropriate test add_vanc_error (cfg.err_msg_supl.initials, i); -- matches a space between two initials end else last = v_name; -- last name or single corporate name? Doesn't support multiword corporate names? do we need this? end if utilities.is_set (first) then if not mw.ustring.match (first, "^%u?%u$") then -- first shall contain one or two upper-case letters, nothing else add_vanc_error (cfg.err_msg_supl.initials, i); -- too many initials; mixed case initials (which may be ok Romanization); hyphenated initials end is_good_vanc_name (last, first, suffix, i); -- check first and last before restoring the suffix which may have a non-Latin digit if utilities.is_set (suffix) then first = first .. ' ' .. suffix; -- if there was a suffix concatenate with the initials suffix = ''; -- unset so we don't add this suffix to all subsequent names end else if not corporate then is_good_vanc_name (last, '', nil, i); end end link = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ) or v_link_table[i]; mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); names[i] = {last = last, first = first, link = link, mask = mask, corporate = corporate}; -- add this assembled name to our names list end return names, etal; -- all done, return our list of names end --[[--------------------------< S E L E C T _ A U T H O R _ E D I T O R _ S O U R C E >------------------------ Select one of |authors=, |authorn= / |lastn / firstn=, or |vauthors= as the source of the author name list or select one of |editorn= / editor-lastn= / |editor-firstn= or |veditors= as the source of the editor name list. Only one of these appropriate three will be used. The hierarchy is: |authorn= (and aliases) highest and |authors= lowest; |editorn= (and aliases) highest and |veditors= lowest (support for |editors= withdrawn) When looking for |authorn= / |editorn= parameters, test |xxxxor1= and |xxxxor2= (and all of their aliases); stops after the second test which mimicks the test used in extract_names() when looking for a hole in the author name list. There may be a better way to do this, I just haven't discovered what that way is. Emits an error message when more than one xxxxor name source is provided. In this function, vxxxxors = vauthors or veditors; xxxxors = authors as appropriate. ]] local function select_author_editor_source (vxxxxors, xxxxors, args, list_name) local lastfirst = false; if utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 1 ) or -- do this twice in case we have a |first1= without a |last1=; this ... utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 1 ) or -- ... also catches the case where |first= is used with |vauthors= utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 2 ) or utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 2 ) then lastfirst = true; end if (utilities.is_set (vxxxxors) and true == lastfirst) or -- these are the three error conditions (utilities.is_set (vxxxxors) and utilities.is_set (xxxxors)) or (true == lastfirst and utilities.is_set (xxxxors)) then utilities.set_message ('err_redundant_parameters', utilities.substitute (cfg.special_case_translation.name_list_params, ('AuthorList' == list_name) and cfg.special_case_translation.author or cfg.special_case_translation.editor)); -- add error message end if true == lastfirst then return 1 end; -- return a number indicating which author name source to use if utilities.is_set (vxxxxors) then return 2 end; if utilities.is_set (xxxxors) then return 3 end; return 1; -- no authors so return 1; this allows missing author name test to run in case there is a first without last end --[[--------------------------< I S _ V A L I D _ P A R A M E T E R _ V A L U E >------------------------------ This function is used to validate a parameter's assigned value for those parameters that have only a limited number of allowable values (yes, y, true, live, dead, etc.). When the parameter value has not been assigned a value (missing or empty in the source template) the function returns the value specified by ret_val. If the parameter value is one of the list of allowed values returns the translated value; else, emits an error message and returns the value specified by ret_val. TODO: explain <invert> ]] local function is_valid_parameter_value (value, name, possible, ret_val, invert) if not utilities.is_set (value) then return ret_val; -- an empty parameter is ok end if (not invert and utilities.in_array (value, possible)) then -- normal; <value> is in <possible> table return cfg.keywords_xlate[value]; -- return translation of parameter keyword elseif invert and not utilities.in_array (value, possible) then -- invert; <value> is not in <possible> table return value; -- return <value> as it is else utilities.set_message ('err_invalid_param_val', {name, value}); -- not an allowed value so add error message return ret_val; end end --[[--------------------------< T E R M I N A T E _ N A M E _ L I S T >---------------------------------------- This function terminates a name list (author, contributor, editor) with a separator character (sepc) and a space when the last character is not a sepc character or when the last three characters are not sepc followed by two closing square brackets (close of a wikilink). When either of these is true, the name_list is terminated with a single space character. ]] local function terminate_name_list (name_list, sepc) if (string.sub (name_list, -3, -1) == sepc .. '. ') then -- if already properly terminated return name_list; -- just return the name list elseif (string.sub (name_list, -1, -1) == sepc) or (string.sub (name_list, -3, -1) == sepc .. ']]') then -- if last name in list ends with sepc char return name_list .. " "; -- don't add another else return name_list .. sepc .. ' '; -- otherwise terminate the name list end end --[[-------------------------< F O R M A T _ V O L U M E _ I S S U E >----------------------------------------- returns the concatenation of the formatted volume and issue (or journal article number) parameters as a single string; or formatted volume or formatted issue, or an empty string if neither are set. ]] local function format_volume_issue (volume, issue, article, cite_class, origin, sepc, lower) if not utilities.is_set (volume) and not utilities.is_set (issue) and not utilities.is_set (article) then return ''; end -- same condition as in format_pages_sheets() local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); local is_numeric_vol = volume and (volume:match ('^[MDCLXVI]+$') or volume:match ('^%d+$')); -- is only uppercase roman numerals or only digits? local is_long_vol = volume and (4 < mw.ustring.len(volume)); -- is |volume= value longer than 4 characters? if volume and (not is_numeric_vol and is_long_vol) then -- when not all digits or Roman numerals, is |volume= longer than 4 characters? utilities.add_prop_cat ('long-vol'); -- yes, add properties cat end if is_journal then -- journal-style formatting local vol = ''; if utilities.is_set (volume) then if is_numeric_vol then -- |volume= value all digits or all uppercase Roman numerals? vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, volume}); -- render in bold face elseif is_long_vol then -- not all digits or Roman numerals; longer than 4 characters? vol = utilities.substitute (cfg.messages['j-vol'], {sepc, utilities.hyphen_to_dash (volume)}); -- not bold else -- four or fewer characters vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, utilities.hyphen_to_dash (volume)}); -- bold end end vol = vol .. (utilities.is_set (issue) and utilities.substitute (cfg.messages['j-issue'], issue) or '') vol = vol .. (utilities.is_set (article) and utilities.substitute (cfg.messages['j-article-num'], article) or '') return vol; end if 'podcast' == cite_class and utilities.is_set (issue) then return wrap_msg ('issue', {sepc, issue}, lower); end if 'conference' == cite_class and utilities.is_set (article) then -- |article-number= supported only in journal and conference cites if utilities.is_set (volume) and utilities.is_set (article) then -- both volume and article number return wrap_msg ('vol-art', {sepc, utilities.hyphen_to_dash (volume), article}, lower); elseif utilities.is_set (article) then -- article number alone; when volume alone, handled below return wrap_msg ('art', {sepc, article}, lower); end end -- all other types of citation if utilities.is_set (volume) and utilities.is_set (issue) then return wrap_msg ('vol-no', {sepc, utilities.hyphen_to_dash (volume), issue}, lower); elseif utilities.is_set (volume) then return wrap_msg ('vol', {sepc, utilities.hyphen_to_dash (volume)}, lower); else return wrap_msg ('issue', {sepc, issue}, lower); end end --[[-------------------------< F O R M A T _ P A G E S _ S H E E T S >----------------------------------------- adds static text to one of |page(s)= or |sheet(s)= values and returns it with all of the others set to empty strings. The return order is: page, pages, sheet, sheets Singular has priority over plural when both are provided. ]] local function format_pages_sheets (page, pages, sheet, sheets, cite_class, origin, sepc, nopp, lower) if 'map' == cite_class then -- only cite map supports sheet(s) as in-source locators if utilities.is_set (sheet) then if 'journal' == origin then return '', '', wrap_msg ('j-sheet', sheet, lower), ''; else return '', '', wrap_msg ('sheet', {sepc, sheet}, lower), ''; end elseif utilities.is_set (sheets) then if 'journal' == origin then return '', '', '', wrap_msg ('j-sheets', sheets, lower); else return '', '', '', wrap_msg ('sheets', {sepc, sheets}, lower); end end end local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); if utilities.is_set (page) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], page), '', '', ''; elseif not nopp then return utilities.substitute (cfg.messages['p-prefix'], {sepc, page}), '', '', ''; else return utilities.substitute (cfg.messages['nopp'], {sepc, page}), '', '', ''; end elseif utilities.is_set (pages) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], pages), '', '', ''; elseif tonumber(pages) ~= nil and not nopp then -- if pages is only digits, assume a single page number return '', utilities.substitute (cfg.messages['p-prefix'], {sepc, pages}), '', ''; elseif not nopp then return '', utilities.substitute (cfg.messages['pp-prefix'], {sepc, pages}), '', ''; else return '', utilities.substitute (cfg.messages['nopp'], {sepc, pages}), '', ''; end end return '', '', '', ''; -- return empty strings end --[[--------------------------< I N S O U R C E _ L O C _ G E T >---------------------------------------------- returns one of the in-source locators: page, pages, or at. If any of these are interwiki links to Wikisource, returns the label portion of the interwiki-link as plain text for use in COinS. This COinS thing is done because here we convert an interwiki-link to an external link and add an icon span around that; get_coins_pages() doesn't know about the span. TODO: should it? TODO: add support for sheet and sheets?; streamline; TODO: make it so that this function returns only one of the three as the single in-source (the return value assigned to a new name)? ]] local function insource_loc_get (page, page_orig, pages, pages_orig, at) local ws_url, ws_label, coins_pages, L; -- for Wikisource interwiki-links; TODO: this corrupts page metadata (span remains in place after cleanup; fix there?) if utilities.is_set (page) then if utilities.is_set (pages) or utilities.is_set (at) then pages = ''; -- unset the others at = ''; end extra_text_in_page_check (page, page_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (page); -- make ws URL from |page= interwiki link; link portion L becomes tooltip label if ws_url then page = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in page'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? page = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, page}); coins_pages = ws_label; end elseif utilities.is_set (pages) then if utilities.is_set (at) then at = ''; -- unset end extra_text_in_page_check (pages, pages_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (pages); -- make ws URL from |pages= interwiki link; link portion L becomes tooltip label if ws_url then pages = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in pages'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? pages = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, pages}); coins_pages = ws_label; end elseif utilities.is_set (at) then ws_url, ws_label, L = wikisource_url_make (at); -- make ws URL from |at= interwiki link; link portion L becomes tooltip label if ws_url then at = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in at'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? at = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, at}); coins_pages = ws_label; end end return page, pages, at, coins_pages; end --[[--------------------------< I S _ U N I Q U E _ A R C H I V E _ U R L >------------------------------------ add error message when |archive-url= value is same as |url= or chapter-url= (or alias...) value ]] local function is_unique_archive_url (archive, url, c_url, source, date) if utilities.is_set (archive) then if archive == url or archive == c_url then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); -- add error message return '', ''; -- unset |archive-url= and |archive-date= because same as |url= or |chapter-url= end end return archive, date; end --[=[-------------------------< A R C H I V E _ U R L _ C H E C K >-------------------------------------------- Check archive.org URLs to make sure they at least look like they are pointing at valid archives and not to the save snapshot URL or to calendar pages. When the archive URL is 'https://web.archive.org/save/' (or http://...) archive.org saves a snapshot of the target page in the URL. That is something that Wikipedia should not allow unwitting readers to do. When the archive.org URL does not have a complete timestamp, archive.org chooses a snapshot according to its own algorithm or provides a calendar 'search' result. [[WP:ELNO]] discourages links to search results. This function looks at the value assigned to |archive-url= and returns empty strings for |archive-url= and |archive-date= and an error message when: |archive-url= holds an archive.org save command URL |archive-url= is an archive.org URL that does not have a complete timestamp (YYYYMMDDhhmmss 14 digits) in the correct place otherwise returns |archive-url= and |archive-date= There are two mostly compatible archive.org URLs: //web.archive.org/<timestamp>... -- the old form //web.archive.org/web/<timestamp>... -- the new form The old form does not support or map to the new form when it contains a display flag. There are four identified flags ('id_', 'js_', 'cs_', 'im_') but since archive.org ignores others following the same form (two letters and an underscore) we don't check for these specific flags but we do check the form. This function supports a preview mode. When the article is rendered in preview mode, this function may return a modified archive URL: for save command errors, return undated wildcard (/*/) for timestamp errors when the timestamp has a wildcard, return the URL unmodified for timestamp errors when the timestamp does not have a wildcard, return with timestamp limited to six digits plus wildcard (/yyyymm*/) A secondary function is to return an archive-url timestamp from those archive urls that have them. The timestamp is used by validation.archive_date_check() to see if the value in |archive-date= matches the timestamp in the archive url. ]=] local function archive_url_check (url, date) local err_msg; -- start with the error message empty local path, timestamp, flag; -- portions of the archive.org URL local function is_ts_date_valid (ts, origin_date) -- local function to validate archive url taimestamp date; time ignored local y, m, d = ts:match ('(%d%d%d%d)(%d%d)(%d%d)'); -- split into parts if y and validation.is_valid_date (y, m, d) and (tonumber (y) >= 1996) then return true, tonumber (y) >= origin_date; -- <origin_date> is 1996 for archive.org end end if (not url:match('//web%.archive%.org/')) and (not url:match('//liveweb%.archive%.org/')) then -- also deprecated liveweb Wayback machine URL return url, date; -- not an archive.org archive, return ArchiveURL and ArchiveDate end if url:match('//web%.archive%.org/save/') then -- if a save command URL, we don't want to allow saving of the target page err_msg = cfg.err_msg_supl.save; url = url:gsub ('(//web%.archive%.org)/save/', '%1/*/', 1); -- for preview mode: modify ArchiveURL elseif url:match('//liveweb%.archive%.org/') then err_msg = cfg.err_msg_supl.liveweb; else path, timestamp, flag = url:match('//web%.archive%.org/([^%d]*)(%d+)([^/]*)/'); -- split out some of the URL parts for evaluation if not path then -- malformed in some way; pattern did not match err_msg = cfg.err_msg_supl.timestamp; elseif 14 ~= timestamp:len() then -- path and flag optional, must have 14-digit timestamp here err_msg = cfg.err_msg_supl.timestamp; if '*' ~= flag then local replacement = timestamp:match ('^%d%d%d%d%d%d') or timestamp:match ('^%d%d%d%d'); -- get the first 6 (YYYYMM) or first 4 digits (YYYY) if replacement then -- nil if there aren't at least 4 digits (year) replacement = replacement .. string.rep ('0', 14 - replacement:len()); -- year or yearmo (4 or 6 digits) zero-fill to make 14-digit timestamp url=url:gsub ('(//web%.archive%.org/[^%d]*)%d[^/]*', '%1' .. replacement .. '*', 1) -- for preview, modify ts to 14 digits plus splat for calendar display end end elseif not is_ts_date_valid (timestamp, 1996) then -- is ymd portion of timestamp a valid date? err_msg = cfg.err_msg_supl.timestamp; timestamp = nil; -- unset because invalid elseif utilities.is_set (path) and 'web/' ~= path then -- older archive URLs do not have the extra 'web/' path element err_msg = cfg.err_msg_supl.path; elseif utilities.is_set (flag) and not utilities.is_set (path) then -- flag not allowed with the old form URL (without the 'web/' path element) err_msg = cfg.err_msg_supl.flag; elseif utilities.is_set (flag) and not flag:match ('%a%a_') then -- flag if present must be two alpha characters and underscore (requires 'web/' path element) err_msg = cfg.err_msg_supl.flag; else return url, date, timestamp; -- return ArchiveURL, ArchiveDate, and timestamp from |archive-url= end end -- if here, something not right so utilities.set_message ('err_archive_url', {err_msg}); -- add error message and if is_preview_mode then return url, date, timestamp; -- preview mode so return ArchiveURL, ArchiveDate, and timestamp from |archive-url= else return '', ''; -- return empty strings for ArchiveURL and ArchiveDate end end --[[--------------------------< P L A C E _ C H E C K >-------------------------------------------------------- check |place=, |publication-place=, |location= to see if these params include digits. This function added because many editors misuse location to specify the in-source location (|page(s)= and |at= are supposed to do that) returns the original parameter value without modification; added maint cat when parameter value contains digits ]] local function place_check (param_val) if not utilities.is_set (param_val) then -- parameter empty or omitted return param_val; -- return that empty state end if mw.ustring.find (param_val, '%d') then -- not empty, are there digits in the parameter value utilities.set_message ('maint_location'); -- yep, add maint cat end return param_val; -- and done end --[[--------------------------< I S _ A R C H I V E D _ C O P Y >---------------------------------------------- compares |title= to 'Archived copy' (placeholder added by bots that can't find proper title); if matches, return true; nil else ]] local function is_archived_copy (title) title = mw.ustring.lower(title); -- switch title to lower case if title:find (cfg.special_case_translation.archived_copy.en) then -- if title is 'Archived copy' return true; elseif cfg.special_case_translation.archived_copy['local'] then if mw.ustring.find (title, cfg.special_case_translation.archived_copy['local']) then -- mw.ustring() because might not be Latin script return true; end end end --[[--------------------------< D I S P L A Y _ N A M E S _ S E L E C T >-------------------------------------- for any of the |display-authors=, |display-editors=, etc parameters, select either the local or global setting. When both are present, look at <local_display_names> value. When the value is some sort of 'et al.'string, special handling is required. When {{cs1 config}} has |display-<namelist>= AND this template has |display-<namelist>=etal AND: the number of names specified by <number_of_names> is: greater than the number specified in the global |display-<namelist>= parameter (<global_display_names>) use global |display-<namelist>= parameter value set overridden maint category less than or equal to the number specified in the global |display-<namelist>= parameter use local |display-<namelist>= parameter value The purpose of this function is to prevent categorizing a template that has fewer names than the global setting to keep the etal annotation specified by <local_display_names>. ]] local function display_names_select (global_display_names, local_display_names, param_name, number_of_names) if global_display_names and utilities.is_set (local_display_names) then -- when both if 'etal' == local_display_names:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings number_of_names = tonumber (number_of_names); -- convert these to numbers for comparison local global_display_names_num = tonumber (global_display_names); -- <global_display_names> not set when parameter value is not digits if number_of_names > global_display_names_num then -- template has more names than global config allows to be displayed? utilities.set_message ('maint_overridden_setting'); -- set a maint message because global is overriding local |display-<namelist>=etal return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local because fewer names so let <local_display_names> control end end -- here when <global_display_names> and <local_display_names> both numbers; <global_display_names> controls utilities.set_message ('maint_overridden_setting'); -- set a maint message return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) end -- here when only one of <global_display_names> or <local_display_names> set if global_display_names then return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local end end --[[--------------------------< M O D E _ S E T >-------------------------------------------------------------- fetch global mode setting from {{cs1 config}} (if present) or from |mode= (if present); global setting overrides local |mode= parameter value. When both are present, emit maintenance message ]] local function mode_set (Mode, Mode_origin) local mode; if cfg.global_cs1_config_t['Mode'] then -- global setting in {{cs1 config}}; nil when empty or assigned value invalid mode = is_valid_parameter_value (cfg.global_cs1_config_t['Mode'], 'cs1 config: mode', cfg.keywords_lists['mode'], ''); -- error messaging 'param' here is a hoax else mode = is_valid_parameter_value (Mode, Mode_origin, cfg.keywords_lists['mode'], ''); end if cfg.global_cs1_config_t['Mode'] and utilities.is_set (Mode) then -- when template has |mode=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end return mode; end --[[--------------------------< Q U O T E _ M A K E >---------------------------------------------------------- create quotation from |quote=, |trans-quote=, and/or script-quote= with or without |quote-page= or |quote-pages= when any of those three quote parameters are set, this function unsets <PostScript>. When none of those parameters are set, |quote-page= and |quote-pages= are unset to nil so that they are not included in the template's metadata ]] local function quote_make (quote, trans_quote, script_quote, quote_page, quote_pages, nopp, sepc, postscript) if utilities.is_set (quote) or utilities.is_set (trans_quote) or utilities.is_set (script_quote) then if utilities.is_set (quote) then if quote:sub(1, 1) == '"' and quote:sub(-1, -1) == '"' then -- if first and last characters of quote are quote marks quote = quote:sub(2, -2); -- strip them off end end quote = kern_quotes (quote); -- kern if needed quote = utilities.wrap_style ('quoted-text', quote ); -- wrap in <q>...</q> tags if utilities.is_set (script_quote) then quote = script_concatenate (quote, script_quote, 'script-quote'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after quote is wrapped end if utilities.is_set (trans_quote) then if trans_quote:sub(1, 1) == '"' and trans_quote:sub(-1, -1) == '"' then -- if first and last characters of |trans-quote are quote marks trans_quote = trans_quote:sub(2, -2); -- strip them off end quote = quote .. " " .. utilities.wrap_style ('trans-quoted-title', trans_quote ); end if utilities.is_set (quote_page) or utilities.is_set (quote_pages) then -- add page prefix local quote_prefix = ''; if utilities.is_set (quote_page) then extra_text_in_page_check (quote_page, 'quote-page'); -- add to maint cat if |quote-page= value begins with what looks like p., pp., etc. if not nopp then quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_page}); else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_page}); end elseif utilities.is_set (quote_pages) then extra_text_in_page_check (quote_pages, 'quote-pages'); -- add to maint cat if |quote-pages= value begins with what looks like p., pp., etc. if tonumber(quote_pages) ~= nil and not nopp then -- if only digits, assume single page quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_pages}); elseif not nopp then quote_prefix = utilities.substitute (cfg.messages['pp-prefix'], {sepc, quote_pages}); else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_pages}); end end quote = quote_prefix .. ": " .. quote; else quote = sepc .. " " .. quote; end postscript = ""; -- cs1|2 does not supply terminal punctuation when |quote= is set elseif utilities.is_set (quote_page) or utilities.is_set (quote_pages) then quote_page = nil; -- unset; these require |quote=; TODO: error message? quote_pages = nil; end return quote, quote_page, quote_pages, postscript; end --[[--------------------------< C H E C K _ P U B L I S H E R _ N A M E >-------------------------------------- look for variations of '<text>: <text>' that might be '<location>: <publisher>' in |publisher= parameter value. when found, emit a maintenance message; return nil else <publisher> is the value assigned to |publisher= or |institution= ]] local function check_publisher_name (publisher) local patterns_t = { '^[%w%s]+%s*:%s*[%w%s]+$', -- plain text <location>: <publisher> '^%[+[%w%s:|]+%]+%s*:%s*[%w%s]+$', -- partially wikilinked [[<location>]]: <publisher> '^[%w%s]+%s*:%s*%[+[%w%s:|]+%]+$', -- partially wikilinked <location>: [[<publisher>]] '^%[+[%w%s:|]+%]+%s*:%s*%[+[%w%s:|]+%]+$', -- wikilinked [[<location>]]: [[<publisher>]] } for _, pattern in ipairs (patterns_t) do -- spin through the patterns_t sequence if mw.ustring.match (publisher, pattern) then -- does this pattern match? utilities.set_message ('maint_publisher_location'); -- set a maint message return; -- and done end end end --[[--------------------------< I S _ P A G E _ A R T _ N U M >------------------------------------------------ compare the trailing (rightmost) characters of the |doi= value against the whole value assigned to |page(s)=. return boolean true when: |page(s)= has exactly 8 digits and a dot between the fourth and fifth digits matches the trailing 9 characters of the |doi= value: |page=12345678 → |page=1234.5678 matches |doi=10.xxxx/yyyy1234.5678 |page(s)= is 5 or more characters and matches |doi= values's trailing characters |page(s)= begins with a lowercase 'e' and |page(s)= without the 'e' matches |doi= values's trailing characters: |page=e12345 → |page=12345 matches |doi=10.xxxx/yyyy12345 |page(s)= begins with a uppercase 'CD' followed by (typically) six digits matches |doi= values that ends with 'CDxxxxxx.pubx' (where 'x' is any single digit) return nil when |page(s)= values: are ranges separated by underscore, hyphen, emdash, endash, figure dash, or minus character are comma- or semicolon-separated lists of pages have external urls (has text 'http') are digit-only values less than 10000 do not match |doi= values's trailing characters ]] local function is_page_art_num (page, doi) if not (utilities.is_set (page) and utilities.is_set (doi)) then -- both required return; -- abandon; nothing to do end if page:match ('[,;_−–—‒%-]') then -- when |page(s)= might be a page range or a separated list of pages return; -- abandon end page = page:lower(); -- because doi names are case insensitive doi = doi:lower(); -- force these to lowercase for testing if page:match ('http') then -- when |page(s)= appears to hold a url return; -- abandon end if tonumber (page) then -- is |page(s)= digits only if 10000 > tonumber (page) then -- when |page(s)= less than 10000 return; -- abandon end if doi:match (page .. '$') then -- digits only page number match the last digits in |doi=? return true; end if 8 == page:len() then -- special case when |page(s)= is exactly 8 digits local dot_page = page:gsub ('(%d%d%d%d)(%d%d%d%d)', '%1.%2'); -- make a |page=xxxx.yyyy version commonly used in |doi= if doi:match (dot_page .. '$') then -- 8-digit dotted page number match the last characters in |doi=? return true; end end else -- here when |page(s)= is alpha-numeric if 4 < page:len() then -- when |page(s)= is five or more characters if doi:match (page .. '$') then -- alpha-numeric page match the last characters in |doi=? return true; end local epage = page:match ('^e([%w]+)$'); -- if first character of |page= is 'e', remove it if epage and doi:match (epage .. '$') then -- page number match the last characters in |doi=? return true; end local cdpage = page:match ('^cd%d+$'); -- if first characters of |page= are 'CD' and last characters are digits (typically 6 digits) if cdpage and doi:match (cdpage .. '%.pub%d$') then -- page number matches doi 'CDxxxxxx.pubx' where 'x' is a digit return true; end end end end --[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------ This is the main function doing the majority of the citation formatting. ]] local function citation0( config, args ) --[[ Load Input Parameters The argument_wrapper facilitates the mapping of multiple aliases to single internal variable. ]] local A = argument_wrapper ( args ); -- Pick out the relevant fields from the arguments. Different citation templates -- define different field names for the same underlying things. local author_etal; local a = {}; -- authors list from |lastn= / |firstn= pairs or |vauthors= local Authors; local NameListStyle; if cfg.global_cs1_config_t['NameListStyle'] then -- global setting in {{cs1 config}} overrides local |name-list-style= parameter value; nil when empty or assigned value invalid NameListStyle = is_valid_parameter_value (cfg.global_cs1_config_t['NameListStyle'], 'cs1 config: name-list-style', cfg.keywords_lists['name-list-style'], ''); -- error messaging 'param' here is a hoax else NameListStyle = is_valid_parameter_value (A['NameListStyle'], A:ORIGIN('NameListStyle'), cfg.keywords_lists['name-list-style'], ''); end if cfg.global_cs1_config_t['NameListStyle'] and utilities.is_set (A['NameListStyle']) then -- when template has |name-list-style=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end local Collaboration = A['Collaboration']; do -- to limit scope of selected local selected = select_author_editor_source (A['Vauthors'], A['Authors'], args, 'AuthorList'); if 1 == selected then a, author_etal = extract_names (args, 'AuthorList'); -- fetch author list from |authorn= / |lastn= / |firstn=, |author-linkn=, and |author-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be a, author_etal = parse_vauthors_veditors (args, A['Vauthors'], 'AuthorList'); -- fetch author list from |vauthors=, |author-linkn=, and |author-maskn= elseif 3 == selected then Authors = A['Authors']; -- use content of |people= or |credits=; |authors= is deprecated; TODO: constrain |people= and |credits= to cite av media, episode, serial? end if utilities.is_set (Collaboration) then author_etal = true; -- so that |display-authors=etal not required end end local editor_etal; local e = {}; -- editors list from |editor-lastn= / |editor-firstn= pairs or |veditors= do -- to limit scope of selected local selected = select_author_editor_source (A['Veditors'], nil, args, 'EditorList'); -- support for |editors= withdrawn if 1 == selected then e, editor_etal = extract_names (args, 'EditorList'); -- fetch editor list from |editorn= / |editor-lastn= / |editor-firstn=, |editor-linkn=, and |editor-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be e, editor_etal = parse_vauthors_veditors (args, args.veditors, 'EditorList'); -- fetch editor list from |veditors=, |editor-linkn=, and |editor-maskn= end end local Chapter = A['Chapter']; -- done here so that we have access to |contribution= from |chapter= and |script-chapter= aliases local Chapter_origin = A:ORIGIN ('Chapter'); local ScriptChapter = A['ScriptChapter']; local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); local Contribution; -- because contribution is required for contributor(s) if 'contribution' == Chapter_origin then -- is there a |contribution= parameter? Contribution = Chapter; -- get the name of the contribution elseif 'script-contribution' == ScriptChapter_origin then -- no, so is there a |script-contribution= parameter? Contribution = ScriptChapter; -- get the name of the contribution end local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (A['Periodical']) then -- |contributor= and |contribution= only supported in book cites c = extract_names (args, 'ContributorList'); -- fetch contributor list from |contributorn= / |contributor-lastn=, -firstn=, -linkn=, -maskn= if 0 < #c then if not utilities.is_set (Contribution) then -- |contributor= requires |contribution= utilities.set_message ('err_contributor_missing_required_param', 'contribution'); -- add missing contribution error message c = {}; -- blank the contributors' table; it is used as a flag later end if 0 == #a then -- |contributor= requires |author= utilities.set_message ('err_contributor_missing_required_param', 'author'); -- add missing author error message c = {}; -- blank the contributors' table; it is used as a flag later end end else -- if not a book cite if utilities.select_one (args, cfg.aliases['ContributorList-Last'], 'err_redundant_parameters', 1 ) then -- are there contributor name list parameters? utilities.set_message ('err_contributor_ignored'); -- add contributor ignored error message end Contribution = nil; -- unset end local Title = A['Title']; local TitleLink = A['TitleLink']; local auto_select = ''; -- default is auto local accept_link; TitleLink, accept_link = utilities.has_accept_as_written (TitleLink, true); -- test for accept-this-as-written markup if (not accept_link) and utilities.in_array (TitleLink, {'none', 'pmc', 'doi'}) then -- check for special keywords auto_select = TitleLink; -- remember selection for later TitleLink = ''; -- treat as if |title-link= would have been empty end TitleLink = link_title_ok (TitleLink, A:ORIGIN ('TitleLink'), Title, 'title'); -- check for wiki-markup in |title-link= or wiki-markup in |title= when |title-link= is set local Section = ''; -- {{cite map}} only; preset to empty string for concatenation if not used if 'map' == config.CitationClass and 'section' == Chapter_origin then Section = A['Chapter']; -- get |section= from |chapter= alias list; |chapter= and the other aliases not supported in {{cite map}} Chapter = ''; -- unset for now; will be reset later from |map= if present end local Periodical = A['Periodical']; local Periodical_origin = A:ORIGIN('Periodical'); local ScriptPeriodical = A['ScriptPeriodical']; local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical'); local TransPeriodical = A['TransPeriodical']; local TransPeriodical_origin = A:ORIGIN ('TransPeriodical'); if (utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical))) then local param; if utilities.is_set (Periodical) then -- get a parameter name from one of these periodical related meta-parameters Periodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = Periodical_origin -- get parameter name for error messaging elseif utilities.is_set (TransPeriodical) then TransPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = TransPeriodical_origin; -- get parameter name for error messaging elseif utilities.is_set (ScriptPeriodical) then ScriptPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = ScriptPeriodical_origin; -- get parameter name for error messaging end if utilities.is_set (param) then -- if we found one utilities.set_message ('err_periodical_ignored', {param}); -- emit an error message end end if utilities.is_set (Periodical) then local i; Periodical, i = utilities.strip_apostrophe_markup (Periodical); -- strip apostrophe markup so that metadata isn't contaminated if i then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {Periodical_origin}); end end if 'mailinglist' == config.CitationClass then -- special case for {{cite mailing list}} if utilities.is_set (Periodical) and utilities.is_set (A ['MailingList']) then -- both set emit an error TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', Periodical_origin) .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'mailinglist')}); end Periodical = A ['MailingList']; -- error or no, set Periodical to |mailinglist= value because this template is {{cite mailing list}} Periodical_origin = A:ORIGIN('MailingList'); end -- web and news not tested for now because of -- Wikipedia:Administrators%27_noticeboard#Is_there_a_semi-automated_tool_that_could_fix_these_annoying_"Cite_Web"_errors? if not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) then -- 'periodical' templates require periodical parameter -- local p = {['journal'] = 'journal', ['magazine'] = 'magazine', ['news'] = 'newspaper', ['web'] = 'website'}; -- for error message local p = {['journal'] = 'journal', ['magazine'] = 'magazine'}; -- for error message if p[config.CitationClass] then utilities.set_message ('err_missing_periodical', {config.CitationClass, p[config.CitationClass]}); end end local Volume; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) then if not utilities.in_array (Periodical_origin, cfg.citation_no_volume_t) then -- {{citation}} does not render |volume= when these parameters are used Volume = A['Volume']; -- but does for all other 'periodicals' end elseif utilities.is_set (ScriptPeriodical) then if 'script-website' ~= ScriptPeriodical_origin then -- {{citation}} does not render volume for |script-website= Volume = A['Volume']; -- but does for all other 'periodicals' end else Volume = A['Volume']; -- and does for non-'periodical' cites end elseif utilities.in_array (config.CitationClass, cfg.templates_using_volume) then -- render |volume= for cs1 according to the configuration settings Volume = A['Volume']; end extra_text_in_vol_iss_check (Volume, A:ORIGIN ('Volume'), 'v'); local Issue; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) and utilities.in_array (Periodical_origin, cfg.citation_issue_t) then -- {{citation}} may render |issue= when these parameters are used Issue = A['Issue']; end elseif utilities.in_array (config.CitationClass, cfg.templates_using_issue) then -- conference & map books do not support issue; {{citation}} listed here because included in settings table if not (utilities.in_array (config.CitationClass, {'conference', 'map', 'citation'}) and not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical))) then Issue = A['Issue']; end end local ArticleNumber; if utilities.in_array (config.CitationClass, {'journal', 'conference'}) or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then ArticleNumber = A['ArticleNumber']; end extra_text_in_vol_iss_check (Issue, A:ORIGIN ('Issue'), 'i'); Issue = utilities.hyphen_to_dash (Issue); local Page; local Pages; local At; local QuotePage; local QuotePages; if not utilities.in_array (config.CitationClass, cfg.templates_not_using_page) then -- TODO: rewrite to emit ignored parameter error message? Page = A['Page']; Pages = utilities.hyphen_to_dash (A['Pages']); At = A['At']; QuotePage = A['QuotePage']; QuotePages = utilities.hyphen_to_dash (A['QuotePages']); end local NoPP = is_valid_parameter_value (A['NoPP'], A:ORIGIN('NoPP'), cfg.keywords_lists['yes_true_y'], nil); local Mode = mode_set (A['Mode'], A:ORIGIN('Mode')); -- separator character and postscript local sepc, PostScript = set_style (Mode:lower(), A['PostScript'], config.CitationClass); local Quote; Quote, QuotePage, QuotePages, PostScript = quote_make (A['Quote'], A['TransQuote'], A['ScriptQuote'], QuotePage, QuotePages, NoPP, sepc, PostScript); local Edition = A['Edition']; local PublicationPlace = place_check (A['PublicationPlace'], A:ORIGIN('PublicationPlace')); local Place = place_check (A['Place'], A:ORIGIN('Place')); local PublisherName = A['PublisherName']; local PublisherName_origin = A:ORIGIN('PublisherName'); if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then local i; PublisherName, i = utilities.strip_apostrophe_markup (PublisherName); -- strip apostrophe markup so that metadata isn't contaminated; publisher is never italicized if i and (0 < i) then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {PublisherName_origin}); end end if ('document' == config.CitationClass) and not utilities.is_set (PublisherName) then utilities.set_message ('err_missing_publisher', {config.CitationClass, 'publisher'}); end local Newsgroup = A['Newsgroup']; -- TODO: strip apostrophe markup? local Newsgroup_origin = A:ORIGIN('Newsgroup'); if 'newsgroup' == config.CitationClass then if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then -- general use parameter |publisher= not allowed in cite newsgroup utilities.set_message ('err_parameter_ignored', {PublisherName_origin}); end PublisherName = nil; -- ensure that this parameter is unset for the time being; will be used again after COinS end if 'book' == config.CitationClass or 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then local accept; PublisherName, accept = utilities.has_accept_as_written (PublisherName); -- check for and remove accept-as-written markup from |publisher= wrapped if not accept then -- when no accept-as-written markup check_publisher_name (PublisherName); -- emit maint message when |publisher= might be prefixed with publisher's location end end local URL = A['URL']; -- TODO: better way to do this for URL, ChapterURL, and MapURL? local UrlAccess = is_valid_parameter_value (A['UrlAccess'], A:ORIGIN('UrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (URL) and utilities.is_set (UrlAccess) then UrlAccess = nil; utilities.set_message ('err_param_access_requires_param', 'url'); end local ChapterURL = A['ChapterURL']; local ChapterUrlAccess = is_valid_parameter_value (A['ChapterUrlAccess'], A:ORIGIN('ChapterUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (ChapterURL) and utilities.is_set (ChapterUrlAccess) then ChapterUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {A:ORIGIN('ChapterUrlAccess'):gsub ('%-access', '')}); end local MapUrlAccess = is_valid_parameter_value (A['MapUrlAccess'], A:ORIGIN('MapUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (A['MapURL']) and utilities.is_set (MapUrlAccess) then MapUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {'map-url'}); end local this_page = mw.title.getCurrentTitle(); -- also used for COinS and for language local no_tracking_cats = is_valid_parameter_value (A['NoTracking'], A:ORIGIN('NoTracking'), cfg.keywords_lists['yes_true_y'], nil); -- check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories if not utilities.is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page if cfg.uncategorized_namespaces[this_page.namespace] then -- is this page's namespace id one of the uncategorized namespace ids? no_tracking_cats = "true"; -- set no_tracking_cats end for _, v in ipairs (cfg.uncategorized_subpages) do -- cycle through page name patterns if this_page.text:match (v) then -- test page name against each pattern no_tracking_cats = "true"; -- set no_tracking_cats break; -- bail out if one is found end end end -- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it) utilities.select_one (args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'err_redundant_parameters'); -- this is a dummy call simply to get the error message and category local coins_pages; Page, Pages, At, coins_pages = insource_loc_get (Page, A:ORIGIN('Page'), Pages, A:ORIGIN('Pages'), At); if utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- both |publication-place= and |place= (|location=) allowed if different utilities.add_prop_cat ('location-test'); -- add property cat to evaluate how often PublicationPlace and Place are used together if PublicationPlace == Place then Place = ''; -- unset; don't need both if they are the same end elseif not utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- when only |place= (|location=) is set ... PublicationPlace = Place; -- promote |place= (|location=) to |publication-place end if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same local URL_origin = A:ORIGIN('URL'); -- get name of parameter that holds URL local ChapterURL_origin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL -- local ScriptChapter = A['ScriptChapter']; -- local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); local Format = A['Format']; local ChapterFormat = A['ChapterFormat']; local TransChapter = A['TransChapter']; local TransChapter_origin = A:ORIGIN ('TransChapter'); local TransTitle = A['TransTitle']; local ScriptTitle = A['ScriptTitle']; --[[ Parameter remapping for cite encyclopedia: When the citation has these parameters: |encyclopedia= and |title= then map |title= to |article= and |encyclopedia= to |title= for rendering |encyclopedia= and |article= then map |encyclopedia= to |title= for rendering |trans-title= maps to |trans-chapter= when |title= is re-mapped |url= maps to |chapter-url= when |title= is remapped All other combinations of |encyclopedia=, |title=, and |article= are not modified ]] local Encyclopedia = A['Encyclopedia']; -- used as a flag by this module and by ~/COinS local ScriptEncyclopedia = A['ScriptEncyclopedia']; local TransEncyclopedia = A['TransEncyclopedia']; if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then -- emit error message when Encyclopedia set but template is other than {{cite encyclopedia}} or {{citation}} if 'encyclopaedia' ~= config.CitationClass and 'citation' ~= config.CitationClass then if utilities.is_set (Encyclopedia) then utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('Encyclopedia')}); else utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('ScriptEncyclopedia')}); end Encyclopedia = nil; -- unset these because not supported by this template ScriptEncyclopedia = nil; TransEncyclopedia = nil; end elseif utilities.is_set (TransEncyclopedia) then utilities.set_message ('err_trans_missing_title', {'encyclopedia'}); end if ('encyclopaedia' == config.CitationClass) or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Periodical) and utilities.is_set (Encyclopedia) then -- when both parameters set emit an error message; {{citation}} only; Periodical not allowed in {{cite encyclopedia}} utilities.set_message ('err_periodical_ignored', {Periodical_origin}); end if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then Periodical = Encyclopedia; -- error or no, set Periodical to Encyclopedia for rendering; {{citation}} could (not legitimately) have both; use Encyclopedia Periodical_origin = A:ORIGIN ('Encyclopedia'); ScriptPeriodical = ScriptEncyclopedia; ScriptPeriodical_origin = A:ORIGIN ('ScriptEncyclopedia'); if utilities.is_set (Title) or utilities.is_set (ScriptTitle) then if not utilities.is_set (Chapter) then Chapter = Title; -- |encyclopedia= and |title= are set so map |title= params to |article= params for rendering ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle') TransChapter = TransTitle; ChapterURL = URL; ChapterURL_origin = URL_origin; ChapterUrlAccess = UrlAccess; ChapterFormat = Format; if not utilities.is_set (ChapterURL) and utilities.is_set (TitleLink) then Chapter = utilities.make_wikilink (TitleLink, Chapter); end Title = Periodical; -- now map |encyclopedia= params to |title= params for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; URL = ''; Format = ''; TitleLink = ''; end elseif utilities.is_set (Chapter) or utilities.is_set (ScriptChapter) then -- |title= not set Title = Periodical; -- |encyclopedia= set and |article= set so map |encyclopedia= to |title= for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; end end end -- special case for cite techreport. local ID = A['ID']; if (config.CitationClass == "techreport") then -- special case for cite techreport if utilities.is_set (A['Number']) then -- cite techreport uses 'number', which other citations alias to 'issue' if not utilities.is_set (ID) then -- can we use ID for the "number"? ID = A['Number']; -- yes, use it else -- ID has a value so emit error message utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'id') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'number')}); end end end -- Account for the oddity that is {{cite conference}}, before generation of COinS data. local ChapterLink -- = A['ChapterLink']; -- deprecated as a parameter but still used internally by cite episode local Conference = A['Conference']; local BookTitle = A['BookTitle']; local TransTitle_origin = A:ORIGIN ('TransTitle'); if 'conference' == config.CitationClass then if utilities.is_set (BookTitle) then Chapter = Title; Chapter_origin = 'title'; -- ChapterLink = TitleLink; -- |chapter-link= is deprecated ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; URL_origin = ''; ChapterFormat = Format; TransChapter = TransTitle; TransChapter_origin = TransTitle_origin; Title = BookTitle; Format = ''; -- TitleLink = ''; TransTitle = ''; URL = ''; end elseif 'speech' ~= config.CitationClass then Conference = ''; -- not cite conference or cite speech so make sure this is empty string end local cs2_lower = function (text) -- if mode is cs2, use lower case if (sepc ~= '.') then return text:lower(); end return text; end local use_lowercase = ( sepc == ',' ); -- controls capitalization of certain static text -- cite map oddities local Cartography = ""; local Scale = ""; local Sheet = A['Sheet'] or ''; local Sheets = A['Sheets'] or ''; if config.CitationClass == "map" then if utilities.is_set (Chapter) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'map') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', Chapter_origin)}); -- add error message end Chapter = A['Map']; Chapter_origin = A:ORIGIN('Map'); -- for now, ignore linter warning ChapterURL = A['MapURL']; ChapterURL_origin = A:ORIGIN('MapURL'); TransChapter = A['TransMap']; ScriptChapter = A['ScriptMap'] ScriptChapter_origin = A:ORIGIN('ScriptMap') ChapterUrlAccess = MapUrlAccess; ChapterFormat = A['MapFormat']; Cartography = A['Cartography']; if utilities.is_set ( Cartography ) then Cartography = sepc .. " " .. wrap_msg ('cartography', Cartography, use_lowercase); end Scale = A['Scale']; if utilities.is_set ( Scale ) then Scale = sepc .. " " .. Scale; end end -- Account for the oddities that are {{cite episode}} and {{cite serial}}, before generation of COinS data. local Series = A['Series']; if 'episode' == config.CitationClass or 'serial' == config.CitationClass then local SeriesLink = A['SeriesLink']; SeriesLink = link_title_ok (SeriesLink, A:ORIGIN ('SeriesLink'), Series, 'series'); -- check for wiki-markup in |series-link= or wiki-markup in |series= when |series-link= is set local Network = A['Network']; local Station = A['Station']; local s, n = {}, {}; -- do common parameters first if utilities.is_set (Network) then table.insert(n, Network); end if utilities.is_set (Station) then table.insert(n, Station); end ID = table.concat(n, sepc .. ' '); if 'episode' == config.CitationClass then -- handle the oddities that are strictly {{cite episode}} local Season = A['Season']; local SeriesNumber = A['SeriesNumber']; if utilities.is_set (Season) and utilities.is_set (SeriesNumber) then -- these are mutually exclusive so if both are set TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'season') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'seriesno')}); -- add error message SeriesNumber = ''; -- unset; prefer |season= over |seriesno= end -- assemble a table of parts concatenated later into Series if utilities.is_set (Season) then table.insert(s, wrap_msg ('season', Season, use_lowercase)); end if utilities.is_set (SeriesNumber) then table.insert(s, wrap_msg ('seriesnum', SeriesNumber, use_lowercase)); end if utilities.is_set (Issue) then table.insert(s, wrap_msg ('episode', Issue, use_lowercase)); end Issue = ''; -- unset because this is not a unique parameter Chapter = Title; -- promote title parameters to chapter ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle'); ChapterLink = TitleLink; -- alias |episode-link= TransChapter = TransTitle; ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; ChapterFormat = Format; Title = Series; -- promote series to title TitleLink = SeriesLink; Series = table.concat(s, sepc .. ' '); -- this is concatenation of season, seriesno, episode number if utilities.is_set (ChapterLink) and not utilities.is_set (ChapterURL) then -- link but not URL Chapter = utilities.make_wikilink (ChapterLink, Chapter); elseif utilities.is_set (ChapterLink) and utilities.is_set (ChapterURL) then -- if both are set, URL links episode; Series = utilities.make_wikilink (ChapterLink, Series); end URL = ''; -- unset TransTitle = ''; ScriptTitle = ''; Format = ''; else -- now oddities that are cite serial Issue = ''; -- unset because this parameter no longer supported by the citation/core version of cite serial Chapter = A['Episode']; -- TODO: make |episode= available to cite episode someday? if utilities.is_set (Series) and utilities.is_set (SeriesLink) then Series = utilities.make_wikilink (SeriesLink, Series); end Series = utilities.wrap_style ('italic-title', Series); -- series is italicized end end -- end of {{cite episode}} stuff -- handle type parameter for those CS1 citations that have default values local TitleType = A['TitleType']; local Degree = A['Degree']; if utilities.in_array (config.CitationClass, {'AV-media-notes', 'document', 'interview', 'mailinglist', 'map', 'podcast', 'pressrelease', 'report', 'speech', 'techreport', 'thesis'}) then TitleType = set_titletype (config.CitationClass, TitleType); if utilities.is_set (Degree) and "Thesis" == TitleType then -- special case for cite thesis TitleType = Degree .. ' ' .. cfg.title_types ['thesis']:lower(); end end if utilities.is_set (TitleType) then -- if type parameter is specified TitleType = utilities.substitute ( cfg.messages['type'], TitleType); -- display it in parentheses -- TODO: Hack on TitleType to fix bunched parentheses problem end -- legacy: promote PublicationDate to Date if neither Date nor Year are set. local Date = A['Date']; local Date_origin; -- to hold the name of parameter promoted to Date; required for date error messaging local PublicationDate = A['PublicationDate']; local Year = A['Year']; if utilities.is_set (Year) then validation.year_check (Year); -- returns nothing; emits maint message when |year= doesn't hold a 'year' value end if not utilities.is_set (Date) then Date = Year; -- promote Year to Date Year = nil; -- make nil so Year as empty string isn't used for CITEREF if not utilities.is_set (Date) and utilities.is_set (PublicationDate) then -- use PublicationDate when |date= and |year= are not set Date = PublicationDate; -- promote PublicationDate to Date PublicationDate = ''; -- unset, no longer needed Date_origin = A:ORIGIN('PublicationDate'); -- save the name of the promoted parameter else Date_origin = A:ORIGIN('Year'); -- save the name of the promoted parameter end else Date_origin = A:ORIGIN('Date'); -- not a promotion; name required for error messaging end if PublicationDate == Date then PublicationDate = ''; end -- if PublicationDate is same as Date, don't display in rendered citation --[[ Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates. This must be done before we do COinS because here is where we get the date used in the metadata. Date validation supporting code is in Module:Citation/CS1/Date_validation ]] local DF = is_valid_parameter_value (A['DF'], A:ORIGIN('DF'), cfg.keywords_lists['df'], ''); if not utilities.is_set (DF) then DF = cfg.global_df; -- local |df= if present overrides global df set by {{use xxx date}} template end local ArchiveURL; local ArchiveDate; local ArchiveFormat = A['ArchiveFormat']; local archive_url_timestamp; -- timestamp from wayback machine url ArchiveURL, ArchiveDate, archive_url_timestamp = archive_url_check (A['ArchiveURL'], A['ArchiveDate']) ArchiveFormat = style_format (ArchiveFormat, ArchiveURL, 'archive-format', 'archive-url'); ArchiveURL, ArchiveDate = is_unique_archive_url (ArchiveURL, URL, ChapterURL, A:ORIGIN('ArchiveURL'), ArchiveDate); -- add error message when URL or ChapterURL == ArchiveURL local AccessDate = A['AccessDate']; local COinS_date = {}; -- holds date info extracted from |date= for the COinS metadata by Module:Date verification local DoiBroken = A['DoiBroken']; local Embargo = A['Embargo']; local anchor_year; -- used in the CITEREF identifier do -- create defined block to contain local variables date_parameters_list, mismatch local date_parameters_list = { -- AirDate has been promoted to Date so not necessary to check it ['access-date'] = {val = AccessDate, name = A:ORIGIN ('AccessDate')}, ['archive-date'] = {val = ArchiveDate, name = A:ORIGIN ('ArchiveDate')}, ['date'] = {val = Date, name = Date_origin}, ['doi-broken-date'] = {val = DoiBroken, name = A:ORIGIN ('DoiBroken')}, ['pmc-embargo-date'] = {val = Embargo, name = A:ORIGIN ('Embargo')}, ['publication-date'] = {val = PublicationDate, name = A:ORIGIN ('PublicationDate')}, ['year'] = {val = Year, name = A:ORIGIN ('Year')}, }; local error_list = {}; anchor_year, Embargo = validation.dates(date_parameters_list, COinS_date, error_list); if utilities.is_set (Year) and utilities.is_set (Date) then -- both |date= and |year= not normally needed; validation.year_date_check (Year, A:ORIGIN ('Year'), Date, A:ORIGIN ('Date'), error_list); end if 0 == #error_list then -- error free dates only; 0 when error_list is empty local modified = false; -- flag if utilities.is_set (DF) then -- if we need to reformat dates modified = validation.reformat_dates (date_parameters_list, DF); -- reformat to DF format, use long month names if appropriate end if true == validation.date_hyphen_to_dash (date_parameters_list) then -- convert hyphens to dashes where appropriate modified = true; utilities.set_message ('maint_date_format'); -- hyphens were converted so add maint category end -- for those wikis that can and want to have English date names translated to the local language; not supported at en.wiki if cfg.date_name_auto_xlate_enable and validation.date_name_xlate (date_parameters_list, cfg.date_digit_auto_xlate_enable ) then utilities.set_message ('maint_date_auto_xlated'); -- add maint cat modified = true; end if modified then -- if the date_parameters_list values were modified AccessDate = date_parameters_list['access-date'].val; -- overwrite date holding parameters with modified values ArchiveDate = date_parameters_list['archive-date'].val; Date = date_parameters_list['date'].val; DoiBroken = date_parameters_list['doi-broken-date'].val; PublicationDate = date_parameters_list['publication-date'].val; end if archive_url_timestamp and utilities.is_set (ArchiveDate) then validation.archive_date_check (ArchiveDate, archive_url_timestamp, DF); -- does YYYYMMDD in archive_url_timestamp match date in ArchiveDate end else utilities.set_message ('err_bad_date', {utilities.make_sep_list (#error_list, error_list)}); -- add this error message end end -- end of do if utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) or -- {{cite book}}, {{cite encyclopedia}}; TODO: {{cite conference}} and others? ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) or -- {{citation}} as an encylopedia citation ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then -- {{citation}} as a book citation if utilities.is_set (PublicationPlace) then if not utilities.is_set (PublisherName) then local date = COinS_date.rftdate and tonumber (COinS_date.rftdate:match ('%d%d%d%d')); -- get year portion of COinS date (because in Arabic numerals); convert string to number if date and (1850 <= date) then -- location has no publisher; if date is 1850 or later utilities.set_message ('maint_location_no_publisher'); -- add maint cat end else -- PublisherName has a value if cfg.keywords_xlate['none'] == PublisherName then -- if that value is 'none' (only for book and encyclopedia citations) PublisherName = ''; -- unset end end end end local ID_list_t; -- sequence table of rendered identifiers local ID_list_coins_t; -- table of identifiers and their values from args; key is same as cfg.id_handlers's key local Class = A['Class']; -- arxiv class identifier local ID_support = { {A['ASINTLD'], 'ASIN', 'err_asintld_missing_asin', A:ORIGIN ('ASINTLD')}, {DoiBroken, 'DOI', 'err_doibroken_missing_doi', A:ORIGIN ('DoiBroken')}, {Embargo, 'PMC', 'err_embargo_missing_pmc', A:ORIGIN ('Embargo')}, } ID_list_t, ID_list_coins_t = identifiers.identifier_lists_get (args, { DoiBroken = DoiBroken, -- for |doi= ASINTLD = A['ASINTLD'], -- for |asin= Embargo = Embargo, -- for |pmc= Class = Class, -- for |arxiv= CitationClass = config.CitationClass, -- for |arxiv= Year=anchor_year, -- for |isbn= }, ID_support); for _, id in ipairs (ID_list_t) do -- search through the ID_list_t sequence looking for an ISBN identifier string if id:find ('ISBN', 3, true) then -- plain find, start at index 3 ([[ISBN) if 'citation' == config.CitationClass then -- catch ve/citoid malformed book cites in {{citation}} templates if utilities.is_set (Periodical) then -- when a |work= alias is set utilities.set_message ('maint_work_isbn'); -- add maint cat break; -- and abandon end elseif ({['journal'] = true, ['magazine'] = true, ['news'] = true, ['web'] = true})[config.CitationClass] then utilities.set_message ('maint_periodical_has_isbn'); -- add maint cat break; -- and abandon end end end -- if 'citation' == config.CitationClass then -- catch ve/citoid malformed book cites in {{citation}} templates -- for _, id in ipairs (ID_list_t) do -- search through the ID_list_t sequence looking for an ISBN identifier string -- if id:find ('ISBN', 3, true) then -- plain find, start at index 3 ([[ISBN) -- if utilities.is_set (Periodical) then -- when a |work= alias is set -- utilities.set_message ('maint_work_isbn'); -- add maint cat -- end -- end -- end -- end -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, {{cite ssrn}}, before generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv=, |citeseerx=, |medrxiv=, |ssrn= required for their templates if not (args[cfg.id_handlers[config.CitationClass:upper()].parameters[1]] or -- can't use ID_list_coins_t k/v table here because invalid parameters omitted args[cfg.id_handlers[config.CitationClass:upper()].parameters[2]]) then -- which causes unexpected parameter missing error message utilities.set_message ('err_' .. config.CitationClass .. '_missing'); -- add error message end Periodical = ({['arxiv'] = 'arXiv', ['biorxiv'] = 'bioRxiv', ['citeseerx'] = 'CiteSeerX', ['medrxiv'] = 'medRxiv', ['ssrn'] = 'Social Science Research Network'})[config.CitationClass]; end -- Link the title of the work if no |url= was provided, but we have a |pmc= or a |doi= with |doi-access=free if config.CitationClass == "journal" and not utilities.is_set (URL) and not utilities.is_set (TitleLink) and not utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) then -- TODO: remove 'none' once existing citations have been switched to 'off', so 'none' can be used as token for "no title" instead if 'none' ~= cfg.keywords_xlate[auto_select] then -- if auto-linking not disabled if identifiers.auto_link_urls[auto_select] then -- manual selection URL = identifiers.auto_link_urls[auto_select]; -- set URL to be the same as identifier's external link URL_origin = cfg.id_handlers[auto_select:upper()].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['pmc'] then -- auto-select PMC URL = identifiers.auto_link_urls['pmc']; -- set URL to be the same as the PMC external link if not embargoed URL_origin = cfg.id_handlers['PMC'].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['doi'] then -- auto-select DOI URL = identifiers.auto_link_urls['doi']; URL_origin = cfg.id_handlers['DOI'].parameters[1]; end end if utilities.is_set (URL) then -- set when using an identifier-created URL if utilities.is_set (AccessDate) then -- |access-date= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_accessdate_missing_url'); -- add an error message AccessDate = ''; -- unset end if utilities.is_set (ArchiveURL) then -- |archive-url= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_archive_missing_url'); -- add an error message ArchiveURL = ''; -- unset end end end -- At this point fields may be nil if they weren't specified in the template use. We can use that fact. -- Test if citation has no title if not utilities.is_set (Title) and not utilities.is_set (TransTitle) and not utilities.is_set (ScriptTitle) then -- has special case for cite episode utilities.set_message ('err_citation_missing_title', {'episode' == config.CitationClass and 'series' or 'title'}); end if utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) and utilities.in_array (config.CitationClass, {'journal', 'citation'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and ('journal' == Periodical_origin or 'script-journal' == ScriptPeriodical_origin) then -- special case for journal cites Title = ''; -- set title to empty string utilities.set_message ('maint_untitled'); -- add maint cat end if 'journal' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then if is_page_art_num (((utilities.is_set (Page) and Page) or (utilities.is_set (Pages) and Pages)) or nil, ID_list_coins_t['DOI']) then -- does |page(s)= look like it holds an article number utilities.set_message ('maint_page_art_num'); -- add maint cat end end -- COinS metadata (see <http://ocoins.info/>) for automated parsing of citation information. -- handle the oddity that is cite encyclopedia and {{citation |encyclopedia=something}}. Here we presume that -- when Periodical, Title, and Chapter are all set, then Periodical is the book (encyclopedia) title, Title -- is the article title, and Chapter is a section within the article. So, we remap local coins_chapter = Chapter; -- default assuming that remapping not required local coins_title = Title; -- et tu if 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Chapter) and utilities.is_set (Title) and utilities.is_set (Periodical) then -- if all are used then coins_chapter = Title; -- remap coins_title = Periodical; end end local coins_author = a; -- default for coins rft.au if 0 < #c then -- but if contributor list coins_author = c; -- use that instead end -- this is the function call to COinS() local OCinSoutput = metadata.COinS({ ['Periodical'] = utilities.strip_apostrophe_markup (Periodical), -- no markup in the metadata ['Encyclopedia'] = Encyclopedia, -- just a flag; content ignored by ~/COinS ['Chapter'] = metadata.make_coins_title (coins_chapter, ScriptChapter), -- Chapter and ScriptChapter stripped of bold / italic / accept-as-written markup ['Degree'] = Degree; -- cite thesis only ['Title'] = metadata.make_coins_title (coins_title, ScriptTitle), -- Title and ScriptTitle stripped of bold / italic / accept-as-written markup ['PublicationPlace'] = PublicationPlace, ['Date'] = COinS_date.rftdate, -- COinS_date.* has correctly formatted date values if Date is valid; ['Season'] = COinS_date.rftssn, ['Quarter'] = COinS_date.rftquarter, ['Chron'] = COinS_date.rftchron, ['Series'] = Series, ['Volume'] = Volume, ['Issue'] = Issue, ['ArticleNumber'] = ArticleNumber, ['Pages'] = coins_pages or metadata.get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At, QuotePage, QuotePages}, 7)), -- pages stripped of external links ['Edition'] = Edition, ['PublisherName'] = PublisherName or Newsgroup, -- any apostrophe markup already removed from PublisherName ['URL'] = first_set ({ChapterURL, URL}, 2), ['Authors'] = coins_author, ['ID_list'] = ID_list_coins_t, ['RawPage'] = this_page.prefixedText, }, config.CitationClass); -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, and {{cite ssrn}} AFTER generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- we have set rft.jtitle in COinS to arXiv, bioRxiv, CiteSeerX, medRxiv, or ssrn now unset so it isn't displayed Periodical = ''; -- periodical not allowed in these templates; if article has been published, use cite journal end -- special case for cite newsgroup. Do this after COinS because we are modifying Publishername to include some static text if 'newsgroup' == config.CitationClass and utilities.is_set (Newsgroup) then PublisherName = utilities.substitute (cfg.messages['newsgroup'], external_link( 'news:' .. Newsgroup, Newsgroup, Newsgroup_origin, nil )); end local Editors; local EditorCount; -- used only for choosing {ed.) or (eds.) annotation at end of editor name-list local Contributors; -- assembled contributors name list local contributor_etal = nil; -- must be intentionally initialized local Translators; -- assembled translators name list local translator_etal = nil; -- must be intentionally initialized local t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= local Interviewers; local interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters local interviewer_etal = nil; -- must be intentionally initialized -- Now perform various field substitutions. -- We also add leading spaces and surrounding markup and punctuation to the -- various parts of the citation, but only when they are non-nil. do local last_first_list; local control = { format = NameListStyle, -- empty string, '&', 'amp', 'and', or 'vanc' maximum = nil, -- as if display-authors or display-editors not set mode = Mode }; do -- do editor name list first because the now unsupported coauthors used to modify control table local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayEditors'], A['DisplayEditors'], A:ORIGIN ('DisplayEditors'), #e); control.maximum, editor_etal = get_display_names (display_names, #e, editor_etal, param); Editors, EditorCount = list_people (control, e, editor_etal); if 1 == EditorCount and (true == editor_etal or 1 < #e) then -- only one editor displayed but includes etal then EditorCount = 2; -- spoof to display (eds.) annotation end end do -- now do interviewers local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayInterviewers'], A['DisplayInterviewers'], A:ORIGIN ('DisplayInterviewers'), #interviewers_list); control.maximum, interviewer_etal = get_display_names (display_names, #interviewers_list, interviewer_etal, param); Interviewers = list_people (control, interviewers_list, interviewer_etal); end do -- now do translators local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayTranslators'], A['DisplayTranslators'], A:ORIGIN ('DisplayTranslators'), #t); control.maximum, translator_etal = get_display_names (display_names, #t, translator_etal, param); Translators = list_people (control, t, translator_etal); end do -- now do contributors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayContributors'], A['DisplayContributors'], A:ORIGIN ('DisplayContributors'), #c); control.maximum, contributor_etal = get_display_names (display_names, #c, contributor_etal, param); Contributors = list_people (control, c, contributor_etal); end do -- now do authors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayAuthors'], A['DisplayAuthors'], A:ORIGIN ('DisplayAuthors'), #a, author_etal); control.maximum, author_etal = get_display_names (display_names, #a, author_etal, param); last_first_list = list_people (control, a, author_etal); if utilities.is_set (Authors) then Authors, author_etal = name_has_etal (Authors, author_etal, false, 'authors'); -- find and remove variations on et al. if author_etal then Authors = Authors .. ' ' .. cfg.messages['et al']; -- add et al. to authors parameter end else Authors = last_first_list; -- either an author name list or an empty string end end -- end of do if utilities.is_set (Authors) and utilities.is_set (Collaboration) then Authors = utilities.substitute (cfg.messages['collaboration'], {Authors, Collaboration}); -- add collaboration after et al. end end local ConferenceFormat = A['ConferenceFormat']; local ConferenceURL = A['ConferenceURL']; ConferenceFormat = style_format (ConferenceFormat, ConferenceURL, 'conference-format', 'conference-url'); Format = style_format (Format, URL, 'format', 'url'); -- special case for chapter format so no error message or cat when chapter not supported if not (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia))) then ChapterFormat = style_format (ChapterFormat, ChapterURL, 'chapter-format', 'chapter-url'); end if not utilities.is_set (URL) then if utilities.in_array (config.CitationClass, {"web", "podcast", "mailinglist"}) or -- |url= required for {{cite web}}, {{cite podcast}}, and {{cite mailing list}} ('citation' == config.CitationClass and ('website' == Periodical_origin or 'script-website' == ScriptPeriodical_origin)) then -- and required for {{citation}} with |website= or |script-website= if not url_was_archive_today then -- is <URL> empty/missing because it was a deprecated archive.today url utilities.set_message ('err_cite_web_url'); -- no; emit an error message for an empty/ missing |url= end end -- do we have |accessdate= without either |url= or |chapter-url=? if utilities.is_set (AccessDate) and not utilities.is_set (ChapterURL) then -- ChapterURL may be set when URL is not set; utilities.set_message ('err_accessdate_missing_url'); AccessDate = ''; end end local UrlStatus = is_valid_parameter_value (A['UrlStatus'], A:ORIGIN('UrlStatus'), cfg.keywords_lists['url-status'], ''); local OriginalURL local OriginalURL_origin local OriginalFormat local OriginalAccess; UrlStatus = UrlStatus:lower(); -- used later when assembling archived text if utilities.is_set ( ArchiveURL ) then if utilities.is_set (ChapterURL) then -- if chapter-url= is set apply archive url to it OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text OriginalURL_origin = ChapterURL_origin; -- name of |chapter-url= parameter for error messages OriginalFormat = ChapterFormat; -- and original |chapter-format= if 'live' ~= UrlStatus then ChapterURL = ArchiveURL -- swap-in the archive's URL ChapterURL_origin = A:ORIGIN('ArchiveURL') -- name of |archive-url= parameter for error messages ChapterFormat = ArchiveFormat or ''; -- swap in archive's format ChapterUrlAccess = nil; -- restricted access levels do not make sense for archived URLs end elseif utilities.is_set (URL) then OriginalURL = URL; -- save copy of original source URL OriginalURL_origin = URL_origin; -- name of URL parameter for error messages OriginalFormat = Format; -- and original |format= OriginalAccess = UrlAccess; if 'live' ~= UrlStatus then -- if URL set then |archive-url= applies to it URL = ArchiveURL -- swap-in the archive's URL URL_origin = A:ORIGIN('ArchiveURL') -- name of archive URL parameter for error messages Format = ArchiveFormat or ''; -- swap in archive's format UrlAccess = nil; -- restricted access levels do not make sense for archived URLs end end elseif utilities.is_set (UrlStatus) then -- if |url-status= is set when |archive-url= is not set utilities.set_message ('maint_url_status'); -- add maint cat end if utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or -- if any of the 'periodical' cites except encyclopedia ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) then local chap_param; if utilities.is_set (Chapter) then -- get a parameter name from one of these chapter related meta-parameters chap_param = A:ORIGIN ('Chapter') elseif utilities.is_set (TransChapter) then chap_param = A:ORIGIN ('TransChapter') elseif utilities.is_set (ChapterURL) then chap_param = A:ORIGIN ('ChapterURL') elseif utilities.is_set (ScriptChapter) then chap_param = ScriptChapter_origin; else utilities.is_set (ChapterFormat) chap_param = A:ORIGIN ('ChapterFormat') end if utilities.is_set (chap_param) then -- if we found one utilities.set_message ('err_chapter_ignored', {chap_param}); -- add error message Chapter = ''; -- and set them to empty string to be safe with concatenation TransChapter = ''; -- for now, ignore linter warnings ChapterURL = ''; ScriptChapter = ''; ChapterFormat = ''; end else -- otherwise, format chapter / article title local no_quotes = false; -- default assume that we will be quoting the chapter parameter value if utilities.is_set (Contribution) and 0 < #c then -- if this is a contribution with contributor(s) if utilities.in_array (Contribution:lower(), cfg.keywords_lists.contribution) then -- and a generic contribution title no_quotes = true; -- then render it unquoted end end Chapter = format_chapter_title (ScriptChapter, ScriptChapter_origin, Chapter, TransChapter, TransChapter_origin, ChapterURL, ChapterURL_origin, no_quotes, ChapterUrlAccess); -- Contribution is also in Chapter if utilities.is_set (Chapter) then Chapter = Chapter .. ChapterFormat ; if 'map' == config.CitationClass and utilities.is_set (TitleType) then Chapter = Chapter .. ' ' .. TitleType; -- map annotation here; not after title end Chapter = Chapter .. sepc .. ' '; elseif utilities.is_set (ChapterFormat) then -- |chapter= not set but |chapter-format= is so ... Chapter = ChapterFormat .. sepc .. ' '; -- ... ChapterFormat has error message, we want to see it end end -- Format main title local plain_title = false; local accept_title; Title, accept_title = utilities.has_accept_as_written (Title, true); -- remove accept-this-as-written markup when it wraps all of <Title> if accept_title and ('' == Title) then -- only support forced empty for now "(())" Title = cfg.messages['notitle']; -- replace by predefined "No title" message -- TODO: utilities.set_message ( 'err_redundant_parameters', ...); -- issue proper error message instead of muting ScriptTitle = ''; -- just mute for now TransTitle = ''; -- just mute for now plain_title = true; -- suppress text decoration for descriptive title utilities.set_message ('maint_untitled'); -- add maint cat end if not accept_title then -- <Title> not wrapped in accept-as-written markup if '...' == Title:sub (-3) then -- if ellipsis is the last three characters of |title= Title = Title:gsub ('(%.%.%.)%.+$', '%1'); -- limit the number of dots to three elseif not mw.ustring.find (Title, '%.%s*%a%.$') and -- end of title is not a 'dot-(optional space-)letter-dot' initialism ... not mw.ustring.find (Title, '%s+%a%.$') then -- ...and not a 'space-letter-dot' initial (''Allium canadense'' L.) Title = mw.ustring.gsub(Title, '%' .. sepc .. '$', ''); -- remove any trailing separator character; sepc and ms.ustring() here for languages that use multibyte separator characters end if utilities.is_set (ArchiveURL) and is_archived_copy (Title) then utilities.set_message ('maint_archived_copy'); -- add maintenance category before we modify the content of Title end if is_generic ('generic_titles', Title) then utilities.set_message ('err_generic_title'); -- set an error message end end if (not plain_title) and (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'document', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) or ('map' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)))) then -- special case for cite map when the map is in a periodical treat as an article Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from module provided quote marks Title = utilities.wrap_style ('quoted-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); elseif plain_title or ('report' == config.CitationClass) then -- no styling for cite report and descriptive titles (otherwise same as above) Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); -- for cite report, use this form for trans-title else Title = utilities.wrap_style ('italic-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-italic-title', TransTitle); end if utilities.is_set (TransTitle) then if utilities.is_set (Title) then TransTitle = " " .. TransTitle; else utilities.set_message ('err_trans_missing_title', {'title'}); end end if utilities.is_set (Title) then -- TODO: is this the right place to be making Wikisource URLs? if utilities.is_set (TitleLink) and utilities.is_set (URL) then utilities.set_message ('err_wikilink_in_url'); -- set an error message because we can't have both TitleLink = ''; -- unset end if not utilities.is_set (TitleLink) and utilities.is_set (URL) then Title = external_link (URL, Title, URL_origin, UrlAccess) .. TransTitle .. Format; URL = ''; -- unset these because no longer needed Format = ''; -- for now, ignore linter warning elseif utilities.is_set (TitleLink) and not utilities.is_set (URL) then local ws_url; ws_url = wikisource_url_make (TitleLink); -- ignore ws_label return; not used here if ws_url then Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title-link'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], TitleLink, Title}); Title = Title .. TransTitle; else Title = utilities.make_wikilink (TitleLink, Title) .. TransTitle; end else local ws_url, ws_label, L; -- Title has italic or quote markup by the time we get here which causes is_wikilink() to return 0 (not a wikilink) ws_url, ws_label, L = wikisource_url_make (Title:gsub('^[\'"]*(.-)[\'"]*$', '%1')); -- make ws URL from |title= interwiki link (strip italic or quote markup); link portion L becomes tooltip label if ws_url then Title = Title:gsub ('%b[]', ws_label); -- replace interwiki link with ws_label to retain markup Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, Title}); Title = Title .. TransTitle; else Title = Title .. TransTitle; end end else Title = TransTitle; end if utilities.is_set (Place) then Place = " " .. wrap_msg ('written', Place, use_lowercase) .. sepc .. " "; end local ConferenceURL_origin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL if utilities.is_set (Conference) then if utilities.is_set (ConferenceURL) then Conference = external_link( ConferenceURL, Conference, ConferenceURL_origin, nil ); end Conference = sepc .. " " .. Conference .. ConferenceFormat; elseif utilities.is_set (ConferenceURL) then Conference = sepc .. " " .. external_link( ConferenceURL, nil, ConferenceURL_origin, nil ); end local Position = ''; if not utilities.is_set (Position) then local Minutes = A['Minutes']; local Time = A['Time']; if utilities.is_set (Minutes) then if utilities.is_set (Time) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'minutes') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'time')}); end Position = utilities.substitute (cfg.messages.minutes, Minutes); else if utilities.is_set (Time) then local TimeCaption = A['TimeCaption'] if not utilities.is_set (TimeCaption) then TimeCaption = cs2_lower(cfg.messages['event']); end Position = " " .. TimeCaption .. " " .. Time; end end else Position = " " .. Position; At = ''; end Page, Pages, Sheet, Sheets = format_pages_sheets (Page, Pages, Sheet, Sheets, config.CitationClass, Periodical_origin, sepc, NoPP, use_lowercase); At = utilities.is_set (At) and (sepc .. " " .. At) or ""; Position = utilities.is_set (Position) and (sepc .. " " .. Position) or ""; if config.CitationClass == 'map' then local Sections = A['Sections']; -- Section (singular) is an alias of Chapter so set earlier local Inset = A['Inset']; if utilities.is_set ( Inset ) then Inset = sepc .. " " .. wrap_msg ('inset', Inset, use_lowercase); end if utilities.is_set ( Sections ) then Section = sepc .. " " .. wrap_msg ('sections', Sections, use_lowercase); elseif utilities.is_set ( Section ) then Section = sepc .. " " .. wrap_msg ('section', Section, use_lowercase); end At = At .. Inset .. Section; end local Others = A['Others']; if utilities.is_set (Others) and 0 == #a and 0 == #e then -- add maint cat when |others= has value and used without |author=, |editor= if config.CitationClass == "AV-media-notes" or config.CitationClass == "audio-visual" then -- special maint for AV/M which has a lot of 'false' positives right now utilities.set_message ('maint_others_avm') else utilities.set_message ('maint_others'); end end Others = utilities.is_set (Others) and (sepc .. " " .. Others) or ""; if utilities.is_set (Translators) then Others = safe_join ({sepc .. ' ', wrap_msg ('translated', Translators, use_lowercase), Others}, sepc); end if utilities.is_set (Interviewers) then Others = safe_join ({sepc .. ' ', wrap_msg ('interview', Interviewers, use_lowercase), Others}, sepc); end local TitleNote = A['TitleNote']; TitleNote = utilities.is_set (TitleNote) and (sepc .. " " .. TitleNote) or ""; if utilities.is_set (Edition) then if Edition:match ('%f[%a][Ee]d%n?%.?$') or Edition:match ('%f[%a][Ee]dition$') then -- Ed, ed, Ed., ed., Edn, edn, Edn., edn. utilities.set_message ('err_extra_text_edition'); -- add error message end Edition = " " .. wrap_msg ('edition', Edition); else Edition = ''; end Series = utilities.is_set (Series) and wrap_msg ('series', {sepc, Series}) or ""; -- not the same as SeriesNum local Agency = A['Agency'] or ''; -- |agency= is supported by {{cite magazine}}, {{cite news}}, {{cite press release}}, {{cite web}}, and certain {{citation}} templates if utilities.is_set (Agency) then -- this testing done here because {{citation}} supports 'news' citations if utilities.in_array (config.CitationClass, {'magazine', 'news', 'pressrelease', 'web'}) or ('citation' == config.CitationClass and utilities.in_array (Periodical_origin, {"magazine", "newspaper", "work"})) then Agency = wrap_msg ('agency', {sepc, Agency}); -- format for rendering else Agency = ''; -- unset; not supported utilities.set_message ('err_parameter_ignored', {'agency'}); -- add error message end end Volume = format_volume_issue (Volume, Issue, ArticleNumber, config.CitationClass, Periodical_origin, sepc, use_lowercase); if utilities.is_set (AccessDate) then local retrv_text = " " .. cfg.messages['retrieved']; AccessDate = nowrap_date (AccessDate); -- wrap in nowrap span if date in appropriate format retrv_text = cs2_lower(retrv_text); -- if mode is cs2, lower case AccessDate = utilities.substitute (retrv_text, AccessDate); -- add retrieved text AccessDate = utilities.substitute (cfg.presentation['accessdate'], {sepc, AccessDate}); -- allow editors to hide accessdates end if utilities.is_set (ID) then ID = sepc .. " " .. ID; end local Docket = A['Docket']; if "thesis" == config.CitationClass and utilities.is_set (Docket) then ID = sepc .. " Docket " .. Docket .. ID; end if "report" == config.CitationClass and utilities.is_set (Docket) then -- for cite report when |docket= is set ID = sepc .. ' ' .. Docket; -- overwrite ID even if |id= is set end if utilities.is_set (URL) then URL = " " .. external_link( URL, nil, URL_origin, UrlAccess ); end -- We check length of PostScript here because it will have been nuked by -- the quote parameters. We'd otherwise emit a message even if there wasn't -- a displayed postscript. -- TODO: Should the max size (1) be configurable? -- TODO: Should we check a specific pattern? if utilities.is_set(PostScript) and mw.ustring.len(PostScript) > 1 then utilities.set_message ('maint_postscript') end local Archived; if utilities.is_set (ArchiveURL) then if not utilities.is_set (ArchiveDate) then -- ArchiveURL set but ArchiveDate not set utilities.set_message ('err_archive_missing_date'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end else if utilities.is_set (ArchiveDate) then -- ArchiveURL not set but ArchiveDate is set utilities.set_message ('err_archive_date_missing_url'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end end if utilities.is_set (ArchiveURL) then if "live" == UrlStatus then if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cfg.messages['archived-live'], { external_link( ArchiveURL, cs2_lower(cfg.messages['archived']), A:ORIGIN('ArchiveURL'), nil) .. ArchiveFormat, ArchiveDate } ); else Archived = ''; end if not utilities.is_set (OriginalURL) then utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (OriginalURL) then -- UrlStatus is empty, 'dead', 'unfit', 'usurped', 'bot: unknown' if utilities.in_array (UrlStatus, {'unfit', 'usurped', 'bot: unknown'}) then Archived = sepc .. ' ' .. utilities.substitute ( cs2_lower(cfg.messages['archived-unfit']), ArchiveDate); if 'bot: unknown' == UrlStatus then utilities.set_message ('maint_bot_unknown'); -- and add a category if not already added else utilities.add_prop_cat ('unfit'); -- and add a category if not already added end else -- UrlStatus is empty, 'dead' if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cs2_lower(cfg.messages['archived-dead']), { external_link( OriginalURL, cfg.messages['original'], OriginalURL_origin, OriginalAccess ) .. OriginalFormat, ArchiveDate } ); else Archived = ''; -- unset for concatenation end end else -- OriginalUrl not set utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (ArchiveFormat) then Archived = ArchiveFormat; -- if set and ArchiveURL not set ArchiveFormat has error message else Archived = ''; end local TranscriptURL = A['TranscriptURL'] local TranscriptFormat = A['TranscriptFormat']; TranscriptFormat = style_format (TranscriptFormat, TranscriptURL, 'transcript-format', 'transcripturl'); local Transcript = A['Transcript']; local TranscriptURL_origin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL if utilities.is_set (Transcript) then if utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, Transcript, TranscriptURL_origin, nil ); end Transcript = sepc .. ' ' .. Transcript .. TranscriptFormat; elseif utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, nil, TranscriptURL_origin, nil ); end local Publisher; if utilities.is_set (PublicationDate) then PublicationDate = wrap_msg ('published', PublicationDate); end if utilities.is_set (PublisherName) then if utilities.is_set (PublicationPlace) then Publisher = sepc .. " " .. PublicationPlace .. ": " .. PublisherName .. PublicationDate; else Publisher = sepc .. " " .. PublisherName .. PublicationDate; end elseif utilities.is_set (PublicationPlace) then Publisher= sepc .. " " .. PublicationPlace .. PublicationDate; else Publisher = PublicationDate; end -- Several of the above rely upon detecting this as nil, so do it last. if (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical)) then if utilities.is_set (Title) or utilities.is_set (TitleNote) then Periodical = sepc .. " " .. format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); else Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); end end local Language = A['Language']; if utilities.is_set (Language) then Language = language_parameter (Language); -- format, categories, name from ISO639-1, etc. else Language=''; -- language not specified so make sure this is an empty string; --[[ TODO: need to extract the wrap_msg from language_parameter so that we can solve parentheses bunching problem with Format/Language/TitleType ]] end --[[ Handle the oddity that is cite speech. This code overrides whatever may be the value assigned to TitleNote (through |department=) and forces it to be " (Speech)" so that the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided). ]] if "speech" == config.CitationClass then -- cite speech only TitleNote = TitleType; -- move TitleType to TitleNote so that it renders ahead of |event= TitleType = ''; -- and unset if utilities.is_set (Periodical) then -- if Periodical, perhaps because of an included |website= or |journal= parameter if utilities.is_set (Conference) then -- and if |event= is set Conference = Conference .. sepc .. " "; -- then add appropriate punctuation to the end of the Conference variable before rendering end end end -- Piece all bits together at last. Here, all should be non-nil. -- We build things this way because it is more efficient in LUA -- not to keep reassigning to the same string variable over and over. local tcommon; local tcommon2; -- used for book cite when |contributor= is set local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (Periodical) then -- special cases for book cites if utilities.is_set (Contributors) then -- when we are citing foreword, preface, introduction, etc. tcommon = safe_join ({Title, TitleNote}, sepc); -- author and other stuff will come after this and before tcommon2 tcommon2 = safe_join ({TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); else tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); end elseif 'map' == config.CitationClass then -- special cases for cite map if utilities.is_set (Chapter) then -- map in a book; TitleType is part of Chapter tcommon = safe_join ({Title, Edition, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); elseif utilities.is_set (Periodical) then -- map in a periodical tcommon = safe_join ({Title, TitleType, Periodical, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); else -- a sheet or stand-alone map tcommon = safe_join ({Title, TitleType, Edition, Scale, Series, Language, Cartography, Others, Publisher}, sepc); end elseif 'episode' == config.CitationClass then -- special case for cite episode tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Edition, Publisher}, sepc); else -- all other CS1 templates tcommon = safe_join ({Title, TitleNote, Conference, Periodical, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc); end if #ID_list_t > 0 then ID_list_t = safe_join( { sepc .. " ", table.concat( ID_list_t, sepc .. " " ), ID }, sepc ); else ID_list_t = ID; end local Via = A['Via']; Via = utilities.is_set (Via) and wrap_msg ('via', Via) or ''; local idcommon; if 'audio-visual' == config.CitationClass or 'episode' == config.CitationClass then -- special case for cite AV media & cite episode position transcript idcommon = safe_join( { ID_list_t, URL, Archived, Transcript, AccessDate, Via, Quote }, sepc ); else idcommon = safe_join( { ID_list_t, URL, Archived, AccessDate, Via, Quote }, sepc ); end local text; -- local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; local OrigDate = A['OrigDate']; OrigDate = utilities.is_set (OrigDate) and wrap_msg ('origdate', OrigDate) or ''; if utilities.is_set (Date) then if utilities.is_set (Authors) or utilities.is_set (Editors) then -- date follows authors or editors when authors not set Date = " (" .. Date .. ")" .. OrigDate .. sepc .. " "; -- in parentheses else -- neither of authors and editors set if (string.sub(tcommon, -1, -1) == sepc) then -- if the last character of tcommon is sepc Date = " " .. Date .. OrigDate; -- Date does not begin with sepc else Date = sepc .. " " .. Date .. OrigDate; -- Date begins with sepc end end end if utilities.is_set (Authors) then if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Authors termination Authors = terminate_name_list (Authors, sepc); -- when no date, terminate with 0 or 1 sepc and a space end if utilities.is_set (Editors) then local in_text = ''; local post_text; if utilities.is_set (Chapter) and 0 == #c then in_text = cfg.messages['in'] .. ' '; in_text = cs2_lower(in_text); -- lowercase for cs2 end if EditorCount <= 1 then post_text = ' (' .. cfg.messages['editor'] .. ')'; -- be consistent with no-author, no-date case else post_text = ' (' .. cfg.messages['editors'] .. ')'; end Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space end if utilities.is_set (Contributors) then -- book cite and we're citing the intro, preface, etc. local by_text = sepc .. ' ' .. cfg.messages['by'] .. ' '; by_text = cs2_lower(by_text); -- lowercase for cs2 Authors = by_text .. Authors; -- author follows title so tweak it here if utilities.is_set (Editors) and utilities.is_set (Date) then -- when Editors make sure that Authors gets terminated Authors = terminate_name_list (Authors, sepc); -- terminate with 0 or 1 sepc and a space end if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Contributors termination Contributors = terminate_name_list (Contributors, sepc); -- terminate with 0 or 1 sepc and a space end text = safe_join( {Contributors, Date, Chapter, tcommon, Authors, Place, Editors, tcommon2, pgtext, idcommon }, sepc ); else text = safe_join( {Authors, Date, Chapter, Place, Editors, tcommon, pgtext, idcommon }, sepc ); end elseif utilities.is_set (Editors) then if utilities.is_set (Date) then if EditorCount <= 1 then Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editor']; else Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editors']; end else if EditorCount <= 1 then Editors = Editors .. " (" .. cfg.messages['editor'] .. ")" .. sepc .. " " else Editors = Editors .. " (" .. cfg.messages['editors'] .. ")" .. sepc .. " " end end text = safe_join( {Editors, Date, Chapter, Place, tcommon, pgtext, idcommon}, sepc ); else if utilities.in_array (config.CitationClass, {"journal", "citation"}) and utilities.is_set (Periodical) then text = safe_join( {Chapter, Place, tcommon, pgtext, Date, idcommon}, sepc ); else text = safe_join( {Chapter, Place, tcommon, Date, pgtext, idcommon}, sepc ); end end if utilities.is_set (PostScript) and PostScript ~= sepc then text = safe_join( {text, sepc}, sepc ); -- Deals with italics, spaces, etc. if '.' == sepc then -- remove final seperator if present text = text:gsub ('%' .. sepc .. '$', ''); -- dot must be escaped here else text = mw.ustring.gsub (text, sepc .. '$', ''); -- using ustring for non-dot sepc (likely a non-Latin character) end end text = safe_join( {text, PostScript}, sepc ); -- Now enclose the whole thing in a <cite> element local options_t = {}; options_t.class = cite_class_attribute_make (config.CitationClass, Mode); local Ref = is_valid_parameter_value (A['Ref'], A:ORIGIN('Ref'), cfg.keywords_lists['ref'], nil, true); -- nil when |ref=harv; A['Ref'] else if 'none' ~= cfg.keywords_xlate[(Ref and Ref:lower()) or ''] then local namelist_t = {}; -- holds selected contributor, author, editor name list local year = first_set ({Year, anchor_year}, 2); -- Year first for legacy citations and for YMD dates that require disambiguation if #c > 0 then -- if there is a contributor list namelist_t = c; -- select it elseif #a > 0 then -- or an author list namelist_t = a; elseif #e > 0 then -- or an editor list namelist_t = e; end local citeref_id; if #namelist_t > 0 then -- if there are names in namelist_t citeref_id = make_citeref_id (namelist_t, year); -- go make the CITEREF anchor if mw.uri.anchorEncode (citeref_id) == ((Ref and mw.uri.anchorEncode (Ref)) or '') then -- Ref may already be encoded (by {{sfnref}}) so citeref_id must be encoded before comparison utilities.set_message ('maint_ref_duplicates_default'); end else citeref_id = ''; -- unset end options_t.id = Ref or citeref_id; end if string.len (text:gsub('%b<>', '')) <= 2 then -- remove html and html-like tags; then get length of what remains; z.error_cats_t = {}; -- blank the categories list z.error_msgs_t = {}; -- blank the error messages list OCinSoutput = nil; -- blank the metadata string text = ''; -- blank the the citation utilities.set_message ('err_empty_citation'); -- set empty citation message and category end local render_t = {}; -- here we collect the final bits for concatenation into the rendered citation if is_preview_mode and (0 ~= #z.error_msgs_t or 0 ~= #z.maint_cats_t) then -- when in preview mode if not utilities.is_set (options_t.id) then -- and when this template has not created an anchor ID math.randomseed (tonumber (mw.getLanguage ('en'):formatDate ('U')) * 10000 + os.clock() * 10000); options_t.id = 'CITEREF_temp_preview_id_' .. math.random (100000, 999999); -- create temporary anchor ID for preview mode end end if utilities.is_set (options_t.id) then -- here we wrap the rendered citation in <cite ...>...</cite> tags options_t.id = mw.uri.anchorEncode(options_t.id); -- do this here; also used when adding preview warning messages table.insert (render_t, utilities.substitute (cfg.presentation['cite-id'], {options_t.id, mw.text.nowiki(options_t.class), text})); -- when |ref= is set or when there is a namelist else table.insert (render_t, utilities.substitute (cfg.presentation['cite'], {mw.text.nowiki(options_t.class), text})); -- when |ref=none or when namelist_t empty and |ref= is missing or is empty end if OCinSoutput then -- blanked when citation is 'empty' so don't bother to add boilerplate metadata span table.insert (render_t, utilities.substitute (cfg.presentation['ocins'], OCinSoutput)); -- format and append metadata to the citation end local template_name = cfg.citation_class_map_t[config.CitationClass]; local template_link = '[[Template:' .. template_name .. '|' .. template_name .. ']]'; local msg_prefix = '<code class="cs1-code">{{' .. template_link .. '}}</code>: '; if 0 ~= #z.error_msgs_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_e, {template_link, options_t.id})); table.insert (render_t, ' '); -- insert a space between citation and its error messages table.sort (z.error_msgs_t); -- sort the error messages list; sorting includes wrapping <span> and <code> tags; hidden-error sorts ahead of visible-error local hidden = true; -- presume that the only error messages emited by this template are hidden for _, v in ipairs (z.error_msgs_t) do -- spin through the list of error messages if v:find ('cs1-visible-error', 1, true) then -- look for the visible error class name hidden = false; -- found one; so don't hide the error message prefix break; -- and done because no need to look further end end z.error_msgs_t[1] = table.concat ({utilities.error_comment (msg_prefix, hidden), z.error_msgs_t[1]}); -- add error message prefix to first error message to prevent extraneous punctuation table.insert (render_t, table.concat (z.error_msgs_t, '; ')); -- make a big string of error messages and add it to the rendering end if 0 ~= #z.maint_cats_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_m, {template_link, options_t.id})); table.sort (z.maint_cats_t); -- sort the maintenance messages list local maint_msgs_t = {}; -- here we collect all of the maint messages if 0 == #z.error_msgs_t then -- if no error messages table.insert (maint_msgs_t, msg_prefix); -- insert message prefix in maint message livery end for _, v in ipairs( z.maint_cats_t ) do -- append maintenance categories table.insert (maint_msgs_t, -- assemble new maint message and add it to the maint_msgs_t table table.concat ({v, ' (', utilities.substitute (cfg.messages[':cat wikilink'], v), ')'}) ); end table.insert (render_t, utilities.substitute (cfg.presentation['hidden-maint'], table.concat (maint_msgs_t, ' '))); -- wrap the group of maint messages with proper presentation and save end if not no_tracking_cats then local sort_key; local cat_wikilink = 'cat wikilink'; if cfg.enable_sort_keys then -- when namespace sort keys enabled local namespace_number = mw.title.getCurrentTitle().namespace; -- get namespace number for this wikitext sort_key = (0 ~= namespace_number and (cfg.name_space_sort_keys[namespace_number] or cfg.name_space_sort_keys.other)) or nil; -- get sort key character; nil for mainspace cat_wikilink = (not sort_key and 'cat wikilink') or 'cat wikilink sk'; -- make <cfg.messages> key end for _, v in ipairs (z.error_cats_t) do -- append error categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end if cfg.id_limits_data_load_fail then -- boolean true when load failed utilities.set_message ('maint_id_limit_load_fail'); -- done here because this maint cat emits no message end for _, v in ipairs (z.maint_cats_t) do -- append maintenance categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end for _, v in ipairs (z.prop_cats_t) do -- append properties categories table.insert (render_t, utilities.substitute (cfg.messages['cat wikilink'], v)); -- no sort keys end end return table.concat (render_t); -- make a big string and done end --[[--------------------------< V A L I D A T E >-------------------------------------------------------------- Looks for a parameter's name in one of several whitelists. Parameters in the whitelist can have three values: true - active, supported parameters false - deprecated, supported parameters nil - unsupported parameters ]] local function validate (name, cite_class, empty) local enum_name; -- parameter name with enumerator (if any) replaced with '#' local state; local function state_test () -- local function to do testing of state values; operates on the upvalues <state> and <name> if true == state then return true; end -- valid actively supported parameter if false == state then if empty then return nil; end -- empty deprecated parameters are treated as unknowns deprecated_parameter (name); -- parameter is deprecated but still supported return true; end if 'tracked' == state then local base_name = name:gsub ('%d', ''); -- strip enumerators from parameter names that have them to get the base name utilities.add_prop_cat ('tracked-param', {base_name}, base_name); -- add a properties category; <base_name> modifies <key> return true; end return nil; end if 'string' ~= type (name) or name:find ('#') then -- # is a cs1|2 reserved character so parameters with # not permitted; positional params are 'number' type; not supported return nil; end -- replace enumerator digit(s) with # (|last25= becomes |last#=) (mw.ustring because non-Western 'local' digits) enum_name = mw.ustring.gsub (name, '%d+$', '#'); -- where enumerator is last charaters in parameter name (these to protect |s2cid=) enum_name = mw.ustring.gsub (enum_name, '%d+([%-l])', '#%1'); -- where enumerator is in the middle of the parameter name; |author#link= is the oddity if 'document' == cite_class then -- special case for {{cite document}} state = whitelist.document_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test () then return true; end return false; end if utilities.in_array (cite_class, whitelist.preprint_template_list_t) then -- limited parameter sets allowed for these templates state = whitelist.limited_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test () then return true; end state = whitelist.preprint_arguments_t[cite_class][name]; -- look in the parameter-list for the template identified by cite_class if true == state_test () then return true; end return false; -- not supported because not found or name is set to nil end -- end limited parameter-set templates if utilities.in_array (cite_class, whitelist.unique_param_template_list_t) then -- template-specific parameters for templates that accept parameters from the basic argument list state = whitelist.unique_arguments_t[cite_class][name]; -- look in the template-specific parameter-lists for the template identified by cite_class if true == state_test () then return true; end end -- if here, fall into general validation state = whitelist.common_parameters_t[enum_name]; -- all other templates; all normal parameters allowed; this list holds enumerated and nonenumerated parameters if true == state_test () then return true; end return false; -- not supported because not found or name is set to nil end --[=[-------------------------< I N T E R _ W I K I _ C H E C K >---------------------------------------------- check <value> for inter-language interwiki-link markup. <prefix> must be a MediaWiki-recognized language code. when these values have the form (without leading colon): [[<prefix>:link|label]] return label as plain-text [[<prefix>:link]] return <prefix>:link as plain-text return value as is else ]=] local function inter_wiki_check (parameter, value) local prefix = value:match ('%[%[(%a+):'); -- get an interwiki prefix if one exists local _; if prefix and cfg.inter_wiki_map[prefix:lower()] then -- if prefix is in the map, needs preceding colon so utilities.set_message ('err_bad_paramlink', parameter); -- emit an error message _, value, _ = utilities.is_wikilink (value); -- extract label portion from wikilink end return value; end --[[--------------------------< M I S S I N G _ P I P E _ C H E C K >------------------------------------------ Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal sign, compare the alphanumeric string to the list of cs1|2 parameters. If found, then the string is possibly a parameter that is missing its pipe. There are two tests made: {{cite ... |title=Title access-date=2016-03-17}} -- the first parameter has a value and whitespace separates that value from the missing pipe parameter name {{cite ... |title=access-date=2016-03-17}} -- the first parameter has no value (whitespace after the first = is trimmed by MediaWiki) cs1|2 shares some parameter names with XML/HTML attributes: class=, title=, etc. To prevent false positives XML/HTML tags are removed before the search. If a missing pipe is detected, this function adds the missing pipe maintenance category. ]] local function missing_pipe_check (parameter, value) local capture; value = value:gsub ('%b<>', ''); -- remove XML/HTML tags because attributes: class=, title=, etc. capture = value:match ('%s+(%a[%w%-]+)%s*=') or value:match ('^(%a[%w%-]+)%s*='); -- find and categorize parameters with possible missing pipes if capture and validate (capture) then -- if the capture is a valid parameter name utilities.set_message ('err_missing_pipe', parameter); end end --[[--------------------------< H A S _ E X T R A N E O U S _ P U N C T >-------------------------------------- look for extraneous terminal punctuation in most parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_punc (param, value) if 'number' == type (param) then return; end param = param:gsub ('%d+', '#'); -- enumerated name-list mask params allow terminal punct; normalize if cfg.punct_skip[param] then return; -- parameter name found in the skip table so done end if value:match ('[,;:]$') then utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end if value:match ('^=') then -- sometimes an extraneous '=' character appears ... utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end end --[[--------------------------< H A S _ T W L _ U R L >-------------------------------------------------------- look for The Wikipedia Library urls in url-holding parameters. TWL urls are accessible only for readers who are active extended confirmed Wikipedia editors. This function sets an error message when such urls are discovered and when appropriate, sets the |<param>-url-access=subscription. returns nothing. looks for: '.wikipedialibrary.idm.oclc.org' ]] local function has_twl_url (url_params_t, cite_args_t) local url_error_t = {}; -- sequence of url-holding parameters that have a TWL url for param, value in pairs (url_params_t) do if value:find ('%.wikipedialibrary%.idm%.oclc%.org') then -- has the TWL base url? table.insert (url_error_t, param); -- add parameter name to the error list end end if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); -- sor for error messaging for i, param in ipairs (url_error_t) do if cfg.url_access_map_t[param] then -- if <param> has a matching -access parameter cite_args_t[cfg.url_access_map_t[param]] = cfg.keywords_xlate.subscription; -- set |<param>-url-access=subscription end url_error_t[i] = utilities.wrap_style ('parameter', param); -- make the parameter pretty for error message end utilities.set_message ('err_param_has_twl_url', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< M I S C _ U R L _ D E T E C T >------------------------------------------------ look for miscellaneous urls that might be converted to, or are duplicates of, identifiers. ]] local misc_url_patterns_t = { 'idm%.oclc%.org', -- but not wikipedialibrary.idm.oclc.org; has_twl_url() 'https?://citeseerx?%.ist%.psu%.edu/', -- simplified so we catch all citeseer and citeseerx urls except ~/document/... (the 'new' form) } local ignore_patterns_t = { 'wikipedialibrary.idm.oclc.org', -- handled by has_twl_url() 'https?://citeseerx?%.ist%.psu%.edu/document', -- 'new'-form citeseerx urls that mostly work; ignore for now } local function misc_url_detect (url_params_t) local ignore_flag = false; for _, value in pairs (url_params_t) do for _, ignore_pattern in ipairs (ignore_patterns_t) do if value:find (ignore_pattern) then -- matches this ignore_pattern? ignore_flag = true; -- found a pattern to ignore break; -- end end if not ignore_flag then -- if ignore_flag is set then don't bother to test this url <value> for _, misc_pattern in ipairs (misc_url_patterns_t) do if value:find (misc_pattern) then -- matches this misc_pattern? utilities.set_message ('maint_misc_url'); -- found one; set the message return; -- and done; no need to test other <value>s end end end ignore_flag = false; -- reset end end --[[--------------------------< H A S _ E X T R A N E O U S _ U R L >------------------------------------------ look for extraneous url parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_url (non_url_param_t) local url_error_t = {}; check_for_url (non_url_param_t, url_error_t); -- extraneous url check if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); utilities.set_message ('err_param_has_ext_link', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< _ C I T A T I O N >------------------------------------------------------------ Module entry point frame – from template call (citation()); may be nil when called from another module args_t – table of all cs1|2 parameters in the template (the parent frame) config_t – table of template-supplied parameter (the #invoke frame) ]] local function _citation (frame, args_t, config_t) -- save a copy in case we need to display an error message in preview mode if not frame then frame = mw.getCurrentFrame(); -- if called from another module, get a frame for frame-provided functions end -- i18n: set the name that your wiki uses to identify sandbox subpages from sandbox template invoke (or can be set here) local sandbox = ((config_t.SandboxPath and '' ~= config_t.SandboxPath) and config_t.SandboxPath) or '/sandbox'; -- sandbox path from {{#invoke:Citation/CS1/sandbox|citation|SandboxPath=/...}} is_sandbox = nil ~= string.find (frame:getTitle(), sandbox, 1, true); -- is this invoke the sandbox module? sandbox = is_sandbox and sandbox or ''; -- use i18n sandbox to load sandbox modules when this module is the sandox; live modules else cfg = mw.loadData ('Module:Citation/CS1/Configuration' .. sandbox); -- load sandbox versions of support modules when {{#invoke:Citation/CS1/sandbox|...}}; live modules else whitelist = mw.loadData ('Module:Citation/CS1/Whitelist' .. sandbox); utilities = require ('Module:Citation/CS1/Utilities' .. sandbox); validation = require ('Module:Citation/CS1/Date_validation' .. sandbox); identifiers = require ('Module:Citation/CS1/Identifiers' .. sandbox); metadata = require ('Module:Citation/CS1/COinS' .. sandbox); utilities.set_selected_modules (cfg); -- so that functions in Utilities can see the selected cfg tables identifiers.set_selected_modules (cfg, utilities); -- so that functions in Identifiers can see the selected cfg tables and selected Utilities module validation.set_selected_modules (cfg, utilities); -- so that functions in Date validataion can see selected cfg tables and the selected Utilities module metadata.set_selected_modules (cfg, utilities); -- so that functions in COinS can see the selected cfg tables and selected Utilities module z = utilities.z; -- table of error and category tables in Module:Citation/CS1/Utilities local cite_args_t = {}; -- because args_t is the parent (template) frame args (which cannot be modified); params and their values will be placed here is_preview_mode = not utilities.is_set (frame:preprocess ('{{REVISIONID}}')); local suggestions = {}; -- table where we store suggestions if we need to loadData them local error_text; -- used as a flag local capture; -- the single supported capture when matching unknown parameters using patterns local empty_unknowns = {}; -- sequence table to hold empty unknown params for error message listing for k, v in pairs (args_t) do -- get parameters from the parent (template) frame v = mw.ustring.gsub (v, '^%s*(.-)%s*$', '%1'); -- trim leading/trailing whitespace; when v is only whitespace, becomes empty string if v ~= '' then if cfg.enum_needs_xlation and 'string' == type (k) then -- for wikis that set date_names['local_digits'] to non-western digits k = mw.ustring.gsub (k, '%d', cfg.date_names.local_digits); -- translate 'local' digits enumerators to Western 0-9 end if not validate( k, config_t.CitationClass ) then if type (k) ~= 'string' then -- exclude empty numbered parameters if v:match("%S+") ~= nil then error_text = utilities.set_message ('err_text_ignored', {v}); end elseif validate (k:lower(), config_t.CitationClass) then error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, k:lower()}); -- suggest the lowercase version of the parameter else if nil == suggestions.suggestions then -- if this table is nil then we need to load it suggestions = mw.loadData ('Module:Citation/CS1/Suggestions' .. sandbox); --load sandbox version of suggestion module when {{#invoke:Citation/CS1/sandbox|...}}; live module else end for pattern, param in pairs (suggestions.patterns) do -- loop through the patterns to see if we can suggest a proper parameter capture = k:match (pattern); -- the whole match if no capture in pattern else the capture if a match if capture then -- if the pattern matches param = utilities.substitute (param, capture); -- add the capture to the suggested parameter (typically the enumerator) if validate (param, config_t.CitationClass) then -- validate the suggestion to make sure that the suggestion is supported by this template (necessary for limited parameter lists) error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, param}); -- set the suggestion error message else error_text = utilities.set_message ('err_parameter_ignored', {k}); -- suggested param not supported by this template v = ''; -- unset end end end if not utilities.is_set (error_text) then -- couldn't match with a pattern, is there an explicit suggestion? if (suggestions.suggestions[ k:lower() ] ~= nil) and validate (suggestions.suggestions[ k:lower() ], config_t.CitationClass) then utilities.set_message ('err_parameter_ignored_suggest', {k, suggestions.suggestions[ k:lower() ]}); else utilities.set_message ('err_parameter_ignored', {k}); v = ''; -- unset value assigned to unrecognized parameters (this for the limited parameter lists) end end end end cite_args_t[k] = v; -- save this parameter and its value elseif not utilities.is_set (v) then -- for empty parameters if not validate (k, config_t.CitationClass, true) then -- is this empty parameter a valid parameter k = ('' == k) and cfg.err_msg_supl.empty_str or k; -- when k is empty string (or was space(s) trimmed to empty string), replace with descriptive text table.insert (empty_unknowns, utilities.wrap_style ('parameter', k)); -- format for error message and add to the list end end end if 0 ~= #empty_unknowns then -- create empty unknown error message utilities.set_message ('err_param_unknown_empty', { 1 == #empty_unknowns and '' or 's', utilities.make_sep_list (#empty_unknowns, empty_unknowns) }); end local non_url_param_t = {}; -- table of parameters and values that are not url-holding parameters local url_param_t = {}; -- table of url-holding paramters and their values for k, v in pairs (cite_args_t) do if 'string' == type (k) then -- don't evaluate positional parameters has_invisible_chars (k, v); -- look for invisible characters end has_extraneous_punc (k, v); -- look for extraneous terminal punctuation in parameter values missing_pipe_check (k, v); -- do we think that there is a parameter that is missing a pipe? cite_args_t[k] = inter_wiki_check (k, v); -- when language interwiki-linked parameter missing leading colon replace with wiki-link label if 'string' == type (k) then -- when parameter k is not positional if not cfg.url_skip[k] then -- and not in url skip table non_url_param_t[k] = v; -- make a parameter/value list for extraneous url check else -- and is in url skip table (a url-holding parameter) url_param_t[k] = v; -- make a parameter/value list to check for values that are The Wikipedia Library url end end end if cfg.suppress_archive_today_urls then has_archive_today_url (cite_args_t); -- look for and suppress archive.today urls and dependent parameters for all templates end has_extraneous_url (non_url_param_t); -- look for url in parameter values where a url does not belong has_twl_url (url_param_t, cite_args_t); -- look for url-holding parameters that hold a The Wikipedia Library url misc_url_detect (url_param_t); -- look for url-holding parameters that hold certain miscellaneous urls return table.concat ({ frame:extensionTag ('templatestyles', '', {src='Module:Citation/CS1' .. sandbox .. '/styles.css'}), citation0 (config_t, cite_args_t) }); end --[[--------------------------< C I T A T I O N >-------------------------------------------------------------- Template entry point ]] local function citation (frame) local config_t = {}; -- table to store parameters from the module {{#invoke:}} local args_t = frame:getParent().args; -- get template's preset parameters for k, v in pairs (frame.args) do -- get parameters from the {{#invoke}} frame config_t[k] = v; -- args_t[k] = v; -- crude debug support that allows us to render a citation from module {{#invoke:}}; skips parameter validation; TODO: keep? end return _citation (frame, args_t, config_t) end --[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------ ]] return { citation = citation, -- template entry point _citation = _citation, -- module entry point } mzkfjlhyhvftcb93lj0ik7zu7t1myhw 736705 736704 2026-10-07T14:40:41Z King ChristLike 13051 1 revision imported from [[:en:Module:Citation/CS1]] 736704 Scribunto text/plain require ('strict'); --[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- each of these counts against the Lua upvalue limit ]] local validation; -- functions in Module:Citation/CS1/Date_validation local utilities; -- functions in Module:Citation/CS1/Utilities local z = {}; -- table of tables in Module:Citation/CS1/Utilities local identifiers; -- functions and tables in Module:Citation/CS1/Identifiers local metadata; -- functions in Module:Citation/CS1/COinS local cfg = {}; -- table of configuration tables that are defined in Module:Citation/CS1/Configuration local whitelist = {}; -- table of tables listing valid template parameter names; defined in Module:Citation/CS1/Whitelist --[[------------------< P A G E S C O P E V A R I A B L E S >--------------- declare variables here that have page-wide scope that are not brought in from other modules; that are created here and used here ]] local added_deprecated_cat; -- boolean flag so that the category is added only once local added_vanc_errs; -- boolean flag so we only emit one Vancouver error / category local added_generic_name_errs; -- boolean flag so we only emit one generic name error / category and stop testing names once an error is encountered local added_numeric_name_errs; -- boolean flag so we only emit one numeric name error / category and stop testing names once an error is encountered local added_numeric_name_maint; -- boolean flag so we only emit one numeric name maint category and stop testing names once a category has been emitted local is_preview_mode; -- true when article is in preview mode; false when using 'Preview page with this template' (previewing the module) local is_sandbox; -- true when using sandbox modules to render citation local url_was_archive_today; -- boolean flag set to true when has_archive_today_url() has unset |url= because it held a deprecated archive.today url --[[--------------------------< F I R S T _ S E T >------------------------------------------------------------ Locates and returns the first set value in a table of values where the order established in the table, left-to-right (or top-to-bottom), is the order in which the values are evaluated. Returns nil if none are set. This version replaces the original 'for _, val in pairs do' and a similar version that used ipairs. With the pairs version the order of evaluation could not be guaranteed. With the ipairs version, a nil value would terminate the for-loop before it reached the actual end of the list. ]] local function first_set (list, count) local i = 1; while i <= count do -- loop through all items in list if utilities.is_set( list[i] ) then return list[i]; -- return the first set list member end i = i + 1; -- point to next end end --[[--------------------------< A D D _ V A N C _ E R R O R >---------------------------------------------------- Adds a single Vancouver system error message to the template's output regardless of how many error actually exist. To prevent duplication, added_vanc_errs is nil until an error message is emitted. added_vanc_errs is a Boolean declared in page scope variables above ]] local function add_vanc_error (source, position) if added_vanc_errs then return end added_vanc_errs = true; -- note that we've added this category utilities.set_message ('err_vancouver', {source, position}); end --[[--------------------------< I S _ S C H E M E >------------------------------------------------------------ does this thing that purports to be a URI scheme seem to be a valid scheme? The scheme is checked to see if it is in agreement with http://tools.ietf.org/html/std66#section-3.1 which says: Scheme names consist of a sequence of characters beginning with a letter and followed by any combination of letters, digits, plus ("+"), period ("."), or hyphen ("-"). returns true if it does, else false ]] local function is_scheme (scheme) return scheme and scheme:match ('^%a[%a%d%+%.%-]*:'); -- true if scheme is set and matches the pattern end --[=[-------------------------< I S _ D O M A I N _ N A M E >-------------------------------------------------- Does this thing that purports to be a domain name seem to be a valid domain name? Syntax defined here: http://tools.ietf.org/html/rfc1034#section-3.5 BNF defined here: https://tools.ietf.org/html/rfc4234 Single character names are generally reserved; see https://tools.ietf.org/html/draft-ietf-dnsind-iana-dns-01#page-15; see also [[Single-letter second-level domain]] list of TLDs: https://www.iana.org/domains/root/db RFC 952 (modified by RFC 1123) requires the first and last character of a hostname to be a letter or a digit (see http://tools.ietf.org/html/rfc952 §GRAMMATICAL HOST TABLE SPECIFICATION §§B. Lexical grammar <name>; see http://tools.ietf.org/html/rfc1123#section-2). Between the first and last characters the name may use letters, digits, and the hyphen. Also allowed are IPv4 addresses. IPv6 not supported domain is expected to be stripped of any path so that the last character in the last character of the TLD. tld is two or more alpha characters. Any preceding '//' (from splitting a URL with a scheme) will be stripped here. Perhaps not necessary but retained in case it is necessary for IPv4 dot decimal. There are several tests: the first character of the whole domain name including subdomains must be a letter or a digit internationalized domain name (ASCII characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the TLD) see https://tools.ietf.org/html/rfc3490 single-letter/digit second-level domains in the .org, .cash, and .today TLDs q, x, and z SL domains in the .com TLD i and q SL domains in the .net TLD single-letter SL domains in the ccTLDs (where the ccTLD is two letters) two-character SL domains in gTLDs (where the gTLD is two or more letters) three-plus-character SL domains in gTLDs (where the gTLD is two or more letters) IPv4 dot-decimal address format; TLD not allowed returns true if domain appears to be a proper name and TLD or IPv4 address, else false ]=] local function is_domain_name (domain) if not domain then return false; -- if not set, abandon end domain = domain:gsub ('^//', ''); -- strip '//' from domain name if present; done here so we only have to do it once local sl_domain = domain:match ('[^%.]+') or domain; -- test the second level domain name if not (sl_domain:match ('^%w') and sl_domain:match ('%w$') and -- first and last characters must be letter or digit sl_domain:match ('^[%w%-]+$')) then -- all other characters must be letters, digits, or hyphen-minus return false; end if domain:match ('^%a+:') then -- hack to detect things that look like s:Page:Title where Page: is namespace at Wikisource return false; end local patterns = { -- patterns that look like URLs '%f[%w][%w][%w%-]+[%w]%.%a%a+$', -- three or more character hostname.hostname or hostname.tld '%f[%w][%w][%w%-]+[%w]%.xn%-%-[%w]+$', -- internationalized domain name with ACE prefix '%f[%a][qxz]%.com$', -- assigned one character .com hostname (x.com times out 2015-12-10) '%f[%a][iq]%.net$', -- assigned one character .net hostname (q.net registered but not active 2015-12-10) '%f[%w][%w]%.%a%a$', -- one character hostname and ccTLD (2 chars) '%f[%w][%w][%w]%.%a%a+$', -- two character hostname and TLD '^%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?', -- IPv4 address '[%a%d]+%:?' -- IPv6 address } for _, pattern in ipairs (patterns) do -- loop through the patterns list if domain:match (pattern) then return true; -- if a match then we think that this thing that purports to be a URL is a URL end end for _, d in ipairs (cfg.single_letter_2nd_lvl_domains_t) do -- look for single letter second level domain names for these top level domains if domain:match ('%f[%w][%w]%.' .. d) then return true end end return false; -- no matches, we don't know what this thing is end --[[--------------------------< I S _ U R L >------------------------------------------------------------------ returns true if the scheme and domain parts of a URL appear to be a valid URL; else false. This function is the last step in the validation process. This function is separate because there are cases that are not covered by split_url(), for example is_parameter_ext_wikilink() which is looking for bracketted external wikilinks. ]] local function is_url (scheme, domain) if utilities.is_set (scheme) then -- if scheme is set check it and domain return is_scheme (scheme) and is_domain_name (domain); else return is_domain_name (domain); -- scheme not set when URL is protocol-relative end end --[[--------------------------< S P L I T _ U R L >------------------------------------------------------------ Split a URL into a scheme, authority indicator, and domain. First remove Fully Qualified Domain Name terminator (a dot following TLD) (if any) and any path(/), query(?) or fragment(#). If protocol-relative URL, return nil scheme and domain else return nil for both scheme and domain. When not protocol-relative, get scheme, authority indicator, and domain. If there is an authority indicator (one or more '/' characters immediately following the scheme's colon), make sure that there are only 2. Any URL that does not have news: scheme must have authority indicator (//). TODO: are there other common schemes like news: that don't use authority indicator? Strip off any port and path; ]] local function split_url (url_str) local scheme, authority, domain; url_str = url_str:gsub ('([%a%d])%.?[/%?#].*$', '%1'); -- strip FQDN terminator and path(/), query(?), fragment (#) (the capture prevents false replacement of '//') if url_str:match ('^//%S*') then -- if there is what appears to be a protocol-relative URL domain = url_str:match ('^//(%S*)') elseif url_str:match ('%S-:/*%S+') then -- if there is what appears to be a scheme, optional authority indicator, and domain name scheme, authority, domain = url_str:match ('(%S-:)(/*)(%S+)'); -- extract the scheme, authority indicator, and domain portions if utilities.is_set (authority) then authority = authority:gsub ('//', '', 1); -- replace place 1 pair of '/' with nothing; if utilities.is_set(authority) then -- if anything left (1 or 3+ '/' where authority should be) then return scheme; -- return scheme only making domain nil which will cause an error message end else if not scheme:match ('^news:') then -- except for news:..., MediaWiki won't link URLs that do not have authority indicator; TODO: a better way to do this test? return scheme; -- return scheme only making domain nil which will cause an error message end end domain = domain:gsub ('(%a):%d+', '%1'); -- strip port number if present end return scheme, domain; end --[[--------------------------< L I N K _ P A R A M _ O K >--------------------------------------------------- checks the content of |title-link=, |series-link=, |author-link=, etc. for properly formatted content: no wikilinks, no URLs Link parameters are to hold the title of a Wikipedia article, so none of the WP:TITLESPECIALCHARACTERS are allowed: # < > [ ] | { } _ except the underscore which is used as a space in wiki URLs and # which is used for section links returns false when the value contains any of these characters. When there are no illegal characters, this function returns TRUE if value DOES NOT appear to be a valid URL (the |<param>-link= parameter is ok); else false when value appears to be a valid URL (the |<param>-link= parameter is NOT ok). ]] local function link_param_ok (value) local scheme, domain; if value:find ('[<>%[%]|{}]') then -- if any prohibited characters return false; end scheme, domain = split_url (value); -- get scheme or nil and domain or nil from URL; return not is_url (scheme, domain); -- return true if value DOES NOT appear to be a valid URL end --[[--------------------------< L I N K _ T I T L E _ O K >--------------------------------------------------- Use link_param_ok() to validate |<param>-link= value and its matching |<title>= value. |<title>= may be wiki-linked but not when |<param>-link= has a value. This function emits an error message when that condition exists check <link> for inter-language interwiki-link prefix. prefix must be a MediaWiki-recognized language code and must begin with a colon. ]] local function link_title_ok (link, lorig, title, torig) local orig; if utilities.is_set (link) then -- don't bother if <param>-link doesn't have a value if not link_param_ok (link) then -- check |<param>-link= markup orig = lorig; -- identify the failing link parameter elseif title:find ('%[%[') then -- check |title= for wikilink markup orig = torig; -- identify the failing |title= parameter elseif link:match ('^%a+:') then -- if the link is what looks like an interwiki local prefix = link:match ('^(%a+):'):lower(); -- get the interwiki prefix if cfg.inter_wiki_map[prefix] then -- if prefix is in the map, must have preceding colon orig = lorig; -- flag as error end end end if utilities.is_set (orig) then link = ''; -- unset utilities.set_message ('err_bad_paramlink', orig); -- URL or wikilink in |title= with |title-link=; end return link; -- link if ok, empty string else end --[[--------------------------< C H E C K _ U R L >------------------------------------------------------------ Determines whether a URL string appears to be valid. First we test for space characters. If any are found, return false. Then split the URL into scheme and domain portions, or for protocol-relative (//example.com) URLs, just the domain. Use is_url() to validate the two portions of the URL. If both are valid, or for protocol-relative if domain is valid, return true, else false. Because it is different from a standard URL, and because this module used external_link() to make external links that work for standard and news: links, we validate newsgroup names here. The specification for a newsgroup name is at https://tools.ietf.org/html/rfc5536#section-3.1.4 ]] local function check_url( url_str ) if nil == url_str:match ("^%S+$") then -- if there are any spaces in |url=value it can't be a proper URL return false; end local scheme, domain; scheme, domain = split_url (url_str); -- get scheme or nil and domain or nil from URL; if 'news:' == scheme then -- special case for newsgroups return domain:match('^[%a%d%+%-_]+%.[%a%d%+%-_%.]*[%a%d%+%-_]$'); end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[=[-------------------------< I S _ P A R A M E T E R _ E X T _ W I K I L I N K >---------------------------- Return true if a parameter value has a string that begins and ends with square brackets [ and ] and the first non-space characters following the opening bracket appear to be a URL. The test will also find external wikilinks that use protocol-relative URLs. Also finds bare URLs. The frontier pattern prevents a match on interwiki-links which are similar to scheme:path URLs. The tests that find bracketed URLs are required because the parameters that call this test (currently |title=, |chapter=, |work=, and |publisher=) may have wikilinks and there are articles or redirects like '//Hus' so, while uncommon, |title=[[//Hus]] is possible as might be [[en://Hus]]. ]=] local function is_parameter_ext_wikilink (value) local scheme, domain; if value:match ('%f[%[]%[%a%S*:%S+.*%]') then -- if ext. wikilink with scheme and domain: [xxxx://yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(%a%S*:%S+).*%]')); elseif value:match ('%f[%[]%[//%S+.*%]') then -- if protocol-relative ext. wikilink: [//yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(//%S+).*%]')); elseif value:match ('%a%S*:%S+') then -- if bare URL with scheme; may have leading or trailing plain text scheme, domain = split_url (value:match ('(%a%S*:%S+)')); elseif value:match ('^//%S+') or value:match ('%s//%S+') then -- if protocol-relative bare URL: //yyyyy.zzz; authority indicator (//) must be be preceded nothing or by whitespace scheme, domain = split_url (value:match ('(//%S+)')); -- what is left should be the domain else return false; -- didn't find anything that is obviously a URL end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[[--------------------------< I S _ A R C H I V E _ T O D A Y _ U R L >-------------------------------------- archive.today (and .ph, .is, .md, .li, .fo, .vn) are deprecated. See Wikipedia:Requests_for_comment/Archive.is_RFC_5 (Special:Permalink/1339352976) <val> is a string that may or may not be a url ]] local function is_archive_today_url (val) if is_parameter_ext_wikilink (val) then -- is <val> a url? local tld = val:match ('archive%.(%l+)/'); -- get the tld; real archive.today urls have a '/' after the tld return tld and cfg.archive_today_tlds_t[tld]; -- return true if <tld> is one of the archive.today tlds; nil else end end --[[--------------------------< H A S _ A R C H I V E _ T O D A Y _ U R L >------------------------------------ blank any parameter that holds one of the archive.today tlds (.today, .ph, .is, .md, .li, .fo, .vn) and also blank parameters that are dependent on the offending parameter. input <cite_args_t> is a table of all of this template's parameters This function modifies <cite_args_t> when |url= or its alias |URL= hold an archive.today url, this function sets the flag <url_was_archive_today> which is used later to suppress the missing url error message from {{citation}} when it has |website=<summat> or from the templates {{cite web}}, {{cite podcast}}, {{cite mailing list}} which all require a url. returns nothing ]] local function has_archive_today_url (cite_args_t) local unset_params_t = {}; -- to hold a sequence of parameters to unset from cite_args_t for p, v in pairs (cite_args_t) do -- look at each parameter in the template if is_archive_today_url (v:lower()) then -- if it has a parameter with an archive.today url table.insert (unset_params_t, p); -- add the url-holding parameter name to our list of parameters to unset (may or may not be a legitimate url parameter) if 'url' == p:lower() then -- if this parameter is |url= or |URL= url_was_archive_today = true; -- set a flag so that cite web / podcast / mailinglist don't emit a missing url error message end if p:match ('archive%-?url') and ('usurped' == cite_args_t['url-status'] or 'unfit' == cite_args_t['url-status']) then -- if |archive-url=archive.today and |url-status=unfit/usurped url_was_archive_today = true; -- set a flag so that cite web / podcast / mailinglist don't emit a missing url error message table.insert (unset_params_t, 'url'); -- add the url parameter name to our list of parameters to unset (may or may not be a legitimate url parameter) table.insert (unset_params_t, 'URL'); -- this one because both are possible end if cfg.dependencies_t[p] then -- if this url-holding parameter (<p>) has dependencies for _, dependent in ipairs (cfg.dependencies_t[p]) do -- loop through the url-holding parameter's dependency sequence table.insert (unset_params_t, dependent); -- add dependent parameter to the list to be unset end end end end if 0 < #unset_params_t then -- when there are parameters to unset if not is_preview_mode then -- when in preview mode do not suppress any parameters for _, unset_param in ipairs (unset_params_t) do -- loop through the sequence cite_args_t[unset_param] = nil; -- and unset the url-holding parameter and its dependent parameters to avoid parameter-requires-other-parameter errors end end utilities.set_message ('maint_deprecated_archive'); -- add a maintenance message end end --[[-------------------------< C H E C K _ F O R _ U R L >----------------------------------------------------- loop through a list of parameters and their values. Look at the value and if it has an external link, emit an error message. ]] local function check_for_url (parameter_list, error_list) for k, v in pairs (parameter_list) do -- for each parameter in the list if is_parameter_ext_wikilink (v) then -- look at the value; if there is a URL add an error message table.insert (error_list, utilities.wrap_style ('parameter', k)); end end end --[[--------------------------< S A F E _ F O R _ U R L >------------------------------------------------------ Escape sequences for content that will be used for URL descriptions ]] local function safe_for_url( str ) if str:match( "%[%[.-%]%]" ) ~= nil then utilities.set_message ('err_wikilink_in_url', {}); end return str:gsub( '[%[%]\n]', { ['['] = '&#91;', [']'] = '&#93;', ['\n'] = ' ' } ); end --[[--------------------------< E X T E R N A L _ L I N K >---------------------------------------------------- Format an external link with error checking ]] local function external_link (URL, label, source, access) local domain; local path; local base_url; if not utilities.is_set (label) then label = URL; if utilities.is_set (source) then utilities.set_message ('err_bare_url_missing_title', {utilities.wrap_style ('parameter', source)}); else error (cfg.messages["bare_url_no_origin"]); -- programmer error; valid parameter name does not have matching meta-parameter end end if not check_url (URL) then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); end domain, path = URL:match ('^([/%.%-%+:%a%d]+)([/%?#].*)$'); -- split the URL into scheme plus domain and path if path then -- if there is a path portion path = path:gsub ('[%[%]]', {['['] = '%5b', [']'] = '%5d'}); -- replace '[' and ']' with their percent-encoded values URL = table.concat ({domain, path}); -- and reassemble end base_url = table.concat ({ "[", URL, " ", safe_for_url (label), "]" }); -- assemble a wiki-markup URL if utilities.is_set (access) then -- access level (subscription, registration, limited) base_url = utilities.substitute (cfg.presentation['ext-link-access-signal'], {cfg.presentation[access].class, cfg.presentation[access].title, base_url}); -- add the appropriate icon end return base_url; end --[[--------------------------< D E P R E C A T E D _ P A R A M E T E R >-------------------------------------- Categorize and emit an error message when the citation contains one or more deprecated parameters. The function includes the offending parameter name to the error message. Only one error message is emitted regardless of the number of deprecated parameters in the citation. added_deprecated_cat is a Boolean declared in page scope variables above ]] local function deprecated_parameter(name) if not added_deprecated_cat then added_deprecated_cat = true; -- note that we've added this category utilities.set_message ('err_deprecated_params', {name}); -- add error message end end --[=[-------------------------< K E R N _ Q U O T E S >-------------------------------------------------------- Apply kerning to open the space between the quote mark provided by the module and a leading or trailing quote mark contained in a |title= or |chapter= parameter's value. This function will positive kern either single or double quotes: "'Unkerned title with leading and trailing single quote marks'" " 'Kerned title with leading and trailing single quote marks' " (in real life the kerning isn't as wide as this example) Double single quotes (italic or bold wiki-markup) are not kerned. Replaces Unicode quote marks in plain text or in the label portion of a [[L|D]] style wikilink with typewriter quote marks regardless of the need for kerning. Unicode quote marks are not replaced in simple [[D]] wikilinks. Call this function for chapter titles, for website titles, etc.; not for book titles. ]=] local function kern_quotes (str) local wl_type, label, link; wl_type, label, link = utilities.is_wikilink (str); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] if 1 == wl_type then -- [[D]] simple wikilink with or without quote marks if mw.ustring.match (str, '%[%[[\"“”\'‘’].+[\"“”\'‘’]%]%]') then -- leading and trailing quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); str = utilities.substitute (cfg.presentation['kern-right'], str); elseif mw.ustring.match (str, '%[%[[\"“”\'‘’].+%]%]') then -- leading quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); elseif mw.ustring.match (str, '%[%[.+[\"“”\'‘’]%]%]') then -- trailing quote marks str = utilities.substitute (cfg.presentation['kern-right'], str); end else -- plain text or [[L|D]]; text in label variable label = mw.ustring.gsub (label, '[“”]', '\"'); -- replace “” (U+201C & U+201D) with " (typewriter double quote mark) label = mw.ustring.gsub (label, '[‘’]', '\''); -- replace ‘’ (U+2018 & U+2019) with ' (typewriter single quote mark) local cap = mw.ustring.match (label, "^([\"\'][^\'].+)"); -- match leading double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-left'], cap); end cap = mw.ustring.match (label, "^(.+[^\'][\"\'])$") -- match trailing double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-right'], cap); end if 2 == wl_type then str = utilities.make_wikilink (link, label); -- reassemble the wikilink else str = label; end end return str; end --[[--------------------------< F O R M A T _ S C R I P T _ V A L U E >---------------------------------------- |script-title= holds title parameters that are not written in Latin-based scripts: Chinese, Japanese, Arabic, Hebrew, etc. These scripts should not be italicized and may be written right-to-left. The value supplied by |script-title= is concatenated onto Title after Title has been wrapped in italic markup. Regardless of language, all values provided by |script-title= are wrapped in <bdi>...</bdi> tags to isolate RTL languages from the English left to right. |script-title= provides a unique feature. The value in |script-title= may be prefixed with a two-character ISO 639-1 language code and a colon: |script-title=ja:*** *** (where * represents a Japanese character) Spaces between the two-character code and the colon and the colon and the first script character are allowed: |script-title=ja : *** *** |script-title=ja: *** *** |script-title=ja :*** *** Spaces preceding the prefix are allowed: |script-title = ja:*** *** The prefix is checked for validity. If it is a valid ISO 639-1 language code, the lang attribute (lang="ja") is added to the <bdi> tag so that browsers can know the language the tag contains. This may help the browser render the script more correctly. If the prefix is invalid, the lang attribute is not added. At this time there is no error message for this condition. Supports |script-title=, |script-chapter=, |script-<periodical>= ]] local function format_script_value (script_value, script_param) local lang=''; -- initialize to empty string local name; if script_value:match('^%l%l%l?%s*:') then -- if first 3 or 4 non-space characters are script language prefix lang = script_value:match('^(%l%l%l?)%s*:%s*%S.*'); -- get the language prefix or nil if there is no script if not utilities.is_set (lang) then utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing title part']}); -- prefix without 'title'; add error message return ''; -- script_value was just the prefix so return empty string end -- if we get this far we have prefix and script name = cfg.lang_tag_remap[lang] or mw.language.fetchLanguageName( lang, cfg.this_wiki_code ); -- get language name so that we can use it to categorize if utilities.is_set (name) then -- is prefix a proper ISO 639-1 language code? script_value = script_value:gsub ('^%l+%s*:%s*', ''); -- strip prefix from script -- is prefix one of these language codes? if utilities.in_array (lang, cfg.script_lang_codes) then utilities.add_prop_cat ('script', {name, lang}) else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['unknown language code']}); -- unknown script-language; add error message end lang = ' lang="' .. lang .. '" '; -- convert prefix into a lang attribute else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['invalid language code']}); -- invalid language code; add error message lang = ''; -- invalid so set lang to empty string end else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing prefix']}); -- no language code prefix; add error message end script_value = utilities.substitute (cfg.presentation['bdi'], {lang, script_value}); -- isolate in case script is RTL return script_value; end --[[--------------------------< S C R I P T _ C O N C A T E N A T E >------------------------------------------ Initially for |title= and |script-title=, this function concatenates those two parameter values after the script value has been wrapped in <bdi> tags. ]] local function script_concatenate (title, script, script_param) if utilities.is_set (script) then script = format_script_value (script, script_param); -- <bdi> tags, lang attribute, categorization, etc.; returns empty string on error if utilities.is_set (script) then title = title .. ' ' .. script; -- concatenate title and script title end end return title; end --[[--------------------------< W R A P _ M S G >-------------------------------------------------------------- Applies additional message text to various parameter values. Supplied string is wrapped using a message_list configuration taking one argument. Supports lower case text for {{citation}} templates. Additional text taken from citation_config.messages - the reason this function is similar to but separate from wrap_style(). ]] local function wrap_msg (key, str, lower) if not utilities.is_set ( str ) then return ""; end if true == lower then local msg; msg = cfg.messages[key]:lower(); -- set the message to lower case before return utilities.substitute ( msg, str ); -- including template text else return utilities.substitute ( cfg.messages[key], str ); end end --[[----------------< W I K I S O U R C E _ U R L _ M A K E >------------------- Makes a Wikisource URL from Wikisource interwiki-link. Returns the URL and appropriate label; nil else. str is the value assigned to |chapter= (or aliases) or |title= or |title-link= ]] local function wikisource_url_make (str) local wl_type, D, L; local ws_url, ws_label; local wikisource_prefix = table.concat ({'https://', cfg.this_wiki_code, '.wikisource.org/wiki/'}); wl_type, D, L = utilities.is_wikilink (str); -- wl_type is 0 (not a wikilink), 1 (simple wikilink), 2 (complex wikilink) if 0 == wl_type then -- not a wikilink; might be from |title-link= str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 1 == wl_type then -- simple wikilink: [[Wikisource:ws article]] str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 2 == wl_type then -- non-so-simple wikilink: [[Wikisource:ws article|displayed text]] ([[L|D]]) str = L:match ('^[Ww]ikisource:(.+)') or L:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_label = D; -- get ws article name from display portion of interwiki link ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title without namespace from link portion of wikilink }); end end if ws_url then ws_url = mw.uri.encode (ws_url, 'WIKI'); -- make a usable URL ws_url = ws_url:gsub ('%%23', '#'); -- undo percent-encoding of fragment marker end return ws_url, ws_label, L or D; -- return proper URL or nil and a label or nil end --[[----------------< F O R M A T _ P E R I O D I C A L >----------------------- Format the three periodical parameters: |script-<periodical>=, |<periodical>=, and |trans-<periodical>= into a single Periodical meta-parameter. ]] local function format_periodical (script_periodical, script_periodical_source, periodical, trans_periodical) if not utilities.is_set (periodical) then periodical = ''; -- to be safe for concatenation else periodical = utilities.wrap_style ('italic-title', periodical); -- style end periodical = script_concatenate (periodical, script_periodical, script_periodical_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (trans_periodical) then trans_periodical = utilities.wrap_style ('trans-italic-title', trans_periodical); if utilities.is_set (periodical) then periodical = periodical .. ' ' .. trans_periodical; else -- here when trans-periodical without periodical or script-periodical periodical = trans_periodical; utilities.set_message ('err_trans_missing_title', {'periodical'}); end end return periodical; end --[[------------------< F O R M A T _ C H A P T E R _ T I T L E >--------------- Format the four chapter parameters: |script-chapter=, |chapter=, |trans-chapter=, and |chapter-url= into a single chapter meta- parameter (chapter_url_source used for error messages). ]] local function format_chapter_title (script_chapter, script_chapter_source, chapter, trans_chapter, trans_chapter_source, chapter_url, chapter_url_source, no_quotes, access) local ws_url, ws_label, L = wikisource_url_make (chapter); -- make a wikisource URL and label from a wikisource interwiki link if ws_url then ws_label = ws_label:gsub ('_', ' '); -- replace underscore separators with space characters chapter = ws_label; end if not utilities.is_set (chapter) then chapter = ''; -- to be safe for concatenation else if false == no_quotes then chapter = kern_quotes (chapter); -- if necessary, separate chapter title's leading and trailing quote marks from module provided quote marks chapter = utilities.wrap_style ('quoted-title', chapter); end end chapter = script_concatenate (chapter, script_chapter, script_chapter_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (chapter_url) then chapter = external_link (chapter_url, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate elseif ws_url then chapter = external_link (ws_url, chapter .. '&nbsp;', 'ws link in chapter'); -- adds bare_url_missing_title error if appropriate; space char to move icon away from chap text; TODO: better way to do this? chapter = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, chapter}); end if utilities.is_set (trans_chapter) then trans_chapter = utilities.wrap_style ('trans-quoted-title', trans_chapter); if utilities.is_set (chapter) then chapter = chapter .. ' ' .. trans_chapter; else -- here when trans_chapter without chapter or script-chapter chapter = trans_chapter; utilities.set_message ('err_trans_missing_title', {trans_chapter_source:match ('trans%-?(.+)')}); -- when no chapter, get matching name from trans-<param> end end return chapter; end --[[----------------< H A S _ I N V I S I B L E _ C H A R S >------------------- This function searches a parameter's value for non-printable or invisible characters. The search stops at the first match. This function will detect the visible replacement character when it is part of the Wikisource. Detects but ignores nowiki and math stripmarkers. Also detects other named stripmarkers (gallery, math, pre, ref) and identifies them with a slightly different error message. See also coins_cleanup(). Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker that was detected along with its position (or, for multi-byte characters, the position of its first byte) in the parameter value. ]] local function has_invisible_chars (param, v) local position; -- position of invisible char or starting position of stripmarker local capture; -- used by stripmarker detection to hold name of the stripmarker local stripmarker; -- boolean set true when a stripmarker is found capture = string.match (v, '[%w%p ]*'); -- test for values that are simple ASCII text and bypass other tests if true if capture == v then -- if same there are no Unicode characters return; end for _, invisible_char in ipairs (cfg.invisible_chars) do local char_name = invisible_char[1]; -- the character or group name local pattern = invisible_char[2]; -- the pattern used to find it position, _, capture = mw.ustring.find (v, pattern); -- see if the parameter value contains characters that match the pattern if position and (cfg.invisible_defs.zwj == capture) then -- if we found a zero-width joiner character if mw.ustring.find (v, cfg.indic_script) then -- it's ok if one of the Indic scripts position = nil; -- unset position elseif cfg.emoji_t[mw.ustring.codepoint (v, position+1)] then -- is zwj followed by a character listed in emoji{}? position = nil; -- unset position end end if position then if 'nowiki' == capture or 'math' == capture or -- nowiki and math stripmarkers (not an error condition) ('templatestyles' == capture and utilities.in_array (param, {'id', 'quote'})) then -- templatestyles stripmarker allowed in these parameters stripmarker = true; -- set a flag elseif true == stripmarker and cfg.invisible_defs.del == capture then -- because stripmakers begin and end with the delete char, assume that we've found one end of a stripmarker position = nil; -- unset; for now, ignore linter warning else local err_msg; if capture and not (cfg.invisible_defs.del == capture or cfg.invisible_defs.zwj == capture) then err_msg = utilities.substitute (cfg.messages.invisible_1, {capture, char_name}); -- <capture> here is stripmarker name else err_msg = utilities.substitute (cfg.messages.invisible_2, char_name); end utilities.set_message ('err_invisible_char', {err_msg, utilities.wrap_style ('parameter', param), position}); -- add error message return; -- and done with this parameter end end end end --[[-------------------< A R G U M E N T _ W R A P P E R >---------------------- Argument wrapper. This function provides support for argument mapping defined in the configuration file so that multiple names can be transparently aliased to single internal variable. ]] local function argument_wrapper ( args ) local origin = {}; return setmetatable({ ORIGIN = function ( self, k ) local dummy = self[k]; -- force the variable to be loaded; for now, ignore linter warning return origin[k]; end }, { __index = function ( tbl, k ) if origin[k] ~= nil then return nil; end local v; local list = cfg.aliases[k]; if type( list ) == 'table' then v, origin[k] = utilities.select_one ( args, list, 'err_redundant_parameters' ); if origin[k] == nil then origin[k] = ''; -- Empty string, not nil end elseif list ~= nil then v, origin[k] = args[list], list; else -- maybe let through instead of raising an error? -- v, origin[k] = args[k], k; error( cfg.messages['unknown_argument_map'] .. ': ' .. k); end -- Empty strings, not nil; if v == nil then v = ''; origin[k] = ''; end -- tbl = rawset( tbl, k, v ); rawset( tbl, k, v ); return v; end, }); end --[[--------------------------< N O W R A P _ D A T E >------------------------- When date is YYYY-MM-DD format wrap in nowrap span: <span ...>YYYY-MM-DD</span>. When date is DD MMMM YYYY or is MMMM DD, YYYY then wrap in nowrap span: <span ...>DD MMMM</span> YYYY or <span ...>MMMM DD,</span> YYYY DOES NOT yet support MMMM YYYY or any of the date ranges. ]] local function nowrap_date (date) local cap; local cap2; if date:match("^%d%d%d%d%-%d%d%-%d%d$") then date = utilities.substitute (cfg.presentation['nowrap1'], date); elseif date:match("^%a+%s*%d%d?,%s+%d%d%d%d$") or date:match ("^%d%d?%s*%a+%s+%d%d%d%d$") then cap, cap2 = string.match (date, "^(.*)%s+(%d%d%d%d)$"); date = utilities.substitute (cfg.presentation['nowrap2'], {cap, cap2}); end return date; end --[[--------------------------< S E T _ T I T L E T Y P E >--------------------- This function sets default title types (equivalent to the citation including |type=<default value>) for those templates that have defaults. Also handles the special case where it is desirable to omit the title type from the rendered citation (|type=none). ]] local function set_titletype (cite_class, title_type) if utilities.is_set (title_type) then if 'none' == cfg.keywords_xlate[title_type] then title_type = ''; -- if |type=none then type parameter not displayed end return title_type; -- if |type= has been set to any other value use that value end return cfg.title_types [cite_class] or ''; -- set template's default title type; else empty string for concatenation end --[[--------------------------< S A F E _ J O I N >----------------------------- Joins a sequence of strings together while checking for duplicate separation characters. ]] local function safe_join( tbl, duplicate_char ) local f = {}; -- create a function table appropriate to type of 'duplicate character' if 1 == #duplicate_char then -- for single byte ASCII characters use the string library functions f.gsub = string.gsub f.match = string.match f.sub = string.sub else -- for multi-byte characters use the ustring library functions f.gsub = mw.ustring.gsub f.match = mw.ustring.match f.sub = mw.ustring.sub end local str = ''; -- the output string for _, value in ipairs( tbl ) do if value == nil then value = ''; end if str == '' then -- if output string is empty str = value; -- assign value to it (first time through the loop) elseif value ~= '' then local comp; -- what does 'comp' mean? if value:sub(1, 1) == '<' then -- special case of values enclosed in spans and other markup. comp = value:gsub( "%b<>", "" ); -- remove HTML markup (<span>string</span> -> string) else comp = value; end -- typically duplicate_char is sepc if f.sub(comp, 1, 1) == duplicate_char then -- is first character same as duplicate_char? why test first character? -- Because individual string segments often (always?) begin with terminal punct for the -- preceding segment: 'First element' .. 'sepc next element' .. etc.? local trim = false; local end_chr = f.sub(str, -1, -1); -- get the last character of the output string -- str = str .. "<HERE(enchr=" .. end_chr .. ")" -- debug stuff? if end_chr == duplicate_char then -- if same as separator str = f.sub(str, 1, -2); -- remove it elseif end_chr == "'" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "''" then -- if last three chars of str are sepc'' str = f.sub(str, 1, -4) .. "''"; -- remove them and add back '' elseif f.sub(str, -5, -1) == duplicate_char .. "]]''" then -- if last five chars of str are sepc]]'' trim = true; -- why? why do this and next differently from previous? elseif f.sub(str, -4, -1) == duplicate_char .. "]''" then -- if last four chars of str are sepc]'' trim = true; -- same question end elseif end_chr == "]" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "]]" then -- if last three chars of str are sepc]] wikilink trim = true; elseif f.sub(str, -3, -1) == duplicate_char .. '"]' then -- if last three chars of str are sepc"] quoted external link trim = true; elseif f.sub(str, -2, -1) == duplicate_char .. "]" then -- if last two chars of str are sepc] external link trim = true; elseif f.sub(str, -4, -1) == duplicate_char .. "'']" then -- normal case when |url=something & |title=Title. trim = true; end elseif end_chr == " " then -- if last char of output string is a space if f.sub(str, -2, -1) == duplicate_char .. " " then -- if last two chars of str are <sepc><space> str = f.sub(str, 1, -3); -- remove them both end end if trim then if value ~= comp then -- value does not equal comp when value contains HTML markup local dup2 = duplicate_char; if f.match(dup2, "%A" ) then dup2 = "%" .. dup2; end -- if duplicate_char not a letter then escape it value = f.gsub(value, "(%b<>)" .. dup2, "%1", 1 ) -- remove duplicate_char if it follows HTML markup else value = f.sub(value, 2, -1 ); -- remove duplicate_char when it is first character end end end str = str .. value; -- add it to the output string end end return str; end --[[--------------------------< I S _ S U F F I X >----------------------------- returns true if suffix is properly formed Jr, Sr, or ordinal in the range 1–9. Puncutation not allowed. ]] local function is_suffix (suffix) if utilities.in_array (suffix, {'Jr', 'Sr', 'Jnr', 'Snr', '1st', '2nd', '3rd'}) or suffix:match ('^%dth$') then return true; end return false; end --[[--------------------< I S _ G O O D _ V A N C _ N A M E >------------------- For Vancouver style, author/editor names are supposed to be rendered in Latin (read ASCII) characters. When a name uses characters that contain diacritical marks, those characters are to be converted to the corresponding Latin character. When a name is written using a non-Latin alphabet or logogram, that name is to be transliterated into Latin characters. The module doesn't do this so editors may/must. This test allows |first= and |last= names to contain any of the letters defined in the four Unicode Latin character sets [http://www.unicode.org/charts/PDF/U0000.pdf C0 Controls and Basic Latin] 0041–005A, 0061–007A [http://www.unicode.org/charts/PDF/U0080.pdf C1 Controls and Latin-1 Supplement] 00C0–00D6, 00D8–00F6, 00F8–00FF [http://www.unicode.org/charts/PDF/U0100.pdf Latin Extended-A] 0100–017F [http://www.unicode.org/charts/PDF/U0180.pdf Latin Extended-B] 0180–01BF, 01C4–024F |lastn= also allowed to contain hyphens, spaces, and apostrophes. (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) |firstn= also allowed to contain hyphens, spaces, apostrophes, and periods This original test: if nil == mw.ustring.find (last, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%'%.]+[2-6%a]*$") then was written outside of the code editor and pasted here because the code editor gets confused between character insertion point and cursor position. The test has been rewritten to use decimal character escape sequence for the individual bytes of the Unicode characters so that it is not necessary to use an external editor to maintain this code. \195\128-\195\150 – À-Ö (U+00C0–U+00D6 – C0 controls) \195\152-\195\182 – Ø-ö (U+00D8-U+00F6 – C0 controls) \195\184-\198\191 – ø-ƿ (U+00F8-U+01BF – C0 controls, Latin extended A & B) \199\132-\201\143 – DŽ-ɏ (U+01C4-U+024F – Latin extended B) ]] local function is_good_vanc_name (last, first, suffix, position) if not suffix then if first:find ('[,%s]') then -- when there is a space or comma, might be first name/initials + generational suffix first = first:match ('(.-)[,%s]+'); -- get name/initials suffix = first:match ('[,%s]+(.+)$'); -- get generational suffix end end if utilities.is_set (suffix) then if not is_suffix (suffix) then add_vanc_error (cfg.err_msg_supl.suffix, position); return false; -- not a name with an appropriate suffix end end if nil == mw.ustring.find (last, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%'%.]*$") then add_vanc_error (cfg.err_msg_supl['non-Latin char'], position); return false; -- not a string of Latin characters; Vancouver requires Romanization end; return true; end --[[--------------------------< R E D U C E _ T O _ I N I T I A L S >------------------------------------------ Attempts to convert names to initials in support of |name-list-style=vanc. Names in |firstn= may be separated by spaces or hyphens, or for initials, a period. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35062/. Vancouver style requires family rank designations (Jr, II, III, etc.) to be rendered as Jr, 2nd, 3rd, etc. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35085/. This code only accepts and understands generational suffix in the Vancouver format because Roman numerals look like, and can be mistaken for, initials. This function uses ustring functions because firstname initials may be any of the Unicode Latin characters accepted by is_good_vanc_name (). ]] local function reduce_to_initials (first, position) if first:find (',', 1, true) then return first; -- commas not allowed; abandon end local name, suffix = mw.ustring.match (first, "^(%u+) ([%dJS][%drndth]+)$"); if not name then -- if not initials and a suffix name = mw.ustring.match (first, "^(%u+)$"); -- is it just initials? end if name then -- if first is initials with or without suffix if 3 > mw.ustring.len (name) then -- if one or two initials if suffix then -- if there is a suffix if is_suffix (suffix) then -- is it legitimate? return first; -- one or two initials and a valid suffix so nothing to do else add_vanc_error (cfg.err_msg_supl.suffix, position); -- one or two initials with invalid suffix so error message return first; -- and return first unmolested end else return first; -- one or two initials without suffix; nothing to do end end end -- if here then name has 3 or more uppercase letters so treat them as a word local initials_t = {}; -- table to hold initials local i = 1; -- counter for number of initials local names_t = mw.text.split (first, '[%s%-]+'); -- split into a sequence of names and possible suffix while names_t[i] do -- loop through the sequence if 1 < i and names_t[i]:match ('[%dJS][%drndth]+%.?$') then -- if not the first name, and looks like a suffix (may have trailing dot) names_t[i] = names_t[i]:gsub ('%.', ''); -- remove terminal dot if present if is_suffix (names_t[i]) then -- if a legitimate suffix table.insert (initials_t, ' ' .. names_t[i]); -- add a separator space, insert at end of initials sequence break; -- and done because suffix must fall at the end of a name end -- no error message if not a suffix; possibly because of Romanization end if 3 > i then table.insert (initials_t, mw.ustring.sub (names_t[i], 1, 1)); -- insert the initial at end of initials sequence end i = i + 1; -- bump the counter end return table.concat (initials_t); -- Vancouver format does not include spaces. end --[[--------------------------< I N T E R W I K I _ P R E F I X E N _ G E T >---------------------------------- extract interwiki prefixen from <value>. Returns two one or two values: false – no prefixen nil – prefix exists but not recognized project prefix, language prefix – when value has either of: :<project>:<language>:<article> :<language>:<project>:<article> project prefix, nil – when <value> has only a known single-letter prefix nil, language prefix – when <value> has only a known language prefix accepts single-letter project prefixen: 'd' (wikidata), 's' (wikisource), and 'w' (wikipedia) prefixes; at this writing, the other single-letter prefixen (b (wikibook), c (commons), m (meta), n (wikinews), q (wikiquote), and v (wikiversity)) are not supported. ]] local function interwiki_prefixen_get (value, is_link) if not value:find (':%l+:') then -- if no prefix return false; -- abandon; boolean here to distinguish from nil fail returns later end local prefix_patterns_linked_t = { -- sequence of valid interwiki and inter project prefixen '^%[%[:([dsw]):(%l%l+):', -- wikilinked; project and language prefixes '^%[%[:(%l%l+):([dsw]):', -- wikilinked; language and project prefixes '^%[%[:([dsw]):', -- wikilinked; project prefix '^%[%[:(%l%l+):', -- wikilinked; language prefix } local prefix_patterns_unlinked_t = { -- sequence of valid interwiki and inter project prefixen '^:([dsw]):(%l%l+):', -- project and language prefixes '^:(%l%l+):([dsw]):', -- language and project prefixes '^:([dsw]):', -- project prefix '^:(%l%l+):', -- language prefix } local cap1, cap2; for _, pattern in ipairs ((is_link and prefix_patterns_linked_t) or prefix_patterns_unlinked_t) do cap1, cap2 = value:match (pattern); if cap1 then break; -- found a match so stop looking end end if cap1 and cap2 then -- when both then :project:language: or :language:project: (both forms allowed) if 1 == #cap1 then -- length == 1 then :project:language: if cfg.inter_wiki_map[cap2] then -- is language prefix in the interwiki map? return cap1, cap2; -- return interwiki project and interwiki language end else -- here when :language:project: if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return cap2, cap1; -- return interwiki project and interwiki language end end return nil; -- unknown interwiki language elseif not (cap1 or cap2) then -- both are nil? return nil; -- we got something that looks like a project prefix but isn't; return fail elseif 1 == #cap1 then -- here when one capture return cap1, nil; -- length is 1 so return project, nil language else -- here when one capture and its length it more than 1 if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return nil, cap1; -- return nil project, language end end end --[[--------------------------< L I S T _ P E O P L E >-------------------------- Formats a list of people (authors, contributors, editors, interviewers, translators) names in the list will be linked when |<name>-link= has a value |<name>-mask- does NOT have a value; masked names are presumed to have been rendered previously so should have been linked there when |<name>-mask=0, the associated name is not rendered ]] local function list_people (control, people, etal) local sep; local namesep; local format = control.format; local maximum = control.maximum; local name_list = {}; if 'vanc' == format then -- Vancouver-like name styling? sep = cfg.presentation['sep_nl_vanc']; -- name-list separator between names is a comma namesep = cfg.presentation['sep_name_vanc']; -- last/first separator is a space else sep = cfg.presentation['sep_nl']; -- name-list separator between names is a semicolon namesep = cfg.presentation['sep_name']; -- last/first separator is <comma><space> end if sep:sub (-1, -1) ~= " " then sep = sep .. " " end if utilities.is_set (maximum) and maximum < 1 then return "", 0; end -- returned 0 is for EditorCount; not used for other names for i, person in ipairs (people) do if utilities.is_set (person.last) then local mask = person.mask; local one; local sep_one = sep; if utilities.is_set (maximum) and i > maximum then etal = true; break; end if mask then local n = tonumber (mask); -- convert to a number if it can be converted; nil else if n then one = 0 ~= n and string.rep("&mdash;", n) or nil; -- make a string of (n > 0) mdashes, nil else, to replace name person.link = nil; -- don't create link to name if name is replaces with mdash string or has been set nil else one = mask; -- replace name with mask text (must include name-list separator) sep_one = " "; -- modify name-list separator end else one = person.last; -- get surname local first = person.first -- get given name if utilities.is_set (first) then if ("vanc" == format) then -- if Vancouver format one = one:gsub ('%.', ''); -- remove periods from surnames (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) if not person.corporate and is_good_vanc_name (one, first, nil, i) then -- and name is all Latin characters; corporate authors not tested first = reduce_to_initials (first, i); -- attempt to convert first name(s) to initials end end one = one .. namesep .. first; end end if utilities.is_set (person.link) then one = utilities.make_wikilink (person.link, one); -- link author/editor end if one then -- if <one> has a value (name, mdash replacement, or mask text replacement) local proj, tag = interwiki_prefixen_get (one, true); -- get the interwiki prefixen if present if 'w' == proj and ('Wikipedia' == mw.site.namespaces.Project['name']) then proj = nil; -- for stuff like :w:de:<article>, :w is unnecessary TODO: maint cat? end if proj then local proj_name = ({['d'] = cfg.messages.wikidata, ['s'] = cfg.messages.wikisource, ['w'] = cfg.messages.wikipedia})[proj]; -- :w (wikipedia) for linking from a non-wikipedia project if proj_name then one = one .. utilities.wrap_style ('interproj', proj_name); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interproj-linked-name', proj); -- categorize it; <proj> is sort key tag = nil; -- unset; don't do both project and language end end if tag == cfg.this_wiki_code then tag = nil; -- stuff like :en:<article> at en.wiki is pointless TODO: maint cat? end if tag then local lang = cfg.lang_tag_remap[tag] or cfg.mw_languages_by_tag_t[tag]; if lang then -- error messaging done in extract_names() where we know parameter names one = one .. utilities.wrap_style ('interwiki', lang); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interwiki-linked-name', tag); -- categorize it; <tag> is sort key end end table.insert (name_list, one); -- add it to the list of names table.insert (name_list, sep_one); -- add the proper name-list separator end end end local count = #name_list / 2; -- (number of names + number of separators) divided by 2 if 0 < count then if 1 < count and not etal then if 'amp' == format then name_list[#name_list-2] = " & "; -- replace last separator with ampersand text elseif 'and' == format then if 2 == count then name_list[#name_list-2] = cfg.presentation.sep_nl_and; -- replace last separator with 'and' text else name_list[#name_list-2] = cfg.presentation.sep_nl_end; -- replace last separator with '(sep) and' text end end end name_list[#name_list] = nil; -- erase the last separator end local result = table.concat (name_list); -- construct list if etal and utilities.is_set (result) then -- etal may be set by |display-authors=etal but we might not have a last-first list result = result .. sep .. cfg.messages['et al']; -- we've got a last-first list and etal so add et al. end return result, count; -- return name-list string and count of number of names (count used for editor names only) end --[[--------------------< M A K E _ C I T E R E F _ I D >----------------------- Generates a CITEREF anchor ID if we have at least one name or a date. Otherwise returns an empty string. namelist is one of the contributor-, author-, or editor-name lists chosen in that order. year is Year or anchor_year. ]] local function make_citeref_id (namelist, year) local names={}; -- a table for the one to four names and year for i,v in ipairs (namelist) do -- loop through the list and take up to the first four last names names[i] = v.last if i == 4 then break end -- if four then done end table.insert (names, year); -- add the year at the end local id = table.concat(names); -- concatenate names and year for CITEREF id if utilities.is_set (id) then -- if concatenation is not an empty string return "CITEREF" .. id; -- add the CITEREF portion else return ''; -- return an empty string; no reason to include CITEREF id in this citation end end --[[--------------------------< C I T E _ C L A S S _A T T R I B U T E _M A K E >------------------------------ construct <cite> tag class attribute for this citation. <cite_class> – config.CitationClass from calling template <mode> – value from |mode= parameter ]] local function cite_class_attribute_make (cite_class, mode) local class_t = {}; table.insert (class_t, 'citation'); -- required for blue highlight if 'citation' ~= cite_class then table.insert (class_t, cite_class); -- identify this template for user css table.insert (class_t, utilities.is_set (mode) and mode or 'cs1'); -- identify the citation style for user css or javascript else table.insert (class_t, utilities.is_set (mode) and mode or 'cs2'); -- identify the citation style for user css or javascript end for _, prop_key in ipairs (z.prop_keys_t) do table.insert (class_t, prop_key); -- identify various properties for user css or javascript end return table.concat (class_t, ' '); -- make a big string and done end --[[---------------------< N A M E _ H A S _ E T A L >-------------------------- Evaluates the content of name parameters (author, editor, etc.) for variations on the theme of et al. If found, the et al. is removed, a flag is set to true and the function returns the modified name and the flag. This function never sets the flag to false but returns its previous state because it may have been set by previous passes through this function or by the associated |display-<names>=etal parameter ]] local function name_has_etal (name, etal, nocat, param) if utilities.is_set (name) then -- name can be nil in which case just return local patterns = cfg.et_al_patterns; -- get patterns from configuration for _, pattern in ipairs (patterns) do -- loop through all of the patterns if name:match (pattern) then -- if this 'et al' pattern is found in name name = name:gsub (pattern, ''); -- remove the offending text etal = true; -- set flag (may have been set previously here or by |display-<names>=etal) if not nocat then -- no categorization for |vauthors= utilities.set_message ('err_etal', {param}); -- and set an error if not added end end end end return name, etal; end --[[---------------------< N A M E _ I S _ N U M E R I C >---------------------- Add an error message and category when <name> parameter value does not contain letters. Add a maintenance category when <name> parameter value has numeric characters mixed with characters that are not numeric characters; could be letters and/or punctuation characters. This function will only emit one error and one maint message for the current template. Does not emit both error and maint messages/categories for the same parameter value. returns nothing ]] local function name_is_numeric (name, name_alias, list_name) local patterns = { '^%D+%d', -- <name> must have digits preceded by other characters '^%D*%d+%D+', -- <name> must have digits followed by other characters } if not added_numeric_name_errs and mw.ustring.match (name, '^[%A]+$') then -- if we have not already set an error message and <name> does not have any alpha characters utilities.set_message ('err_numeric_names', name_alias); -- add an error message added_numeric_name_errs = true; -- set the flag so we emit only one error message return; -- when here no point in further testing; abandon end if not added_numeric_name_maint then -- if we have already set a maint message for _, pattern in ipairs (patterns) do -- spin through list of patterns if mw.ustring.match (name, pattern) then -- digits preceded or followed by anything but digits; %D+ includes punctuation utilities.set_message ('maint_numeric_names', cfg.special_case_translation [list_name]); -- add a maint cat for this template added_numeric_name_maint = true; -- set the flag so we emit only one maint message return; -- when here no point in further testing; abandon end end end end --[[-----------------< N A M E _ H A S _ M U L T _ N A M E S >------------------ Evaluates the content of last/surname (authors etc.) parameters for multiple names. Multiple names are indicated if there is more than one comma or any "unescaped" semicolons. Escaped semicolons are ones used as part of selected HTML entities. If the condition is met, the function adds the multiple name maintenance category. Same test for first except that commas should not appear in given names (MOS:JR says that the generational suffix does not take a separator character). Titles, degrees, postnominals, affiliations, all normally comma separated don't belong in a citation. <name> – name parameter value <list_name> – AuthorList, EditorList, etc <limit> – number of allowed commas; 1 (default) for surnames; 0 for given names returns nothing ]] local function name_has_mult_names (name, list_name, limit) local _, commas, semicolons, nbsps; limit = limit and limit or 1; if utilities.is_set (name) then _, commas = name:gsub (',', ''); -- count the number of commas _, semicolons = name:gsub (';', ''); -- count the number of semicolons -- nbsps probably should be its own separate count rather than merged in -- some way with semicolons because Lua patterns do not support the -- grouping operator that regex does, which means there is no way to add -- more entities to escape except by adding more counts with the new -- entities _, nbsps = name:gsub ('&nbsp;',''); -- count nbsps -- There is exactly 1 semicolon per &nbsp; entity, so subtract nbsps -- from semicolons to 'escape' them. If additional entities are added, -- they also can be subtracted. if limit < commas or 0 < (semicolons - nbsps) then utilities.set_message ('maint_mult_names', cfg.special_case_translation [list_name]); -- add a maint message end end end --[=[-------------------------< I S _ G E N E R I C >---------------------------------------------------------- Compares values assigned to various parameters according to the string provided as <item> in the function call. <item> can have on of two values: 'generic_names' – for name-holding parameters: |last=, |first=, |editor-last=, etc 'generic_titles' – for |title= There are two types of generic tests. The 'accept' tests look for a pattern that should not be rejected by the 'reject' test. For example, |author=[[John Smith (author)|Smith, John]] would be rejected by the 'author' reject test. But piped wikilinks with 'author' disambiguation should not be rejected so the 'accept' test prevents that from happening. Accept tests are always performed before reject tests. Each of the 'accept' and 'reject' sequence tables hold tables for en.wiki (['en']) and local.wiki (['local']) that each can hold a test sequence table The sequence table holds, at index [1], a test pattern, and, at index [2], a boolean control value. The control value tells string.find() or mw.ustring.find() to do plain-text search (true) or a pattern search (false). The intent of all this complexity is to make these searches as fast as possible so that we don't run out of processing time on very large articles. Returns true when a reject test finds the pattern or string false when an accept test finds the pattern or string nil else ]=] local function is_generic (item, value) local str_lower = { -- use string.lower() for en.wiki (['en']) and use mw.ustring.lower() or local.wiki (['local']) ['en'] = string.lower, ['local'] = mw.ustring.lower, } local str_find = { -- use string.find() for en.wiki (['en']) and use mw.ustring.find() or local.wiki (['local']) ['en'] = string.find, ['local'] = mw.ustring.find, } local function test (val, test_t, wiki) -- local function to do the testing; <wiki> selects lower() and find() functions val = test_t[2] and str_lower[wiki](value) or val; -- when <test_t[2]> set to 'true', plaintext search using lowercase value return str_find[wiki] (val, test_t[1], 1, test_t[2]); -- return nil when not found or matched end local test_types_t = {'accept', 'reject'}; -- test accept patterns first, then reject patterns local wikis_t = {'en', 'local'}; -- do tests for each of these keys; en.wiki first, local.wiki second for _, test_type in ipairs (test_types_t) do -- for each test type for _, generic_value in pairs (cfg.special_case_translation[item][test_type]) do -- spin through the list of generic value fragments to accept or reject for _, wiki in ipairs (wikis_t) do if generic_value[wiki] then if test (value, generic_value[wiki], wiki) then -- go do the test return ('reject' == test_type); -- param value rejected, return true; false else end end end end end end --[[--------------------------< N A M E _ I S _ G E N E R I C >------------------------------------------------ calls is_generic() to determine if <name> is a 'generic name' listed in cfg.generic_names; <name_alias> is the parameter name used in error messaging ]] local function name_is_generic (name, name_alias) if not added_generic_name_errs and is_generic ('generic_names', name) then utilities.set_message ('err_generic_name', name_alias); -- set an error message added_generic_name_errs = true; end end --[[--------------------------< N A M E _ C H E C K S >-------------------------------------------------------- This function calls various name checking functions used to validate the content of the various name-holding parameters. ]] local function name_checks (last, first, list_name, last_alias, first_alias) local accept_name; if utilities.is_set (last) then last, accept_name = utilities.has_accept_as_written (last); -- remove accept-this-as-written markup when it wraps all of <last> if not accept_name then -- <last> not wrapped in accept-as-written markup name_has_mult_names (last, list_name); -- check for multiple names in the parameter name_is_numeric (last, last_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (last, last_alias); -- check for names found in the generic names list end end if utilities.is_set (first) then first, accept_name = utilities.has_accept_as_written (first); -- remove accept-this-as-written markup when it wraps all of <first> if not accept_name then -- <first> not wrapped in accept-as-written markup name_has_mult_names (first, list_name, 0); -- check for multiple names in the parameter; 0 is number of allowed commas in a given name name_is_numeric (first, first_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (first, first_alias); -- check for names found in the generic names list end local wl_type, D = utilities.is_wikilink (first); if 0 ~= wl_type then first = D; utilities.set_message ('err_bad_paramlink', first_alias); end end return last, first; -- done end --[[----------------------< E X T R A C T _ N A M E S >------------------------- Gets name list from the input arguments Searches through args in sequential order to find |lastn= and |firstn= parameters (or their aliases), and their matching link and mask parameters. Stops searching when both |lastn= and |firstn= are not found in args after two sequential attempts: found |last1=, |last2=, and |last3= but doesn't find |last4= and |last5= then the search is done. This function emits an error message when there is a |firstn= without a matching |lastn=. When there are 'holes' in the list of last names, |last1= and |last3= are present but |last2= is missing, an error message is emitted. |lastn= is not required to have a matching |firstn=. When an author or editor parameter contains some form of 'et al.', the 'et al.' is stripped from the parameter and a flag (etal) returned that will cause list_people() to add the static 'et al.' text from Module:Citation/CS1/Configuration. This keeps 'et al.' out of the template's metadata. When this occurs, an error is emitted. ]] local function extract_names(args, list_name) local names = {}; -- table of names local last; -- individual name components local first; local link; local mask; local i = 1; -- loop counter/indexer local n = 1; -- output table indexer local count = 0; -- used to count the number of times we haven't found a |last= (or alias for authors, |editor-last or alias for editors) local etal = false; -- return value set to true when we find some form of et al. in an author parameter local last_alias, first_alias, link_alias; -- selected parameter aliases used in error messaging while true do last, last_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'err_redundant_parameters', i ); -- search through args for name components beginning at 1 first, first_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'err_redundant_parameters', i ); link, link_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ); mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); if last then -- error check |lastn= alias for unknown interwiki link prefix; done here because this is where we have the parameter name local project, language = interwiki_prefixen_get (last, true); -- true because we expect interwiki links in |lastn= to be wikilinked if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', last_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? last = utilities.remove_wiki_link (last); -- remove wikilink markup; show display value only end end if link then -- error check |linkn= alias for unknown interwiki link prefix local project, language = interwiki_prefixen_get (link, false); -- false because wiki links in |author-linkn= is an error if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', link_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? link = nil; -- unset so we don't link link_alias = nil; end end last, etal = name_has_etal (last, etal, false, last_alias); -- find and remove variations on et al. first, etal = name_has_etal (first, etal, false, first_alias); -- find and remove variations on et al. last, first = name_checks (last, first, list_name, last_alias, first_alias); -- multiple names, extraneous annotation, etc. checks if first and not last then -- if there is a firstn without a matching lastn local alias = first_alias:find ('given', 1, true) and 'given' or 'first'; -- get first or given form of the alias utilities.set_message ('err_first_missing_last', { first_alias, -- param name of alias missing its mate first_alias:gsub (alias, {['first'] = 'last', ['given'] = 'surname'}), -- make param name appropriate to the alias form }); -- add this error message elseif not first and not last then -- if both firstn and lastn aren't found, are we done? count = count + 1; -- number of times we haven't found last and first if 2 <= count then -- two missing names and we give up break; -- normal exit or there is a two-name hole in the list; can't tell which end else -- we have last with or without a first link = link_title_ok (link, link_alias, last, last_alias); -- check for improper wiki-markup if first then link = link_title_ok (link, link_alias, first, first_alias); -- check for improper wiki-markup end names[n] = {last = last, first = first, link = link, mask = mask, corporate = false}; -- add this name to our names list (corporate for |vauthors= only) n = n + 1; -- point to next location in the names table if 1 == count then -- if the previous name was missing utilities.set_message ('err_missing_name', {list_name:match ("(%w+)List"):lower(), i - 1}); -- add this error message end count = 0; -- reset the counter, we're looking for two consecutive missing names end i = i + 1; -- point to next args location end return names, etal; -- all done, return our list of names and the etal flag end --[[--------------------------< N A M E _ T A G _ G E T >------------------------------------------------------ attempt to decode |language=<lang_param> and return language name and matching tag; nil else. This function looks for: <lang_param> as a tag in cfg.lang_tag_remap{} <lang_param> as a name in cfg.lang_name_remap{} <lang_param> as a name in cfg.mw_languages_by_name_t <lang_param> as a tag in cfg.mw_languages_by_tag_t when those fail, presume that <lang_param> is an IETF-like tag that MediaWiki does not recognize. Strip all script, region, variant, whatever subtags from <lang_param> to leave just a two or three character language tag and look for the new <lang_param> in cfg.mw_languages_by_tag_t{} on success, returns name (in properly capitalized form) and matching tag (in lowercase); on failure returns nil ]] local function name_tag_get (lang_param) local lang_param_lc = mw.ustring.lower (lang_param); -- use lowercase as an index into the various tables local name; local tag; name = cfg.lang_tag_remap[lang_param_lc]; -- assume <lang_param_lc> is a tag; attempt to get remapped language name if name then -- when <name>, <lang_param> is a tag for a remapped language name if cfg.lang_name_remap[name:lower()][2] ~= lang_param_lc then utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added return name, cfg.lang_name_remap[name:lower()][2]; -- so return name and tag from lang_name_remap[name]; special case to xlate sr-ec and sr-el to sr-cyrl and sr-latn end return name, lang_param_lc; -- so return <name> from remap and <lang_param_lc> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- still assuming that <lang_param_lc> is a tag; strip script, region, variant subtags name = cfg.lang_tag_remap[tag]; -- attempt to get remapped language name with language subtag only if name then -- when <name>, <tag> is a tag for a remapped language name return name, tag; -- so return <name> from remap and <tag> end if cfg.lang_name_remap[lang_param_lc] then -- not a remapped tag, assume <lang_param_lc> is a name; attempt to get remapped language tag return cfg.lang_name_remap[lang_param_lc][1], cfg.lang_name_remap[lang_param_lc][2]; -- for this <lang_param_lc>, return a (possibly) new name and appropriate tag end name = cfg.mw_languages_by_tag_t[lang_param_lc]; -- assume that <lang_param_lc> is a tag; attempt to get its matching language name if name then return name, lang_param_lc; -- <lang_param_lc> is a tag so return it and <name> end tag = cfg.mw_languages_by_name_t[lang_param_lc]; -- assume that <lang_param_lc> is a language name; attempt to get its matching tag if tag then return cfg.mw_languages_by_tag_t[tag], tag; -- <lang_param_lc> is a name so return the name from the table and <tag> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- is <lang_param_lc> an IETF-like tag that MediaWiki doesn't recognize? <tag> gets the language subtag; nil else if tag then name = cfg.mw_languages_by_tag_t[tag]; -- attempt to get a language name using the shortened <tag> if name then return name, tag; -- <lang_param_lc> is an unrecognized IETF-like tag so return <name> and language subtag end end end --[[-------------------< L A N G U A G E _ P A R A M E T E R >------------------ Gets language name from a provided two- or three-character ISO 639 code. If a code is recognized by MediaWiki, use the returned name; if not, then use the value that was provided with the language parameter. When |language= contains a recognized language (either code or name), the page is assigned to the category for that code: Category:Norwegian-language sources (no). For valid three-character code languages, the page is assigned to the single category for '639-2' codes: Category:CS1 ISO 639-2 language sources. Languages that are the same as the local wiki are not categorized. MediaWiki does not recognize three-character equivalents of two-character codes: code 'ar' is recognized but code 'ara' is not. This function supports multiple languages in the form |language=nb, French, th where the language names or codes are separated from each other by commas with optional space characters. ]] local function language_parameter (lang) local tag; -- some form of IETF-like language tag; language subtag with optional region, sript, vatiant, etc subtags local lang_subtag; -- ve populates |language= with mostly unecessary region subtags that MediaWiki does not recognize; this is the base language subtag local name; -- the language name local language_list = {}; -- table of language names to be rendered local names_t = mw.text.split (lang, '%s*,%s*'); -- names should be a comma separated list for _, lang in ipairs (names_t) do -- reuse lang here because we don't yet know if lang is a language name or a language tag; for now, ignore linter warning name, tag = name_tag_get (lang); -- attempt to get name/tag pair for <lang>; <name> has proper capitalization; <tag> is lowercase if utilities.is_set (tag) then lang_subtag = tag:gsub ('^(%a%a%a?)%-.*', '%1'); -- for categorization, strip any IETF-like tags from language tag if cfg.this_wiki_code ~= lang_subtag then -- when the language is not the same as this wiki's language if 2 == lang_subtag:len() then -- and is a two-character tag utilities.add_prop_cat ('foreign-lang-source', {name, tag}, lang_subtag); -- categorize it; tag appended to allow for multiple language categorization else -- or is a recognized language (but has a three-character tag) utilities.add_prop_cat ('foreign-lang-source-2', {lang_subtag}, lang_subtag); -- categorize it differently TODO: support multiple three-character tag categories per cs1|2 template? end elseif cfg.local_lang_cat_enable then -- when the language and this wiki's language are the same and categorization is enabled utilities.add_prop_cat ('local-lang-source', {name, lang_subtag}); -- categorize it end else name = lang; -- return whatever <lang> has so that we show something utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added end table.insert (language_list, name); end name = utilities.make_sep_list (#language_list, language_list); if (1 == #language_list) and (lang_subtag == cfg.this_wiki_code) then -- when only one language, find lang name in this wiki lang name; for |language=en-us, 'English' in 'American English' return ''; -- if one language and that language is this wiki's return an empty string (no annotation) end return (" " .. wrap_msg ('language', name)); -- otherwise wrap with '(in ...)' --[[ TODO: should only return blank or name rather than full list so we can clean up the bunched parenthetical elements Language, Type, Format ]] end --[[-----------------------< S E T _ C S _ S T Y L E >-------------------------- Gets the default CS style configuration for the given mode. Returns default separator and either postscript as passed in or the default. In CS1, the default postscript and separator are '.'. In CS2, the default postscript is the empty string and the default separator is ','. ]] local function set_cs_style (postscript, mode) if utilities.is_set(postscript) then -- emit a maintenance message if user postscript is the default cs1 postscript -- we catch the opposite case for cs2 in set_style if mode == 'cs1' and postscript == cfg.presentation['ps_' .. mode] then utilities.set_message ('maint_postscript'); end else postscript = cfg.presentation['ps_' .. mode]; end return cfg.presentation['sep_' .. mode], postscript; end --[[--------------------------< S E T _ S T Y L E >----------------------------- Sets the separator and postscript styles. Checks the |mode= first and the #invoke CitationClass second. Removes the postscript if postscript == none. ]] local function set_style (mode, postscript, cite_class) local sep; if 'cs2' == mode then sep, postscript = set_cs_style (postscript, 'cs2'); elseif 'cs1' == mode then sep, postscript = set_cs_style (postscript, 'cs1'); elseif 'citation' == cite_class then sep, postscript = set_cs_style (postscript, 'cs2'); else sep, postscript = set_cs_style (postscript, 'cs1'); end if cfg.keywords_xlate[postscript:lower()] == 'none' then -- emit a maintenance message if user postscript is the default cs2 postscript -- we catch the opposite case for cs1 in set_cs_style if 'cs2' == mode or ('cs1' ~= mode and 'citation' == cite_class) then -- {{citation |title=Title |mode=cs1 |postscript=none}} should not emit maint message utilities.set_message ('maint_postscript'); end postscript = ''; end return sep, postscript end --[=[-------------------------< I S _ P D F >----------------------------------- Determines if a URL has the file extension that is one of the PDF file extensions used by [[MediaWiki:Common.css]] when applying the PDF icon to external links. returns true if file extension is one of the recognized extensions, else false ]=] local function is_pdf (url) return url:match ('%.pdf$') or url:match ('%.PDF$') or url:match ('%.pdf[%?#]') or url:match ('%.PDF[%?#]') or url:match ('%.PDF&#035') or url:match ('%.pdf&#035'); end --[[--------------------------< S T Y L E _ F O R M A T >----------------------- Applies CSS style to |format=, |chapter-format=, etc. Also emits an error message if the format parameter does not have a matching URL parameter. If the format parameter is not set and the URL contains a file extension that is recognized as a PDF document by MediaWiki's commons.css, this code will set the format parameter to (PDF) with the appropriate styling. ]] local function style_format (format, url, fmt_param, url_param) if utilities.is_set (format) then format = utilities.wrap_style ('format', format); -- add leading space, parentheses, resize if not utilities.is_set (url) then utilities.set_message ('err_format_missing_url', {fmt_param, url_param}); -- add an error message end elseif is_pdf (url) then -- format is not set so if URL is a PDF file then format = utilities.wrap_style ('format', 'PDF'); -- set format to PDF else format = ''; -- empty string for concatenation end return format; end --[[---------------------< G E T _ D I S P L A Y _ N A M E S >------------------ Returns a number that defines the number of names displayed for author and editor name lists and a Boolean flag to indicate when et al. should be appended to the name list. When the value assigned to |display-xxxxors= is a number greater than or equal to zero, return the number and the previous state of the 'etal' flag (false by default but may have been set to true if the name list contains some variant of the text 'et al.'). When the value assigned to |display-xxxxors= is the keyword 'etal', return a number that is one greater than the number of authors in the list and set the 'etal' flag true. This will cause the list_people() to display all of the names in the name list followed by 'et al.' In all other cases, returns nil and the previous state of the 'etal' flag. inputs: max: A['DisplayAuthors'] or A['DisplayEditors'], etc; a number or some flavor of etal count: #a or #e list_name: 'authors' or 'editors' etal: author_etal or editor_etal This function sets an error message when |display-xxxxors= value greater than or equal to number of names but not when <max> comes from {{cs1 config}} global settings. When using global settings, <param> is set to the keyword 'cs1 config' which is used to supress the normal error. Error is suppressed because it is to be expected that some citations in an article will have the same or fewer names that the limit specified in {{cs1 config}}. ]] local function get_display_names (max, count, etal, param) if utilities.is_set (max) then if 'etal' == cfg.keywords_xlate[max:lower():gsub("[ '%.]", '')] then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings max = count + 1; -- number of authors + 1 so display all author name plus et al. etal = true; -- overrides value set by extract_names() elseif max:match ('^%d+$') then -- if is a string of numbers max = tonumber (max); -- make it a number if (max >= count) and ('cs1 config' ~= param) then -- error when local |display-xxxxors= value greater than or equal to number of names; not an error when using global setting utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; end else -- not a valid keyword or number utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; -- unset; as if |display-xxxxors= had not been set end end return max, etal; end --[[----------< E X T R A _ T E X T _ I N _ P A G E _ C H E C K >--------------- Adds error if |page=, |pages=, |quote-page=, |quote-pages= has what appears to be some form of p. or pp. abbreviation in the first characters of the parameter content. check page for extraneous p, p., pp, pp., pg, pg. at start of parameter value: good pattern: '^P[^%.P%l]' matches when page begins PX or P# but not Px where x and X are letters and # is a digit bad pattern: '^[Pp][PpGg]' matches when page begins pp, pP, Pp, PP, pg, pG, Pg, PG ]] local function extra_text_in_page_check (val, name) if not val:match (cfg.vol_iss_pg_patterns.good_ppattern) then for _, pattern in ipairs (cfg.vol_iss_pg_patterns.bad_ppatterns) do -- spin through the selected sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message ('err_extra_text_pages', name); -- add error message return; -- and done end end end end --[[--------------------------< E X T R A _ T E X T _ I N _ V O L _ I S S _ C H E C K >------------------------ Adds error if |volume= or |issue= has what appears to be some form of redundant 'type' indicator. Applies to both; this function looks for issue text in both |issue= and |volume= and looks for volume-like text in |voluem= and |issue=. For |volume=: 'V.', or 'Vol.' (with or without the dot) abbreviations or 'Volume' in the first characters of the parameter content (all case insensitive). 'V' and 'v' (without the dot) are presumed to be roman numerals so are allowed. For |issue=: 'No.', 'I.', 'Iss.' (with or without the dot) abbreviations, or 'Issue' in the first characters of the parameter content (all case insensitive); numero styling: 'n°' with degree sign U+00B0, and № precomposed numero sign U+2116. Single character values ('v', 'i', 'n') allowed when not followed by separator character ('.', ':', '=', or whitespace character) – param values are trimmed of whitespace by MediaWiki before delivered to the module. <val> is |volume= or |issue= parameter value <name> is |volume= or |issue= parameter name for error message <selector> is 'v' for |volume=, 'i' for |issue= sets error message on failure; returns nothing ]] local function extra_text_in_vol_iss_check (val, name, selector) if not utilities.is_set (val) then return; end local handler = 'v' == selector and 'err_extra_text_volume' or 'err_extra_text_issue'; local accept_val; -- for now, ignore linter warning val, accept_val = utilities.has_accept_as_written (val); --if accept_val then -- if uncomment this, |volume=((vol. 1)) suppresses error -- return; --end --val = mw.text.unstripNoWiki (val); -- if uncomment this, |volume=<nowiki>vol. 1</nowiki> shows error val = val:lower(); -- force parameter value to lower case for _, pattern in ipairs (cfg.vol_iss_pg_patterns.vi_patterns_t) do -- spin through the sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message (handler, name); -- add error message return; -- and done end end end --[=[-------------------------< G E T _ V _ N A M E _ T A B L E >---------------------------------------------- split apart a |vauthors= or |veditors= parameter. This function allows for corporate names, wrapped in doubled parentheses to also have commas; in the old version of the code, the doubled parentheses were included in the rendered citation and in the metadata. Individual author names may be wikilinked |vauthors=Jones AB, [[E. B. White|White EB]], ((Black, Brown, and Co.)) ]=] local function get_v_name_table (vparam, output_table, output_link_table) local _, accept = utilities.has_accept_as_written (vparam); if accept then utilities.add_prop_cat ('vanc-accept'); -- add properties category end local name_table = mw.text.split(vparam, "%s*,%s*"); -- names are separated by commas local wl_type, label, link; -- wl_type not used here; just a placeholder local i = 1; while name_table[i] do if name_table[i]:match ('^%(%(.*[^%)][^%)]$') then -- first segment of corporate with one or more commas; this segment has the opening doubled parentheses local name = name_table[i]; i = i + 1; -- bump indexer to next segment while name_table[i] do name = name .. ', ' .. name_table[i]; -- concatenate with previous segments if name_table[i]:match ('^.*%)%)$') then -- if this table member has the closing doubled parentheses break; -- and done reassembling so end i = i + 1; -- bump indexer end table.insert (output_table, name); -- and add corporate name to the output table table.insert (output_link_table, ''); -- no wikilink else wl_type, label, link = utilities.is_wikilink (name_table[i]); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] table.insert (output_table, label); -- add this name if 1 == wl_type then table.insert (output_link_table, label); -- simple wikilink [[D]] else table.insert (output_link_table, link); -- no wikilink or [[L|D]]; add this link if there is one, else empty string end end i = i + 1; end return output_table; end --[[--------------------------< P A R S E _ V A U T H O R S _ V E D I T O R S >-------------------------------- This function extracts author / editor names from |vauthors= or |veditors= and finds matching |xxxxor-maskn= and |xxxxor-linkn= in args. It then returns a table of assembled names just as extract_names() does. Author / editor names in |vauthors= or |veditors= must be in Vancouver system style. Corporate or institutional names may sometimes be required and because such names will often fail the is_good_vanc_name() and other format compliance tests, are wrapped in doubled parentheses ((corporate name)) to suppress the format tests. Supports generational suffixes Jr, 2nd, 3rd, 4th–6th. This function sets the Vancouver error when a required comma is missing and when there is a space between an author's initials. ]] local function parse_vauthors_veditors (args, vparam, list_name) local names = {}; -- table of names assembled from |vauthors=, |author-maskn=, |author-linkn= local v_name_table = {}; local v_link_table = {}; -- when name is wikilinked, targets go in this table local etal = false; -- return value set to true when we find some form of et al. vauthors parameter local last, first, link, mask, suffix; local corporate = false; vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period) v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); -- names are separated by commas for i, v_name in ipairs(v_name_table) do first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor local accept_name; v_name, accept_name = utilities.has_accept_as_written (v_name); -- remove accept-this-as-written markup when it wraps all of <v_name> if accept_name then last = v_name; corporate = true; -- flag used in list_people() elseif string.find(v_name, "%s") then if v_name:find('[;%.]') then -- look for commonly occurring punctuation characters; add_vanc_error (cfg.err_msg_supl.punctuation, i); end local lastfirst_t = mw.text.split(v_name, "%s+"); first = table.remove (lastfirst_t); -- removes and returns value of last element in table which should be initials or generational suffix if not mw.ustring.match (first, '^%u+$') then -- mw.ustring here so that later we will catch non-Latin characters suffix = first; -- not initials so assume that whatever we got is a generational suffix first = table.remove (lastfirst_t); -- get what should be the initials from the table end last = table.concat (lastfirst_t, ' '); -- returns a string that is the concatenation of all other names that are not initials and generational suffix if not utilities.is_set (last) then first = ''; -- unset last = v_name; -- last empty because something wrong with first add_vanc_error (cfg.err_msg_supl.name, i); end if mw.ustring.match (last, '%a+%s+%u+%s+%a+') then add_vanc_error (cfg.err_msg_supl['missing comma'], i); -- matches last II last; the case when a comma is missing end if mw.ustring.match (v_name, ' %u %u$') then -- this test is in the wrong place TODO: move or replace with a more appropriate test add_vanc_error (cfg.err_msg_supl.initials, i); -- matches a space between two initials end else last = v_name; -- last name or single corporate name? Doesn't support multiword corporate names? do we need this? end if utilities.is_set (first) then if not mw.ustring.match (first, "^%u?%u$") then -- first shall contain one or two upper-case letters, nothing else add_vanc_error (cfg.err_msg_supl.initials, i); -- too many initials; mixed case initials (which may be ok Romanization); hyphenated initials end is_good_vanc_name (last, first, suffix, i); -- check first and last before restoring the suffix which may have a non-Latin digit if utilities.is_set (suffix) then first = first .. ' ' .. suffix; -- if there was a suffix concatenate with the initials suffix = ''; -- unset so we don't add this suffix to all subsequent names end else if not corporate then is_good_vanc_name (last, '', nil, i); end end link = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ) or v_link_table[i]; mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); names[i] = {last = last, first = first, link = link, mask = mask, corporate = corporate}; -- add this assembled name to our names list end return names, etal; -- all done, return our list of names end --[[--------------------------< S E L E C T _ A U T H O R _ E D I T O R _ S O U R C E >------------------------ Select one of |authors=, |authorn= / |lastn / firstn=, or |vauthors= as the source of the author name list or select one of |editorn= / editor-lastn= / |editor-firstn= or |veditors= as the source of the editor name list. Only one of these appropriate three will be used. The hierarchy is: |authorn= (and aliases) highest and |authors= lowest; |editorn= (and aliases) highest and |veditors= lowest (support for |editors= withdrawn) When looking for |authorn= / |editorn= parameters, test |xxxxor1= and |xxxxor2= (and all of their aliases); stops after the second test which mimicks the test used in extract_names() when looking for a hole in the author name list. There may be a better way to do this, I just haven't discovered what that way is. Emits an error message when more than one xxxxor name source is provided. In this function, vxxxxors = vauthors or veditors; xxxxors = authors as appropriate. ]] local function select_author_editor_source (vxxxxors, xxxxors, args, list_name) local lastfirst = false; if utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 1 ) or -- do this twice in case we have a |first1= without a |last1=; this ... utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 1 ) or -- ... also catches the case where |first= is used with |vauthors= utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 2 ) or utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 2 ) then lastfirst = true; end if (utilities.is_set (vxxxxors) and true == lastfirst) or -- these are the three error conditions (utilities.is_set (vxxxxors) and utilities.is_set (xxxxors)) or (true == lastfirst and utilities.is_set (xxxxors)) then utilities.set_message ('err_redundant_parameters', utilities.substitute (cfg.special_case_translation.name_list_params, ('AuthorList' == list_name) and cfg.special_case_translation.author or cfg.special_case_translation.editor)); -- add error message end if true == lastfirst then return 1 end; -- return a number indicating which author name source to use if utilities.is_set (vxxxxors) then return 2 end; if utilities.is_set (xxxxors) then return 3 end; return 1; -- no authors so return 1; this allows missing author name test to run in case there is a first without last end --[[--------------------------< I S _ V A L I D _ P A R A M E T E R _ V A L U E >------------------------------ This function is used to validate a parameter's assigned value for those parameters that have only a limited number of allowable values (yes, y, true, live, dead, etc.). When the parameter value has not been assigned a value (missing or empty in the source template) the function returns the value specified by ret_val. If the parameter value is one of the list of allowed values returns the translated value; else, emits an error message and returns the value specified by ret_val. TODO: explain <invert> ]] local function is_valid_parameter_value (value, name, possible, ret_val, invert) if not utilities.is_set (value) then return ret_val; -- an empty parameter is ok end if (not invert and utilities.in_array (value, possible)) then -- normal; <value> is in <possible> table return cfg.keywords_xlate[value]; -- return translation of parameter keyword elseif invert and not utilities.in_array (value, possible) then -- invert; <value> is not in <possible> table return value; -- return <value> as it is else utilities.set_message ('err_invalid_param_val', {name, value}); -- not an allowed value so add error message return ret_val; end end --[[--------------------------< T E R M I N A T E _ N A M E _ L I S T >---------------------------------------- This function terminates a name list (author, contributor, editor) with a separator character (sepc) and a space when the last character is not a sepc character or when the last three characters are not sepc followed by two closing square brackets (close of a wikilink). When either of these is true, the name_list is terminated with a single space character. ]] local function terminate_name_list (name_list, sepc) if (string.sub (name_list, -3, -1) == sepc .. '. ') then -- if already properly terminated return name_list; -- just return the name list elseif (string.sub (name_list, -1, -1) == sepc) or (string.sub (name_list, -3, -1) == sepc .. ']]') then -- if last name in list ends with sepc char return name_list .. " "; -- don't add another else return name_list .. sepc .. ' '; -- otherwise terminate the name list end end --[[-------------------------< F O R M A T _ V O L U M E _ I S S U E >----------------------------------------- returns the concatenation of the formatted volume and issue (or journal article number) parameters as a single string; or formatted volume or formatted issue, or an empty string if neither are set. ]] local function format_volume_issue (volume, issue, article, cite_class, origin, sepc, lower) if not utilities.is_set (volume) and not utilities.is_set (issue) and not utilities.is_set (article) then return ''; end -- same condition as in format_pages_sheets() local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); local is_numeric_vol = volume and (volume:match ('^[MDCLXVI]+$') or volume:match ('^%d+$')); -- is only uppercase roman numerals or only digits? local is_long_vol = volume and (4 < mw.ustring.len(volume)); -- is |volume= value longer than 4 characters? if volume and (not is_numeric_vol and is_long_vol) then -- when not all digits or Roman numerals, is |volume= longer than 4 characters? utilities.add_prop_cat ('long-vol'); -- yes, add properties cat end if is_journal then -- journal-style formatting local vol = ''; if utilities.is_set (volume) then if is_numeric_vol then -- |volume= value all digits or all uppercase Roman numerals? vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, volume}); -- render in bold face elseif is_long_vol then -- not all digits or Roman numerals; longer than 4 characters? vol = utilities.substitute (cfg.messages['j-vol'], {sepc, utilities.hyphen_to_dash (volume)}); -- not bold else -- four or fewer characters vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, utilities.hyphen_to_dash (volume)}); -- bold end end vol = vol .. (utilities.is_set (issue) and utilities.substitute (cfg.messages['j-issue'], issue) or '') vol = vol .. (utilities.is_set (article) and utilities.substitute (cfg.messages['j-article-num'], article) or '') return vol; end if 'podcast' == cite_class and utilities.is_set (issue) then return wrap_msg ('issue', {sepc, issue}, lower); end if 'conference' == cite_class and utilities.is_set (article) then -- |article-number= supported only in journal and conference cites if utilities.is_set (volume) and utilities.is_set (article) then -- both volume and article number return wrap_msg ('vol-art', {sepc, utilities.hyphen_to_dash (volume), article}, lower); elseif utilities.is_set (article) then -- article number alone; when volume alone, handled below return wrap_msg ('art', {sepc, article}, lower); end end -- all other types of citation if utilities.is_set (volume) and utilities.is_set (issue) then return wrap_msg ('vol-no', {sepc, utilities.hyphen_to_dash (volume), issue}, lower); elseif utilities.is_set (volume) then return wrap_msg ('vol', {sepc, utilities.hyphen_to_dash (volume)}, lower); else return wrap_msg ('issue', {sepc, issue}, lower); end end --[[-------------------------< F O R M A T _ P A G E S _ S H E E T S >----------------------------------------- adds static text to one of |page(s)= or |sheet(s)= values and returns it with all of the others set to empty strings. The return order is: page, pages, sheet, sheets Singular has priority over plural when both are provided. ]] local function format_pages_sheets (page, pages, sheet, sheets, cite_class, origin, sepc, nopp, lower) if 'map' == cite_class then -- only cite map supports sheet(s) as in-source locators if utilities.is_set (sheet) then if 'journal' == origin then return '', '', wrap_msg ('j-sheet', sheet, lower), ''; else return '', '', wrap_msg ('sheet', {sepc, sheet}, lower), ''; end elseif utilities.is_set (sheets) then if 'journal' == origin then return '', '', '', wrap_msg ('j-sheets', sheets, lower); else return '', '', '', wrap_msg ('sheets', {sepc, sheets}, lower); end end end local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); if utilities.is_set (page) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], page), '', '', ''; elseif not nopp then return utilities.substitute (cfg.messages['p-prefix'], {sepc, page}), '', '', ''; else return utilities.substitute (cfg.messages['nopp'], {sepc, page}), '', '', ''; end elseif utilities.is_set (pages) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], pages), '', '', ''; elseif tonumber(pages) ~= nil and not nopp then -- if pages is only digits, assume a single page number return '', utilities.substitute (cfg.messages['p-prefix'], {sepc, pages}), '', ''; elseif not nopp then return '', utilities.substitute (cfg.messages['pp-prefix'], {sepc, pages}), '', ''; else return '', utilities.substitute (cfg.messages['nopp'], {sepc, pages}), '', ''; end end return '', '', '', ''; -- return empty strings end --[[--------------------------< I N S O U R C E _ L O C _ G E T >---------------------------------------------- returns one of the in-source locators: page, pages, or at. If any of these are interwiki links to Wikisource, returns the label portion of the interwiki-link as plain text for use in COinS. This COinS thing is done because here we convert an interwiki-link to an external link and add an icon span around that; get_coins_pages() doesn't know about the span. TODO: should it? TODO: add support for sheet and sheets?; streamline; TODO: make it so that this function returns only one of the three as the single in-source (the return value assigned to a new name)? ]] local function insource_loc_get (page, page_orig, pages, pages_orig, at) local ws_url, ws_label, coins_pages, L; -- for Wikisource interwiki-links; TODO: this corrupts page metadata (span remains in place after cleanup; fix there?) if utilities.is_set (page) then if utilities.is_set (pages) or utilities.is_set (at) then pages = ''; -- unset the others at = ''; end extra_text_in_page_check (page, page_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (page); -- make ws URL from |page= interwiki link; link portion L becomes tooltip label if ws_url then page = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in page'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? page = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, page}); coins_pages = ws_label; end elseif utilities.is_set (pages) then if utilities.is_set (at) then at = ''; -- unset end extra_text_in_page_check (pages, pages_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (pages); -- make ws URL from |pages= interwiki link; link portion L becomes tooltip label if ws_url then pages = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in pages'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? pages = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, pages}); coins_pages = ws_label; end elseif utilities.is_set (at) then ws_url, ws_label, L = wikisource_url_make (at); -- make ws URL from |at= interwiki link; link portion L becomes tooltip label if ws_url then at = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in at'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? at = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, at}); coins_pages = ws_label; end end return page, pages, at, coins_pages; end --[[--------------------------< I S _ U N I Q U E _ A R C H I V E _ U R L >------------------------------------ add error message when |archive-url= value is same as |url= or chapter-url= (or alias...) value ]] local function is_unique_archive_url (archive, url, c_url, source, date) if utilities.is_set (archive) then if archive == url or archive == c_url then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); -- add error message return '', ''; -- unset |archive-url= and |archive-date= because same as |url= or |chapter-url= end end return archive, date; end --[=[-------------------------< A R C H I V E _ U R L _ C H E C K >-------------------------------------------- Check archive.org URLs to make sure they at least look like they are pointing at valid archives and not to the save snapshot URL or to calendar pages. When the archive URL is 'https://web.archive.org/save/' (or http://...) archive.org saves a snapshot of the target page in the URL. That is something that Wikipedia should not allow unwitting readers to do. When the archive.org URL does not have a complete timestamp, archive.org chooses a snapshot according to its own algorithm or provides a calendar 'search' result. [[WP:ELNO]] discourages links to search results. This function looks at the value assigned to |archive-url= and returns empty strings for |archive-url= and |archive-date= and an error message when: |archive-url= holds an archive.org save command URL |archive-url= is an archive.org URL that does not have a complete timestamp (YYYYMMDDhhmmss 14 digits) in the correct place otherwise returns |archive-url= and |archive-date= There are two mostly compatible archive.org URLs: //web.archive.org/<timestamp>... -- the old form //web.archive.org/web/<timestamp>... -- the new form The old form does not support or map to the new form when it contains a display flag. There are four identified flags ('id_', 'js_', 'cs_', 'im_') but since archive.org ignores others following the same form (two letters and an underscore) we don't check for these specific flags but we do check the form. This function supports a preview mode. When the article is rendered in preview mode, this function may return a modified archive URL: for save command errors, return undated wildcard (/*/) for timestamp errors when the timestamp has a wildcard, return the URL unmodified for timestamp errors when the timestamp does not have a wildcard, return with timestamp limited to six digits plus wildcard (/yyyymm*/) A secondary function is to return an archive-url timestamp from those archive urls that have them. The timestamp is used by validation.archive_date_check() to see if the value in |archive-date= matches the timestamp in the archive url. ]=] local function archive_url_check (url, date) local err_msg; -- start with the error message empty local path, timestamp, flag; -- portions of the archive.org URL local function is_ts_date_valid (ts, origin_date) -- local function to validate archive url taimestamp date; time ignored local y, m, d = ts:match ('(%d%d%d%d)(%d%d)(%d%d)'); -- split into parts if y and validation.is_valid_date (y, m, d) and (tonumber (y) >= 1996) then return true, tonumber (y) >= origin_date; -- <origin_date> is 1996 for archive.org end end if (not url:match('//web%.archive%.org/')) and (not url:match('//liveweb%.archive%.org/')) then -- also deprecated liveweb Wayback machine URL return url, date; -- not an archive.org archive, return ArchiveURL and ArchiveDate end if url:match('//web%.archive%.org/save/') then -- if a save command URL, we don't want to allow saving of the target page err_msg = cfg.err_msg_supl.save; url = url:gsub ('(//web%.archive%.org)/save/', '%1/*/', 1); -- for preview mode: modify ArchiveURL elseif url:match('//liveweb%.archive%.org/') then err_msg = cfg.err_msg_supl.liveweb; else path, timestamp, flag = url:match('//web%.archive%.org/([^%d]*)(%d+)([^/]*)/'); -- split out some of the URL parts for evaluation if not path then -- malformed in some way; pattern did not match err_msg = cfg.err_msg_supl.timestamp; elseif 14 ~= timestamp:len() then -- path and flag optional, must have 14-digit timestamp here err_msg = cfg.err_msg_supl.timestamp; if '*' ~= flag then local replacement = timestamp:match ('^%d%d%d%d%d%d') or timestamp:match ('^%d%d%d%d'); -- get the first 6 (YYYYMM) or first 4 digits (YYYY) if replacement then -- nil if there aren't at least 4 digits (year) replacement = replacement .. string.rep ('0', 14 - replacement:len()); -- year or yearmo (4 or 6 digits) zero-fill to make 14-digit timestamp url=url:gsub ('(//web%.archive%.org/[^%d]*)%d[^/]*', '%1' .. replacement .. '*', 1) -- for preview, modify ts to 14 digits plus splat for calendar display end end elseif not is_ts_date_valid (timestamp, 1996) then -- is ymd portion of timestamp a valid date? err_msg = cfg.err_msg_supl.timestamp; timestamp = nil; -- unset because invalid elseif utilities.is_set (path) and 'web/' ~= path then -- older archive URLs do not have the extra 'web/' path element err_msg = cfg.err_msg_supl.path; elseif utilities.is_set (flag) and not utilities.is_set (path) then -- flag not allowed with the old form URL (without the 'web/' path element) err_msg = cfg.err_msg_supl.flag; elseif utilities.is_set (flag) and not flag:match ('%a%a_') then -- flag if present must be two alpha characters and underscore (requires 'web/' path element) err_msg = cfg.err_msg_supl.flag; else return url, date, timestamp; -- return ArchiveURL, ArchiveDate, and timestamp from |archive-url= end end -- if here, something not right so utilities.set_message ('err_archive_url', {err_msg}); -- add error message and if is_preview_mode then return url, date, timestamp; -- preview mode so return ArchiveURL, ArchiveDate, and timestamp from |archive-url= else return '', ''; -- return empty strings for ArchiveURL and ArchiveDate end end --[[--------------------------< P L A C E _ C H E C K >-------------------------------------------------------- check |place=, |publication-place=, |location= to see if these params include digits. This function added because many editors misuse location to specify the in-source location (|page(s)= and |at= are supposed to do that) returns the original parameter value without modification; added maint cat when parameter value contains digits ]] local function place_check (param_val) if not utilities.is_set (param_val) then -- parameter empty or omitted return param_val; -- return that empty state end if mw.ustring.find (param_val, '%d') then -- not empty, are there digits in the parameter value utilities.set_message ('maint_location'); -- yep, add maint cat end return param_val; -- and done end --[[--------------------------< I S _ A R C H I V E D _ C O P Y >---------------------------------------------- compares |title= to 'Archived copy' (placeholder added by bots that can't find proper title); if matches, return true; nil else ]] local function is_archived_copy (title) title = mw.ustring.lower(title); -- switch title to lower case if title:find (cfg.special_case_translation.archived_copy.en) then -- if title is 'Archived copy' return true; elseif cfg.special_case_translation.archived_copy['local'] then if mw.ustring.find (title, cfg.special_case_translation.archived_copy['local']) then -- mw.ustring() because might not be Latin script return true; end end end --[[--------------------------< D I S P L A Y _ N A M E S _ S E L E C T >-------------------------------------- for any of the |display-authors=, |display-editors=, etc parameters, select either the local or global setting. When both are present, look at <local_display_names> value. When the value is some sort of 'et al.'string, special handling is required. When {{cs1 config}} has |display-<namelist>= AND this template has |display-<namelist>=etal AND: the number of names specified by <number_of_names> is: greater than the number specified in the global |display-<namelist>= parameter (<global_display_names>) use global |display-<namelist>= parameter value set overridden maint category less than or equal to the number specified in the global |display-<namelist>= parameter use local |display-<namelist>= parameter value The purpose of this function is to prevent categorizing a template that has fewer names than the global setting to keep the etal annotation specified by <local_display_names>. ]] local function display_names_select (global_display_names, local_display_names, param_name, number_of_names) if global_display_names and utilities.is_set (local_display_names) then -- when both if 'etal' == local_display_names:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings number_of_names = tonumber (number_of_names); -- convert these to numbers for comparison local global_display_names_num = tonumber (global_display_names); -- <global_display_names> not set when parameter value is not digits if number_of_names > global_display_names_num then -- template has more names than global config allows to be displayed? utilities.set_message ('maint_overridden_setting'); -- set a maint message because global is overriding local |display-<namelist>=etal return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local because fewer names so let <local_display_names> control end end -- here when <global_display_names> and <local_display_names> both numbers; <global_display_names> controls utilities.set_message ('maint_overridden_setting'); -- set a maint message return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) end -- here when only one of <global_display_names> or <local_display_names> set if global_display_names then return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local end end --[[--------------------------< M O D E _ S E T >-------------------------------------------------------------- fetch global mode setting from {{cs1 config}} (if present) or from |mode= (if present); global setting overrides local |mode= parameter value. When both are present, emit maintenance message ]] local function mode_set (Mode, Mode_origin) local mode; if cfg.global_cs1_config_t['Mode'] then -- global setting in {{cs1 config}}; nil when empty or assigned value invalid mode = is_valid_parameter_value (cfg.global_cs1_config_t['Mode'], 'cs1 config: mode', cfg.keywords_lists['mode'], ''); -- error messaging 'param' here is a hoax else mode = is_valid_parameter_value (Mode, Mode_origin, cfg.keywords_lists['mode'], ''); end if cfg.global_cs1_config_t['Mode'] and utilities.is_set (Mode) then -- when template has |mode=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end return mode; end --[[--------------------------< Q U O T E _ M A K E >---------------------------------------------------------- create quotation from |quote=, |trans-quote=, and/or script-quote= with or without |quote-page= or |quote-pages= when any of those three quote parameters are set, this function unsets <PostScript>. When none of those parameters are set, |quote-page= and |quote-pages= are unset to nil so that they are not included in the template's metadata ]] local function quote_make (quote, trans_quote, script_quote, quote_page, quote_pages, nopp, sepc, postscript) if utilities.is_set (quote) or utilities.is_set (trans_quote) or utilities.is_set (script_quote) then if utilities.is_set (quote) then if quote:sub(1, 1) == '"' and quote:sub(-1, -1) == '"' then -- if first and last characters of quote are quote marks quote = quote:sub(2, -2); -- strip them off end end quote = kern_quotes (quote); -- kern if needed quote = utilities.wrap_style ('quoted-text', quote ); -- wrap in <q>...</q> tags if utilities.is_set (script_quote) then quote = script_concatenate (quote, script_quote, 'script-quote'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after quote is wrapped end if utilities.is_set (trans_quote) then if trans_quote:sub(1, 1) == '"' and trans_quote:sub(-1, -1) == '"' then -- if first and last characters of |trans-quote are quote marks trans_quote = trans_quote:sub(2, -2); -- strip them off end quote = quote .. " " .. utilities.wrap_style ('trans-quoted-title', trans_quote ); end if utilities.is_set (quote_page) or utilities.is_set (quote_pages) then -- add page prefix local quote_prefix = ''; if utilities.is_set (quote_page) then extra_text_in_page_check (quote_page, 'quote-page'); -- add to maint cat if |quote-page= value begins with what looks like p., pp., etc. if not nopp then quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_page}); else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_page}); end elseif utilities.is_set (quote_pages) then extra_text_in_page_check (quote_pages, 'quote-pages'); -- add to maint cat if |quote-pages= value begins with what looks like p., pp., etc. if tonumber(quote_pages) ~= nil and not nopp then -- if only digits, assume single page quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_pages}); elseif not nopp then quote_prefix = utilities.substitute (cfg.messages['pp-prefix'], {sepc, quote_pages}); else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_pages}); end end quote = quote_prefix .. ": " .. quote; else quote = sepc .. " " .. quote; end postscript = ""; -- cs1|2 does not supply terminal punctuation when |quote= is set elseif utilities.is_set (quote_page) or utilities.is_set (quote_pages) then quote_page = nil; -- unset; these require |quote=; TODO: error message? quote_pages = nil; end return quote, quote_page, quote_pages, postscript; end --[[--------------------------< C H E C K _ P U B L I S H E R _ N A M E >-------------------------------------- look for variations of '<text>: <text>' that might be '<location>: <publisher>' in |publisher= parameter value. when found, emit a maintenance message; return nil else <publisher> is the value assigned to |publisher= or |institution= ]] local function check_publisher_name (publisher) local patterns_t = { '^[%w%s]+%s*:%s*[%w%s]+$', -- plain text <location>: <publisher> '^%[+[%w%s:|]+%]+%s*:%s*[%w%s]+$', -- partially wikilinked [[<location>]]: <publisher> '^[%w%s]+%s*:%s*%[+[%w%s:|]+%]+$', -- partially wikilinked <location>: [[<publisher>]] '^%[+[%w%s:|]+%]+%s*:%s*%[+[%w%s:|]+%]+$', -- wikilinked [[<location>]]: [[<publisher>]] } for _, pattern in ipairs (patterns_t) do -- spin through the patterns_t sequence if mw.ustring.match (publisher, pattern) then -- does this pattern match? utilities.set_message ('maint_publisher_location'); -- set a maint message return; -- and done end end end --[[--------------------------< I S _ P A G E _ A R T _ N U M >------------------------------------------------ compare the trailing (rightmost) characters of the |doi= value against the whole value assigned to |page(s)=. return boolean true when: |page(s)= has exactly 8 digits and a dot between the fourth and fifth digits matches the trailing 9 characters of the |doi= value: |page=12345678 → |page=1234.5678 matches |doi=10.xxxx/yyyy1234.5678 |page(s)= is 5 or more characters and matches |doi= values's trailing characters |page(s)= begins with a lowercase 'e' and |page(s)= without the 'e' matches |doi= values's trailing characters: |page=e12345 → |page=12345 matches |doi=10.xxxx/yyyy12345 |page(s)= begins with a uppercase 'CD' followed by (typically) six digits matches |doi= values that ends with 'CDxxxxxx.pubx' (where 'x' is any single digit) return nil when |page(s)= values: are ranges separated by underscore, hyphen, emdash, endash, figure dash, or minus character are comma- or semicolon-separated lists of pages have external urls (has text 'http') are digit-only values less than 10000 do not match |doi= values's trailing characters ]] local function is_page_art_num (page, doi) if not (utilities.is_set (page) and utilities.is_set (doi)) then -- both required return; -- abandon; nothing to do end if page:match ('[,;_−–—‒%-]') then -- when |page(s)= might be a page range or a separated list of pages return; -- abandon end page = page:lower(); -- because doi names are case insensitive doi = doi:lower(); -- force these to lowercase for testing if page:match ('http') then -- when |page(s)= appears to hold a url return; -- abandon end if tonumber (page) then -- is |page(s)= digits only if 10000 > tonumber (page) then -- when |page(s)= less than 10000 return; -- abandon end if doi:match (page .. '$') then -- digits only page number match the last digits in |doi=? return true; end if 8 == page:len() then -- special case when |page(s)= is exactly 8 digits local dot_page = page:gsub ('(%d%d%d%d)(%d%d%d%d)', '%1.%2'); -- make a |page=xxxx.yyyy version commonly used in |doi= if doi:match (dot_page .. '$') then -- 8-digit dotted page number match the last characters in |doi=? return true; end end else -- here when |page(s)= is alpha-numeric if 4 < page:len() then -- when |page(s)= is five or more characters if doi:match (page .. '$') then -- alpha-numeric page match the last characters in |doi=? return true; end local epage = page:match ('^e([%w]+)$'); -- if first character of |page= is 'e', remove it if epage and doi:match (epage .. '$') then -- page number match the last characters in |doi=? return true; end local cdpage = page:match ('^cd%d+$'); -- if first characters of |page= are 'CD' and last characters are digits (typically 6 digits) if cdpage and doi:match (cdpage .. '%.pub%d$') then -- page number matches doi 'CDxxxxxx.pubx' where 'x' is a digit return true; end end end end --[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------ This is the main function doing the majority of the citation formatting. ]] local function citation0( config, args ) --[[ Load Input Parameters The argument_wrapper facilitates the mapping of multiple aliases to single internal variable. ]] local A = argument_wrapper ( args ); -- Pick out the relevant fields from the arguments. Different citation templates -- define different field names for the same underlying things. local author_etal; local a = {}; -- authors list from |lastn= / |firstn= pairs or |vauthors= local Authors; local NameListStyle; if cfg.global_cs1_config_t['NameListStyle'] then -- global setting in {{cs1 config}} overrides local |name-list-style= parameter value; nil when empty or assigned value invalid NameListStyle = is_valid_parameter_value (cfg.global_cs1_config_t['NameListStyle'], 'cs1 config: name-list-style', cfg.keywords_lists['name-list-style'], ''); -- error messaging 'param' here is a hoax else NameListStyle = is_valid_parameter_value (A['NameListStyle'], A:ORIGIN('NameListStyle'), cfg.keywords_lists['name-list-style'], ''); end if cfg.global_cs1_config_t['NameListStyle'] and utilities.is_set (A['NameListStyle']) then -- when template has |name-list-style=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end local Collaboration = A['Collaboration']; do -- to limit scope of selected local selected = select_author_editor_source (A['Vauthors'], A['Authors'], args, 'AuthorList'); if 1 == selected then a, author_etal = extract_names (args, 'AuthorList'); -- fetch author list from |authorn= / |lastn= / |firstn=, |author-linkn=, and |author-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be a, author_etal = parse_vauthors_veditors (args, A['Vauthors'], 'AuthorList'); -- fetch author list from |vauthors=, |author-linkn=, and |author-maskn= elseif 3 == selected then Authors = A['Authors']; -- use content of |people= or |credits=; |authors= is deprecated; TODO: constrain |people= and |credits= to cite av media, episode, serial? end if utilities.is_set (Collaboration) then author_etal = true; -- so that |display-authors=etal not required end end local editor_etal; local e = {}; -- editors list from |editor-lastn= / |editor-firstn= pairs or |veditors= do -- to limit scope of selected local selected = select_author_editor_source (A['Veditors'], nil, args, 'EditorList'); -- support for |editors= withdrawn if 1 == selected then e, editor_etal = extract_names (args, 'EditorList'); -- fetch editor list from |editorn= / |editor-lastn= / |editor-firstn=, |editor-linkn=, and |editor-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be e, editor_etal = parse_vauthors_veditors (args, args.veditors, 'EditorList'); -- fetch editor list from |veditors=, |editor-linkn=, and |editor-maskn= end end local Chapter = A['Chapter']; -- done here so that we have access to |contribution= from |chapter= and |script-chapter= aliases local Chapter_origin = A:ORIGIN ('Chapter'); local ScriptChapter = A['ScriptChapter']; local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); local Contribution; -- because contribution is required for contributor(s) if 'contribution' == Chapter_origin then -- is there a |contribution= parameter? Contribution = Chapter; -- get the name of the contribution elseif 'script-contribution' == ScriptChapter_origin then -- no, so is there a |script-contribution= parameter? Contribution = ScriptChapter; -- get the name of the contribution end local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (A['Periodical']) then -- |contributor= and |contribution= only supported in book cites c = extract_names (args, 'ContributorList'); -- fetch contributor list from |contributorn= / |contributor-lastn=, -firstn=, -linkn=, -maskn= if 0 < #c then if not utilities.is_set (Contribution) then -- |contributor= requires |contribution= utilities.set_message ('err_contributor_missing_required_param', 'contribution'); -- add missing contribution error message c = {}; -- blank the contributors' table; it is used as a flag later end if 0 == #a then -- |contributor= requires |author= utilities.set_message ('err_contributor_missing_required_param', 'author'); -- add missing author error message c = {}; -- blank the contributors' table; it is used as a flag later end end else -- if not a book cite if utilities.select_one (args, cfg.aliases['ContributorList-Last'], 'err_redundant_parameters', 1 ) then -- are there contributor name list parameters? utilities.set_message ('err_contributor_ignored'); -- add contributor ignored error message end Contribution = nil; -- unset end local Title = A['Title']; local TitleLink = A['TitleLink']; local auto_select = ''; -- default is auto local accept_link; TitleLink, accept_link = utilities.has_accept_as_written (TitleLink, true); -- test for accept-this-as-written markup if (not accept_link) and utilities.in_array (TitleLink, {'none', 'pmc', 'doi'}) then -- check for special keywords auto_select = TitleLink; -- remember selection for later TitleLink = ''; -- treat as if |title-link= would have been empty end TitleLink = link_title_ok (TitleLink, A:ORIGIN ('TitleLink'), Title, 'title'); -- check for wiki-markup in |title-link= or wiki-markup in |title= when |title-link= is set local Section = ''; -- {{cite map}} only; preset to empty string for concatenation if not used if 'map' == config.CitationClass and 'section' == Chapter_origin then Section = A['Chapter']; -- get |section= from |chapter= alias list; |chapter= and the other aliases not supported in {{cite map}} Chapter = ''; -- unset for now; will be reset later from |map= if present end local Periodical = A['Periodical']; local Periodical_origin = A:ORIGIN('Periodical'); local ScriptPeriodical = A['ScriptPeriodical']; local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical'); local TransPeriodical = A['TransPeriodical']; local TransPeriodical_origin = A:ORIGIN ('TransPeriodical'); if (utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical))) then local param; if utilities.is_set (Periodical) then -- get a parameter name from one of these periodical related meta-parameters Periodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = Periodical_origin -- get parameter name for error messaging elseif utilities.is_set (TransPeriodical) then TransPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = TransPeriodical_origin; -- get parameter name for error messaging elseif utilities.is_set (ScriptPeriodical) then ScriptPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = ScriptPeriodical_origin; -- get parameter name for error messaging end if utilities.is_set (param) then -- if we found one utilities.set_message ('err_periodical_ignored', {param}); -- emit an error message end end if utilities.is_set (Periodical) then local i; Periodical, i = utilities.strip_apostrophe_markup (Periodical); -- strip apostrophe markup so that metadata isn't contaminated if i then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {Periodical_origin}); end end if 'mailinglist' == config.CitationClass then -- special case for {{cite mailing list}} if utilities.is_set (Periodical) and utilities.is_set (A ['MailingList']) then -- both set emit an error TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', Periodical_origin) .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'mailinglist')}); end Periodical = A ['MailingList']; -- error or no, set Periodical to |mailinglist= value because this template is {{cite mailing list}} Periodical_origin = A:ORIGIN('MailingList'); end -- web and news not tested for now because of -- Wikipedia:Administrators%27_noticeboard#Is_there_a_semi-automated_tool_that_could_fix_these_annoying_"Cite_Web"_errors? if not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) then -- 'periodical' templates require periodical parameter -- local p = {['journal'] = 'journal', ['magazine'] = 'magazine', ['news'] = 'newspaper', ['web'] = 'website'}; -- for error message local p = {['journal'] = 'journal', ['magazine'] = 'magazine'}; -- for error message if p[config.CitationClass] then utilities.set_message ('err_missing_periodical', {config.CitationClass, p[config.CitationClass]}); end end local Volume; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) then if not utilities.in_array (Periodical_origin, cfg.citation_no_volume_t) then -- {{citation}} does not render |volume= when these parameters are used Volume = A['Volume']; -- but does for all other 'periodicals' end elseif utilities.is_set (ScriptPeriodical) then if 'script-website' ~= ScriptPeriodical_origin then -- {{citation}} does not render volume for |script-website= Volume = A['Volume']; -- but does for all other 'periodicals' end else Volume = A['Volume']; -- and does for non-'periodical' cites end elseif utilities.in_array (config.CitationClass, cfg.templates_using_volume) then -- render |volume= for cs1 according to the configuration settings Volume = A['Volume']; end extra_text_in_vol_iss_check (Volume, A:ORIGIN ('Volume'), 'v'); local Issue; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) and utilities.in_array (Periodical_origin, cfg.citation_issue_t) then -- {{citation}} may render |issue= when these parameters are used Issue = A['Issue']; end elseif utilities.in_array (config.CitationClass, cfg.templates_using_issue) then -- conference & map books do not support issue; {{citation}} listed here because included in settings table if not (utilities.in_array (config.CitationClass, {'conference', 'map', 'citation'}) and not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical))) then Issue = A['Issue']; end end local ArticleNumber; if utilities.in_array (config.CitationClass, {'journal', 'conference'}) or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then ArticleNumber = A['ArticleNumber']; end extra_text_in_vol_iss_check (Issue, A:ORIGIN ('Issue'), 'i'); Issue = utilities.hyphen_to_dash (Issue); local Page; local Pages; local At; local QuotePage; local QuotePages; if not utilities.in_array (config.CitationClass, cfg.templates_not_using_page) then -- TODO: rewrite to emit ignored parameter error message? Page = A['Page']; Pages = utilities.hyphen_to_dash (A['Pages']); At = A['At']; QuotePage = A['QuotePage']; QuotePages = utilities.hyphen_to_dash (A['QuotePages']); end local NoPP = is_valid_parameter_value (A['NoPP'], A:ORIGIN('NoPP'), cfg.keywords_lists['yes_true_y'], nil); local Mode = mode_set (A['Mode'], A:ORIGIN('Mode')); -- separator character and postscript local sepc, PostScript = set_style (Mode:lower(), A['PostScript'], config.CitationClass); local Quote; Quote, QuotePage, QuotePages, PostScript = quote_make (A['Quote'], A['TransQuote'], A['ScriptQuote'], QuotePage, QuotePages, NoPP, sepc, PostScript); local Edition = A['Edition']; local PublicationPlace = place_check (A['PublicationPlace'], A:ORIGIN('PublicationPlace')); local Place = place_check (A['Place'], A:ORIGIN('Place')); local PublisherName = A['PublisherName']; local PublisherName_origin = A:ORIGIN('PublisherName'); if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then local i; PublisherName, i = utilities.strip_apostrophe_markup (PublisherName); -- strip apostrophe markup so that metadata isn't contaminated; publisher is never italicized if i and (0 < i) then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {PublisherName_origin}); end end if ('document' == config.CitationClass) and not utilities.is_set (PublisherName) then utilities.set_message ('err_missing_publisher', {config.CitationClass, 'publisher'}); end local Newsgroup = A['Newsgroup']; -- TODO: strip apostrophe markup? local Newsgroup_origin = A:ORIGIN('Newsgroup'); if 'newsgroup' == config.CitationClass then if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then -- general use parameter |publisher= not allowed in cite newsgroup utilities.set_message ('err_parameter_ignored', {PublisherName_origin}); end PublisherName = nil; -- ensure that this parameter is unset for the time being; will be used again after COinS end if 'book' == config.CitationClass or 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then local accept; PublisherName, accept = utilities.has_accept_as_written (PublisherName); -- check for and remove accept-as-written markup from |publisher= wrapped if not accept then -- when no accept-as-written markup check_publisher_name (PublisherName); -- emit maint message when |publisher= might be prefixed with publisher's location end end local URL = A['URL']; -- TODO: better way to do this for URL, ChapterURL, and MapURL? local UrlAccess = is_valid_parameter_value (A['UrlAccess'], A:ORIGIN('UrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (URL) and utilities.is_set (UrlAccess) then UrlAccess = nil; utilities.set_message ('err_param_access_requires_param', 'url'); end local ChapterURL = A['ChapterURL']; local ChapterUrlAccess = is_valid_parameter_value (A['ChapterUrlAccess'], A:ORIGIN('ChapterUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (ChapterURL) and utilities.is_set (ChapterUrlAccess) then ChapterUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {A:ORIGIN('ChapterUrlAccess'):gsub ('%-access', '')}); end local MapUrlAccess = is_valid_parameter_value (A['MapUrlAccess'], A:ORIGIN('MapUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (A['MapURL']) and utilities.is_set (MapUrlAccess) then MapUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {'map-url'}); end local this_page = mw.title.getCurrentTitle(); -- also used for COinS and for language local no_tracking_cats = is_valid_parameter_value (A['NoTracking'], A:ORIGIN('NoTracking'), cfg.keywords_lists['yes_true_y'], nil); -- check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories if not utilities.is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page if cfg.uncategorized_namespaces[this_page.namespace] then -- is this page's namespace id one of the uncategorized namespace ids? no_tracking_cats = "true"; -- set no_tracking_cats end for _, v in ipairs (cfg.uncategorized_subpages) do -- cycle through page name patterns if this_page.text:match (v) then -- test page name against each pattern no_tracking_cats = "true"; -- set no_tracking_cats break; -- bail out if one is found end end end -- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it) utilities.select_one (args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'err_redundant_parameters'); -- this is a dummy call simply to get the error message and category local coins_pages; Page, Pages, At, coins_pages = insource_loc_get (Page, A:ORIGIN('Page'), Pages, A:ORIGIN('Pages'), At); if utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- both |publication-place= and |place= (|location=) allowed if different utilities.add_prop_cat ('location-test'); -- add property cat to evaluate how often PublicationPlace and Place are used together if PublicationPlace == Place then Place = ''; -- unset; don't need both if they are the same end elseif not utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- when only |place= (|location=) is set ... PublicationPlace = Place; -- promote |place= (|location=) to |publication-place end if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same local URL_origin = A:ORIGIN('URL'); -- get name of parameter that holds URL local ChapterURL_origin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL -- local ScriptChapter = A['ScriptChapter']; -- local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); local Format = A['Format']; local ChapterFormat = A['ChapterFormat']; local TransChapter = A['TransChapter']; local TransChapter_origin = A:ORIGIN ('TransChapter'); local TransTitle = A['TransTitle']; local ScriptTitle = A['ScriptTitle']; --[[ Parameter remapping for cite encyclopedia: When the citation has these parameters: |encyclopedia= and |title= then map |title= to |article= and |encyclopedia= to |title= for rendering |encyclopedia= and |article= then map |encyclopedia= to |title= for rendering |trans-title= maps to |trans-chapter= when |title= is re-mapped |url= maps to |chapter-url= when |title= is remapped All other combinations of |encyclopedia=, |title=, and |article= are not modified ]] local Encyclopedia = A['Encyclopedia']; -- used as a flag by this module and by ~/COinS local ScriptEncyclopedia = A['ScriptEncyclopedia']; local TransEncyclopedia = A['TransEncyclopedia']; if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then -- emit error message when Encyclopedia set but template is other than {{cite encyclopedia}} or {{citation}} if 'encyclopaedia' ~= config.CitationClass and 'citation' ~= config.CitationClass then if utilities.is_set (Encyclopedia) then utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('Encyclopedia')}); else utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('ScriptEncyclopedia')}); end Encyclopedia = nil; -- unset these because not supported by this template ScriptEncyclopedia = nil; TransEncyclopedia = nil; end elseif utilities.is_set (TransEncyclopedia) then utilities.set_message ('err_trans_missing_title', {'encyclopedia'}); end if ('encyclopaedia' == config.CitationClass) or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Periodical) and utilities.is_set (Encyclopedia) then -- when both parameters set emit an error message; {{citation}} only; Periodical not allowed in {{cite encyclopedia}} utilities.set_message ('err_periodical_ignored', {Periodical_origin}); end if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then Periodical = Encyclopedia; -- error or no, set Periodical to Encyclopedia for rendering; {{citation}} could (not legitimately) have both; use Encyclopedia Periodical_origin = A:ORIGIN ('Encyclopedia'); ScriptPeriodical = ScriptEncyclopedia; ScriptPeriodical_origin = A:ORIGIN ('ScriptEncyclopedia'); if utilities.is_set (Title) or utilities.is_set (ScriptTitle) then if not utilities.is_set (Chapter) then Chapter = Title; -- |encyclopedia= and |title= are set so map |title= params to |article= params for rendering ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle') TransChapter = TransTitle; ChapterURL = URL; ChapterURL_origin = URL_origin; ChapterUrlAccess = UrlAccess; ChapterFormat = Format; if not utilities.is_set (ChapterURL) and utilities.is_set (TitleLink) then Chapter = utilities.make_wikilink (TitleLink, Chapter); end Title = Periodical; -- now map |encyclopedia= params to |title= params for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; URL = ''; Format = ''; TitleLink = ''; end elseif utilities.is_set (Chapter) or utilities.is_set (ScriptChapter) then -- |title= not set Title = Periodical; -- |encyclopedia= set and |article= set so map |encyclopedia= to |title= for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; end end end -- special case for cite techreport. local ID = A['ID']; if (config.CitationClass == "techreport") then -- special case for cite techreport if utilities.is_set (A['Number']) then -- cite techreport uses 'number', which other citations alias to 'issue' if not utilities.is_set (ID) then -- can we use ID for the "number"? ID = A['Number']; -- yes, use it else -- ID has a value so emit error message utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'id') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'number')}); end end end -- Account for the oddity that is {{cite conference}}, before generation of COinS data. local ChapterLink -- = A['ChapterLink']; -- deprecated as a parameter but still used internally by cite episode local Conference = A['Conference']; local BookTitle = A['BookTitle']; local TransTitle_origin = A:ORIGIN ('TransTitle'); if 'conference' == config.CitationClass then if utilities.is_set (BookTitle) then Chapter = Title; Chapter_origin = 'title'; -- ChapterLink = TitleLink; -- |chapter-link= is deprecated ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; URL_origin = ''; ChapterFormat = Format; TransChapter = TransTitle; TransChapter_origin = TransTitle_origin; Title = BookTitle; Format = ''; -- TitleLink = ''; TransTitle = ''; URL = ''; end elseif 'speech' ~= config.CitationClass then Conference = ''; -- not cite conference or cite speech so make sure this is empty string end local cs2_lower = function (text) -- if mode is cs2, use lower case if (sepc ~= '.') then return text:lower(); end return text; end local use_lowercase = ( sepc == ',' ); -- controls capitalization of certain static text -- cite map oddities local Cartography = ""; local Scale = ""; local Sheet = A['Sheet'] or ''; local Sheets = A['Sheets'] or ''; if config.CitationClass == "map" then if utilities.is_set (Chapter) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'map') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', Chapter_origin)}); -- add error message end Chapter = A['Map']; Chapter_origin = A:ORIGIN('Map'); -- for now, ignore linter warning ChapterURL = A['MapURL']; ChapterURL_origin = A:ORIGIN('MapURL'); TransChapter = A['TransMap']; ScriptChapter = A['ScriptMap'] ScriptChapter_origin = A:ORIGIN('ScriptMap') ChapterUrlAccess = MapUrlAccess; ChapterFormat = A['MapFormat']; Cartography = A['Cartography']; if utilities.is_set ( Cartography ) then Cartography = sepc .. " " .. wrap_msg ('cartography', Cartography, use_lowercase); end Scale = A['Scale']; if utilities.is_set ( Scale ) then Scale = sepc .. " " .. Scale; end end -- Account for the oddities that are {{cite episode}} and {{cite serial}}, before generation of COinS data. local Series = A['Series']; if 'episode' == config.CitationClass or 'serial' == config.CitationClass then local SeriesLink = A['SeriesLink']; SeriesLink = link_title_ok (SeriesLink, A:ORIGIN ('SeriesLink'), Series, 'series'); -- check for wiki-markup in |series-link= or wiki-markup in |series= when |series-link= is set local Network = A['Network']; local Station = A['Station']; local s, n = {}, {}; -- do common parameters first if utilities.is_set (Network) then table.insert(n, Network); end if utilities.is_set (Station) then table.insert(n, Station); end ID = table.concat(n, sepc .. ' '); if 'episode' == config.CitationClass then -- handle the oddities that are strictly {{cite episode}} local Season = A['Season']; local SeriesNumber = A['SeriesNumber']; if utilities.is_set (Season) and utilities.is_set (SeriesNumber) then -- these are mutually exclusive so if both are set TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'season') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'seriesno')}); -- add error message SeriesNumber = ''; -- unset; prefer |season= over |seriesno= end -- assemble a table of parts concatenated later into Series if utilities.is_set (Season) then table.insert(s, wrap_msg ('season', Season, use_lowercase)); end if utilities.is_set (SeriesNumber) then table.insert(s, wrap_msg ('seriesnum', SeriesNumber, use_lowercase)); end if utilities.is_set (Issue) then table.insert(s, wrap_msg ('episode', Issue, use_lowercase)); end Issue = ''; -- unset because this is not a unique parameter Chapter = Title; -- promote title parameters to chapter ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle'); ChapterLink = TitleLink; -- alias |episode-link= TransChapter = TransTitle; ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; ChapterFormat = Format; Title = Series; -- promote series to title TitleLink = SeriesLink; Series = table.concat(s, sepc .. ' '); -- this is concatenation of season, seriesno, episode number if utilities.is_set (ChapterLink) and not utilities.is_set (ChapterURL) then -- link but not URL Chapter = utilities.make_wikilink (ChapterLink, Chapter); elseif utilities.is_set (ChapterLink) and utilities.is_set (ChapterURL) then -- if both are set, URL links episode; Series = utilities.make_wikilink (ChapterLink, Series); end URL = ''; -- unset TransTitle = ''; ScriptTitle = ''; Format = ''; else -- now oddities that are cite serial Issue = ''; -- unset because this parameter no longer supported by the citation/core version of cite serial Chapter = A['Episode']; -- TODO: make |episode= available to cite episode someday? if utilities.is_set (Series) and utilities.is_set (SeriesLink) then Series = utilities.make_wikilink (SeriesLink, Series); end Series = utilities.wrap_style ('italic-title', Series); -- series is italicized end end -- end of {{cite episode}} stuff -- handle type parameter for those CS1 citations that have default values local TitleType = A['TitleType']; local Degree = A['Degree']; if utilities.in_array (config.CitationClass, {'AV-media-notes', 'document', 'interview', 'mailinglist', 'map', 'podcast', 'pressrelease', 'report', 'speech', 'techreport', 'thesis'}) then TitleType = set_titletype (config.CitationClass, TitleType); if utilities.is_set (Degree) and "Thesis" == TitleType then -- special case for cite thesis TitleType = Degree .. ' ' .. cfg.title_types ['thesis']:lower(); end end if utilities.is_set (TitleType) then -- if type parameter is specified TitleType = utilities.substitute ( cfg.messages['type'], TitleType); -- display it in parentheses -- TODO: Hack on TitleType to fix bunched parentheses problem end -- legacy: promote PublicationDate to Date if neither Date nor Year are set. local Date = A['Date']; local Date_origin; -- to hold the name of parameter promoted to Date; required for date error messaging local PublicationDate = A['PublicationDate']; local Year = A['Year']; if utilities.is_set (Year) then validation.year_check (Year); -- returns nothing; emits maint message when |year= doesn't hold a 'year' value end if not utilities.is_set (Date) then Date = Year; -- promote Year to Date Year = nil; -- make nil so Year as empty string isn't used for CITEREF if not utilities.is_set (Date) and utilities.is_set (PublicationDate) then -- use PublicationDate when |date= and |year= are not set Date = PublicationDate; -- promote PublicationDate to Date PublicationDate = ''; -- unset, no longer needed Date_origin = A:ORIGIN('PublicationDate'); -- save the name of the promoted parameter else Date_origin = A:ORIGIN('Year'); -- save the name of the promoted parameter end else Date_origin = A:ORIGIN('Date'); -- not a promotion; name required for error messaging end if PublicationDate == Date then PublicationDate = ''; end -- if PublicationDate is same as Date, don't display in rendered citation --[[ Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates. This must be done before we do COinS because here is where we get the date used in the metadata. Date validation supporting code is in Module:Citation/CS1/Date_validation ]] local DF = is_valid_parameter_value (A['DF'], A:ORIGIN('DF'), cfg.keywords_lists['df'], ''); if not utilities.is_set (DF) then DF = cfg.global_df; -- local |df= if present overrides global df set by {{use xxx date}} template end local ArchiveURL; local ArchiveDate; local ArchiveFormat = A['ArchiveFormat']; local archive_url_timestamp; -- timestamp from wayback machine url ArchiveURL, ArchiveDate, archive_url_timestamp = archive_url_check (A['ArchiveURL'], A['ArchiveDate']) ArchiveFormat = style_format (ArchiveFormat, ArchiveURL, 'archive-format', 'archive-url'); ArchiveURL, ArchiveDate = is_unique_archive_url (ArchiveURL, URL, ChapterURL, A:ORIGIN('ArchiveURL'), ArchiveDate); -- add error message when URL or ChapterURL == ArchiveURL local AccessDate = A['AccessDate']; local COinS_date = {}; -- holds date info extracted from |date= for the COinS metadata by Module:Date verification local DoiBroken = A['DoiBroken']; local Embargo = A['Embargo']; local anchor_year; -- used in the CITEREF identifier do -- create defined block to contain local variables date_parameters_list, mismatch local date_parameters_list = { -- AirDate has been promoted to Date so not necessary to check it ['access-date'] = {val = AccessDate, name = A:ORIGIN ('AccessDate')}, ['archive-date'] = {val = ArchiveDate, name = A:ORIGIN ('ArchiveDate')}, ['date'] = {val = Date, name = Date_origin}, ['doi-broken-date'] = {val = DoiBroken, name = A:ORIGIN ('DoiBroken')}, ['pmc-embargo-date'] = {val = Embargo, name = A:ORIGIN ('Embargo')}, ['publication-date'] = {val = PublicationDate, name = A:ORIGIN ('PublicationDate')}, ['year'] = {val = Year, name = A:ORIGIN ('Year')}, }; local error_list = {}; anchor_year, Embargo = validation.dates(date_parameters_list, COinS_date, error_list); if utilities.is_set (Year) and utilities.is_set (Date) then -- both |date= and |year= not normally needed; validation.year_date_check (Year, A:ORIGIN ('Year'), Date, A:ORIGIN ('Date'), error_list); end if 0 == #error_list then -- error free dates only; 0 when error_list is empty local modified = false; -- flag if utilities.is_set (DF) then -- if we need to reformat dates modified = validation.reformat_dates (date_parameters_list, DF); -- reformat to DF format, use long month names if appropriate end if true == validation.date_hyphen_to_dash (date_parameters_list) then -- convert hyphens to dashes where appropriate modified = true; utilities.set_message ('maint_date_format'); -- hyphens were converted so add maint category end -- for those wikis that can and want to have English date names translated to the local language; not supported at en.wiki if cfg.date_name_auto_xlate_enable and validation.date_name_xlate (date_parameters_list, cfg.date_digit_auto_xlate_enable ) then utilities.set_message ('maint_date_auto_xlated'); -- add maint cat modified = true; end if modified then -- if the date_parameters_list values were modified AccessDate = date_parameters_list['access-date'].val; -- overwrite date holding parameters with modified values ArchiveDate = date_parameters_list['archive-date'].val; Date = date_parameters_list['date'].val; DoiBroken = date_parameters_list['doi-broken-date'].val; PublicationDate = date_parameters_list['publication-date'].val; end if archive_url_timestamp and utilities.is_set (ArchiveDate) then validation.archive_date_check (ArchiveDate, archive_url_timestamp, DF); -- does YYYYMMDD in archive_url_timestamp match date in ArchiveDate end else utilities.set_message ('err_bad_date', {utilities.make_sep_list (#error_list, error_list)}); -- add this error message end end -- end of do if utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) or -- {{cite book}}, {{cite encyclopedia}}; TODO: {{cite conference}} and others? ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) or -- {{citation}} as an encylopedia citation ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then -- {{citation}} as a book citation if utilities.is_set (PublicationPlace) then if not utilities.is_set (PublisherName) then local date = COinS_date.rftdate and tonumber (COinS_date.rftdate:match ('%d%d%d%d')); -- get year portion of COinS date (because in Arabic numerals); convert string to number if date and (1850 <= date) then -- location has no publisher; if date is 1850 or later utilities.set_message ('maint_location_no_publisher'); -- add maint cat end else -- PublisherName has a value if cfg.keywords_xlate['none'] == PublisherName then -- if that value is 'none' (only for book and encyclopedia citations) PublisherName = ''; -- unset end end end end local ID_list_t; -- sequence table of rendered identifiers local ID_list_coins_t; -- table of identifiers and their values from args; key is same as cfg.id_handlers's key local Class = A['Class']; -- arxiv class identifier local ID_support = { {A['ASINTLD'], 'ASIN', 'err_asintld_missing_asin', A:ORIGIN ('ASINTLD')}, {DoiBroken, 'DOI', 'err_doibroken_missing_doi', A:ORIGIN ('DoiBroken')}, {Embargo, 'PMC', 'err_embargo_missing_pmc', A:ORIGIN ('Embargo')}, } ID_list_t, ID_list_coins_t = identifiers.identifier_lists_get (args, { DoiBroken = DoiBroken, -- for |doi= ASINTLD = A['ASINTLD'], -- for |asin= Embargo = Embargo, -- for |pmc= Class = Class, -- for |arxiv= CitationClass = config.CitationClass, -- for |arxiv= Year=anchor_year, -- for |isbn= }, ID_support); for _, id in ipairs (ID_list_t) do -- search through the ID_list_t sequence looking for an ISBN identifier string if id:find ('ISBN', 3, true) then -- plain find, start at index 3 ([[ISBN) if 'citation' == config.CitationClass then -- catch ve/citoid malformed book cites in {{citation}} templates if utilities.is_set (Periodical) then -- when a |work= alias is set utilities.set_message ('maint_work_isbn'); -- add maint cat break; -- and abandon end elseif ({['journal'] = true, ['magazine'] = true, ['news'] = true, ['web'] = true})[config.CitationClass] then utilities.set_message ('maint_periodical_has_isbn'); -- add maint cat break; -- and abandon end end end -- if 'citation' == config.CitationClass then -- catch ve/citoid malformed book cites in {{citation}} templates -- for _, id in ipairs (ID_list_t) do -- search through the ID_list_t sequence looking for an ISBN identifier string -- if id:find ('ISBN', 3, true) then -- plain find, start at index 3 ([[ISBN) -- if utilities.is_set (Periodical) then -- when a |work= alias is set -- utilities.set_message ('maint_work_isbn'); -- add maint cat -- end -- end -- end -- end -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, {{cite ssrn}}, before generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv=, |citeseerx=, |medrxiv=, |ssrn= required for their templates if not (args[cfg.id_handlers[config.CitationClass:upper()].parameters[1]] or -- can't use ID_list_coins_t k/v table here because invalid parameters omitted args[cfg.id_handlers[config.CitationClass:upper()].parameters[2]]) then -- which causes unexpected parameter missing error message utilities.set_message ('err_' .. config.CitationClass .. '_missing'); -- add error message end Periodical = ({['arxiv'] = 'arXiv', ['biorxiv'] = 'bioRxiv', ['citeseerx'] = 'CiteSeerX', ['medrxiv'] = 'medRxiv', ['ssrn'] = 'Social Science Research Network'})[config.CitationClass]; end -- Link the title of the work if no |url= was provided, but we have a |pmc= or a |doi= with |doi-access=free if config.CitationClass == "journal" and not utilities.is_set (URL) and not utilities.is_set (TitleLink) and not utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) then -- TODO: remove 'none' once existing citations have been switched to 'off', so 'none' can be used as token for "no title" instead if 'none' ~= cfg.keywords_xlate[auto_select] then -- if auto-linking not disabled if identifiers.auto_link_urls[auto_select] then -- manual selection URL = identifiers.auto_link_urls[auto_select]; -- set URL to be the same as identifier's external link URL_origin = cfg.id_handlers[auto_select:upper()].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['pmc'] then -- auto-select PMC URL = identifiers.auto_link_urls['pmc']; -- set URL to be the same as the PMC external link if not embargoed URL_origin = cfg.id_handlers['PMC'].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['doi'] then -- auto-select DOI URL = identifiers.auto_link_urls['doi']; URL_origin = cfg.id_handlers['DOI'].parameters[1]; end end if utilities.is_set (URL) then -- set when using an identifier-created URL if utilities.is_set (AccessDate) then -- |access-date= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_accessdate_missing_url'); -- add an error message AccessDate = ''; -- unset end if utilities.is_set (ArchiveURL) then -- |archive-url= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_archive_missing_url'); -- add an error message ArchiveURL = ''; -- unset end end end -- At this point fields may be nil if they weren't specified in the template use. We can use that fact. -- Test if citation has no title if not utilities.is_set (Title) and not utilities.is_set (TransTitle) and not utilities.is_set (ScriptTitle) then -- has special case for cite episode utilities.set_message ('err_citation_missing_title', {'episode' == config.CitationClass and 'series' or 'title'}); end if utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) and utilities.in_array (config.CitationClass, {'journal', 'citation'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and ('journal' == Periodical_origin or 'script-journal' == ScriptPeriodical_origin) then -- special case for journal cites Title = ''; -- set title to empty string utilities.set_message ('maint_untitled'); -- add maint cat end if 'journal' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then if is_page_art_num (((utilities.is_set (Page) and Page) or (utilities.is_set (Pages) and Pages)) or nil, ID_list_coins_t['DOI']) then -- does |page(s)= look like it holds an article number utilities.set_message ('maint_page_art_num'); -- add maint cat end end -- COinS metadata (see <http://ocoins.info/>) for automated parsing of citation information. -- handle the oddity that is cite encyclopedia and {{citation |encyclopedia=something}}. Here we presume that -- when Periodical, Title, and Chapter are all set, then Periodical is the book (encyclopedia) title, Title -- is the article title, and Chapter is a section within the article. So, we remap local coins_chapter = Chapter; -- default assuming that remapping not required local coins_title = Title; -- et tu if 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Chapter) and utilities.is_set (Title) and utilities.is_set (Periodical) then -- if all are used then coins_chapter = Title; -- remap coins_title = Periodical; end end local coins_author = a; -- default for coins rft.au if 0 < #c then -- but if contributor list coins_author = c; -- use that instead end -- this is the function call to COinS() local OCinSoutput = metadata.COinS({ ['Periodical'] = utilities.strip_apostrophe_markup (Periodical), -- no markup in the metadata ['Encyclopedia'] = Encyclopedia, -- just a flag; content ignored by ~/COinS ['Chapter'] = metadata.make_coins_title (coins_chapter, ScriptChapter), -- Chapter and ScriptChapter stripped of bold / italic / accept-as-written markup ['Degree'] = Degree; -- cite thesis only ['Title'] = metadata.make_coins_title (coins_title, ScriptTitle), -- Title and ScriptTitle stripped of bold / italic / accept-as-written markup ['PublicationPlace'] = PublicationPlace, ['Date'] = COinS_date.rftdate, -- COinS_date.* has correctly formatted date values if Date is valid; ['Season'] = COinS_date.rftssn, ['Quarter'] = COinS_date.rftquarter, ['Chron'] = COinS_date.rftchron, ['Series'] = Series, ['Volume'] = Volume, ['Issue'] = Issue, ['ArticleNumber'] = ArticleNumber, ['Pages'] = coins_pages or metadata.get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At, QuotePage, QuotePages}, 7)), -- pages stripped of external links ['Edition'] = Edition, ['PublisherName'] = PublisherName or Newsgroup, -- any apostrophe markup already removed from PublisherName ['URL'] = first_set ({ChapterURL, URL}, 2), ['Authors'] = coins_author, ['ID_list'] = ID_list_coins_t, ['RawPage'] = this_page.prefixedText, }, config.CitationClass); -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, and {{cite ssrn}} AFTER generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- we have set rft.jtitle in COinS to arXiv, bioRxiv, CiteSeerX, medRxiv, or ssrn now unset so it isn't displayed Periodical = ''; -- periodical not allowed in these templates; if article has been published, use cite journal end -- special case for cite newsgroup. Do this after COinS because we are modifying Publishername to include some static text if 'newsgroup' == config.CitationClass and utilities.is_set (Newsgroup) then PublisherName = utilities.substitute (cfg.messages['newsgroup'], external_link( 'news:' .. Newsgroup, Newsgroup, Newsgroup_origin, nil )); end local Editors; local EditorCount; -- used only for choosing {ed.) or (eds.) annotation at end of editor name-list local Contributors; -- assembled contributors name list local contributor_etal = nil; -- must be intentionally initialized local Translators; -- assembled translators name list local translator_etal = nil; -- must be intentionally initialized local t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= local Interviewers; local interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters local interviewer_etal = nil; -- must be intentionally initialized -- Now perform various field substitutions. -- We also add leading spaces and surrounding markup and punctuation to the -- various parts of the citation, but only when they are non-nil. do local last_first_list; local control = { format = NameListStyle, -- empty string, '&', 'amp', 'and', or 'vanc' maximum = nil, -- as if display-authors or display-editors not set mode = Mode }; do -- do editor name list first because the now unsupported coauthors used to modify control table local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayEditors'], A['DisplayEditors'], A:ORIGIN ('DisplayEditors'), #e); control.maximum, editor_etal = get_display_names (display_names, #e, editor_etal, param); Editors, EditorCount = list_people (control, e, editor_etal); if 1 == EditorCount and (true == editor_etal or 1 < #e) then -- only one editor displayed but includes etal then EditorCount = 2; -- spoof to display (eds.) annotation end end do -- now do interviewers local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayInterviewers'], A['DisplayInterviewers'], A:ORIGIN ('DisplayInterviewers'), #interviewers_list); control.maximum, interviewer_etal = get_display_names (display_names, #interviewers_list, interviewer_etal, param); Interviewers = list_people (control, interviewers_list, interviewer_etal); end do -- now do translators local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayTranslators'], A['DisplayTranslators'], A:ORIGIN ('DisplayTranslators'), #t); control.maximum, translator_etal = get_display_names (display_names, #t, translator_etal, param); Translators = list_people (control, t, translator_etal); end do -- now do contributors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayContributors'], A['DisplayContributors'], A:ORIGIN ('DisplayContributors'), #c); control.maximum, contributor_etal = get_display_names (display_names, #c, contributor_etal, param); Contributors = list_people (control, c, contributor_etal); end do -- now do authors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayAuthors'], A['DisplayAuthors'], A:ORIGIN ('DisplayAuthors'), #a, author_etal); control.maximum, author_etal = get_display_names (display_names, #a, author_etal, param); last_first_list = list_people (control, a, author_etal); if utilities.is_set (Authors) then Authors, author_etal = name_has_etal (Authors, author_etal, false, 'authors'); -- find and remove variations on et al. if author_etal then Authors = Authors .. ' ' .. cfg.messages['et al']; -- add et al. to authors parameter end else Authors = last_first_list; -- either an author name list or an empty string end end -- end of do if utilities.is_set (Authors) and utilities.is_set (Collaboration) then Authors = utilities.substitute (cfg.messages['collaboration'], {Authors, Collaboration}); -- add collaboration after et al. end end local ConferenceFormat = A['ConferenceFormat']; local ConferenceURL = A['ConferenceURL']; ConferenceFormat = style_format (ConferenceFormat, ConferenceURL, 'conference-format', 'conference-url'); Format = style_format (Format, URL, 'format', 'url'); -- special case for chapter format so no error message or cat when chapter not supported if not (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia))) then ChapterFormat = style_format (ChapterFormat, ChapterURL, 'chapter-format', 'chapter-url'); end if not utilities.is_set (URL) then if utilities.in_array (config.CitationClass, {"web", "podcast", "mailinglist"}) or -- |url= required for {{cite web}}, {{cite podcast}}, and {{cite mailing list}} ('citation' == config.CitationClass and ('website' == Periodical_origin or 'script-website' == ScriptPeriodical_origin)) then -- and required for {{citation}} with |website= or |script-website= if not url_was_archive_today then -- is <URL> empty/missing because it was a deprecated archive.today url utilities.set_message ('err_cite_web_url'); -- no; emit an error message for an empty/ missing |url= end end -- do we have |accessdate= without either |url= or |chapter-url=? if utilities.is_set (AccessDate) and not utilities.is_set (ChapterURL) then -- ChapterURL may be set when URL is not set; utilities.set_message ('err_accessdate_missing_url'); AccessDate = ''; end end local UrlStatus = is_valid_parameter_value (A['UrlStatus'], A:ORIGIN('UrlStatus'), cfg.keywords_lists['url-status'], ''); local OriginalURL local OriginalURL_origin local OriginalFormat local OriginalAccess; UrlStatus = UrlStatus:lower(); -- used later when assembling archived text if utilities.is_set ( ArchiveURL ) then if utilities.is_set (ChapterURL) then -- if chapter-url= is set apply archive url to it OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text OriginalURL_origin = ChapterURL_origin; -- name of |chapter-url= parameter for error messages OriginalFormat = ChapterFormat; -- and original |chapter-format= if 'live' ~= UrlStatus then ChapterURL = ArchiveURL -- swap-in the archive's URL ChapterURL_origin = A:ORIGIN('ArchiveURL') -- name of |archive-url= parameter for error messages ChapterFormat = ArchiveFormat or ''; -- swap in archive's format ChapterUrlAccess = nil; -- restricted access levels do not make sense for archived URLs end elseif utilities.is_set (URL) then OriginalURL = URL; -- save copy of original source URL OriginalURL_origin = URL_origin; -- name of URL parameter for error messages OriginalFormat = Format; -- and original |format= OriginalAccess = UrlAccess; if 'live' ~= UrlStatus then -- if URL set then |archive-url= applies to it URL = ArchiveURL -- swap-in the archive's URL URL_origin = A:ORIGIN('ArchiveURL') -- name of archive URL parameter for error messages Format = ArchiveFormat or ''; -- swap in archive's format UrlAccess = nil; -- restricted access levels do not make sense for archived URLs end end elseif utilities.is_set (UrlStatus) then -- if |url-status= is set when |archive-url= is not set utilities.set_message ('maint_url_status'); -- add maint cat end if utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or -- if any of the 'periodical' cites except encyclopedia ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) then local chap_param; if utilities.is_set (Chapter) then -- get a parameter name from one of these chapter related meta-parameters chap_param = A:ORIGIN ('Chapter') elseif utilities.is_set (TransChapter) then chap_param = A:ORIGIN ('TransChapter') elseif utilities.is_set (ChapterURL) then chap_param = A:ORIGIN ('ChapterURL') elseif utilities.is_set (ScriptChapter) then chap_param = ScriptChapter_origin; else utilities.is_set (ChapterFormat) chap_param = A:ORIGIN ('ChapterFormat') end if utilities.is_set (chap_param) then -- if we found one utilities.set_message ('err_chapter_ignored', {chap_param}); -- add error message Chapter = ''; -- and set them to empty string to be safe with concatenation TransChapter = ''; -- for now, ignore linter warnings ChapterURL = ''; ScriptChapter = ''; ChapterFormat = ''; end else -- otherwise, format chapter / article title local no_quotes = false; -- default assume that we will be quoting the chapter parameter value if utilities.is_set (Contribution) and 0 < #c then -- if this is a contribution with contributor(s) if utilities.in_array (Contribution:lower(), cfg.keywords_lists.contribution) then -- and a generic contribution title no_quotes = true; -- then render it unquoted end end Chapter = format_chapter_title (ScriptChapter, ScriptChapter_origin, Chapter, TransChapter, TransChapter_origin, ChapterURL, ChapterURL_origin, no_quotes, ChapterUrlAccess); -- Contribution is also in Chapter if utilities.is_set (Chapter) then Chapter = Chapter .. ChapterFormat ; if 'map' == config.CitationClass and utilities.is_set (TitleType) then Chapter = Chapter .. ' ' .. TitleType; -- map annotation here; not after title end Chapter = Chapter .. sepc .. ' '; elseif utilities.is_set (ChapterFormat) then -- |chapter= not set but |chapter-format= is so ... Chapter = ChapterFormat .. sepc .. ' '; -- ... ChapterFormat has error message, we want to see it end end -- Format main title local plain_title = false; local accept_title; Title, accept_title = utilities.has_accept_as_written (Title, true); -- remove accept-this-as-written markup when it wraps all of <Title> if accept_title and ('' == Title) then -- only support forced empty for now "(())" Title = cfg.messages['notitle']; -- replace by predefined "No title" message -- TODO: utilities.set_message ( 'err_redundant_parameters', ...); -- issue proper error message instead of muting ScriptTitle = ''; -- just mute for now TransTitle = ''; -- just mute for now plain_title = true; -- suppress text decoration for descriptive title utilities.set_message ('maint_untitled'); -- add maint cat end if not accept_title then -- <Title> not wrapped in accept-as-written markup if '...' == Title:sub (-3) then -- if ellipsis is the last three characters of |title= Title = Title:gsub ('(%.%.%.)%.+$', '%1'); -- limit the number of dots to three elseif not mw.ustring.find (Title, '%.%s*%a%.$') and -- end of title is not a 'dot-(optional space-)letter-dot' initialism ... not mw.ustring.find (Title, '%s+%a%.$') then -- ...and not a 'space-letter-dot' initial (''Allium canadense'' L.) Title = mw.ustring.gsub(Title, '%' .. sepc .. '$', ''); -- remove any trailing separator character; sepc and ms.ustring() here for languages that use multibyte separator characters end if utilities.is_set (ArchiveURL) and is_archived_copy (Title) then utilities.set_message ('maint_archived_copy'); -- add maintenance category before we modify the content of Title end if is_generic ('generic_titles', Title) then utilities.set_message ('err_generic_title'); -- set an error message end end if (not plain_title) and (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'document', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) or ('map' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)))) then -- special case for cite map when the map is in a periodical treat as an article Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from module provided quote marks Title = utilities.wrap_style ('quoted-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); elseif plain_title or ('report' == config.CitationClass) then -- no styling for cite report and descriptive titles (otherwise same as above) Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); -- for cite report, use this form for trans-title else Title = utilities.wrap_style ('italic-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-italic-title', TransTitle); end if utilities.is_set (TransTitle) then if utilities.is_set (Title) then TransTitle = " " .. TransTitle; else utilities.set_message ('err_trans_missing_title', {'title'}); end end if utilities.is_set (Title) then -- TODO: is this the right place to be making Wikisource URLs? if utilities.is_set (TitleLink) and utilities.is_set (URL) then utilities.set_message ('err_wikilink_in_url'); -- set an error message because we can't have both TitleLink = ''; -- unset end if not utilities.is_set (TitleLink) and utilities.is_set (URL) then Title = external_link (URL, Title, URL_origin, UrlAccess) .. TransTitle .. Format; URL = ''; -- unset these because no longer needed Format = ''; -- for now, ignore linter warning elseif utilities.is_set (TitleLink) and not utilities.is_set (URL) then local ws_url; ws_url = wikisource_url_make (TitleLink); -- ignore ws_label return; not used here if ws_url then Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title-link'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], TitleLink, Title}); Title = Title .. TransTitle; else Title = utilities.make_wikilink (TitleLink, Title) .. TransTitle; end else local ws_url, ws_label, L; -- Title has italic or quote markup by the time we get here which causes is_wikilink() to return 0 (not a wikilink) ws_url, ws_label, L = wikisource_url_make (Title:gsub('^[\'"]*(.-)[\'"]*$', '%1')); -- make ws URL from |title= interwiki link (strip italic or quote markup); link portion L becomes tooltip label if ws_url then Title = Title:gsub ('%b[]', ws_label); -- replace interwiki link with ws_label to retain markup Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, Title}); Title = Title .. TransTitle; else Title = Title .. TransTitle; end end else Title = TransTitle; end if utilities.is_set (Place) then Place = " " .. wrap_msg ('written', Place, use_lowercase) .. sepc .. " "; end local ConferenceURL_origin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL if utilities.is_set (Conference) then if utilities.is_set (ConferenceURL) then Conference = external_link( ConferenceURL, Conference, ConferenceURL_origin, nil ); end Conference = sepc .. " " .. Conference .. ConferenceFormat; elseif utilities.is_set (ConferenceURL) then Conference = sepc .. " " .. external_link( ConferenceURL, nil, ConferenceURL_origin, nil ); end local Position = ''; if not utilities.is_set (Position) then local Minutes = A['Minutes']; local Time = A['Time']; if utilities.is_set (Minutes) then if utilities.is_set (Time) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'minutes') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'time')}); end Position = utilities.substitute (cfg.messages.minutes, Minutes); else if utilities.is_set (Time) then local TimeCaption = A['TimeCaption'] if not utilities.is_set (TimeCaption) then TimeCaption = cs2_lower(cfg.messages['event']); end Position = " " .. TimeCaption .. " " .. Time; end end else Position = " " .. Position; At = ''; end Page, Pages, Sheet, Sheets = format_pages_sheets (Page, Pages, Sheet, Sheets, config.CitationClass, Periodical_origin, sepc, NoPP, use_lowercase); At = utilities.is_set (At) and (sepc .. " " .. At) or ""; Position = utilities.is_set (Position) and (sepc .. " " .. Position) or ""; if config.CitationClass == 'map' then local Sections = A['Sections']; -- Section (singular) is an alias of Chapter so set earlier local Inset = A['Inset']; if utilities.is_set ( Inset ) then Inset = sepc .. " " .. wrap_msg ('inset', Inset, use_lowercase); end if utilities.is_set ( Sections ) then Section = sepc .. " " .. wrap_msg ('sections', Sections, use_lowercase); elseif utilities.is_set ( Section ) then Section = sepc .. " " .. wrap_msg ('section', Section, use_lowercase); end At = At .. Inset .. Section; end local Others = A['Others']; if utilities.is_set (Others) and 0 == #a and 0 == #e then -- add maint cat when |others= has value and used without |author=, |editor= if config.CitationClass == "AV-media-notes" or config.CitationClass == "audio-visual" then -- special maint for AV/M which has a lot of 'false' positives right now utilities.set_message ('maint_others_avm') else utilities.set_message ('maint_others'); end end Others = utilities.is_set (Others) and (sepc .. " " .. Others) or ""; if utilities.is_set (Translators) then Others = safe_join ({sepc .. ' ', wrap_msg ('translated', Translators, use_lowercase), Others}, sepc); end if utilities.is_set (Interviewers) then Others = safe_join ({sepc .. ' ', wrap_msg ('interview', Interviewers, use_lowercase), Others}, sepc); end local TitleNote = A['TitleNote']; TitleNote = utilities.is_set (TitleNote) and (sepc .. " " .. TitleNote) or ""; if utilities.is_set (Edition) then if Edition:match ('%f[%a][Ee]d%n?%.?$') or Edition:match ('%f[%a][Ee]dition$') then -- Ed, ed, Ed., ed., Edn, edn, Edn., edn. utilities.set_message ('err_extra_text_edition'); -- add error message end Edition = " " .. wrap_msg ('edition', Edition); else Edition = ''; end Series = utilities.is_set (Series) and wrap_msg ('series', {sepc, Series}) or ""; -- not the same as SeriesNum local Agency = A['Agency'] or ''; -- |agency= is supported by {{cite magazine}}, {{cite news}}, {{cite press release}}, {{cite web}}, and certain {{citation}} templates if utilities.is_set (Agency) then -- this testing done here because {{citation}} supports 'news' citations if utilities.in_array (config.CitationClass, {'magazine', 'news', 'pressrelease', 'web'}) or ('citation' == config.CitationClass and utilities.in_array (Periodical_origin, {"magazine", "newspaper", "work"})) then Agency = wrap_msg ('agency', {sepc, Agency}); -- format for rendering else Agency = ''; -- unset; not supported utilities.set_message ('err_parameter_ignored', {'agency'}); -- add error message end end Volume = format_volume_issue (Volume, Issue, ArticleNumber, config.CitationClass, Periodical_origin, sepc, use_lowercase); if utilities.is_set (AccessDate) then local retrv_text = " " .. cfg.messages['retrieved']; AccessDate = nowrap_date (AccessDate); -- wrap in nowrap span if date in appropriate format retrv_text = cs2_lower(retrv_text); -- if mode is cs2, lower case AccessDate = utilities.substitute (retrv_text, AccessDate); -- add retrieved text AccessDate = utilities.substitute (cfg.presentation['accessdate'], {sepc, AccessDate}); -- allow editors to hide accessdates end if utilities.is_set (ID) then ID = sepc .. " " .. ID; end local Docket = A['Docket']; if "thesis" == config.CitationClass and utilities.is_set (Docket) then ID = sepc .. " Docket " .. Docket .. ID; end if "report" == config.CitationClass and utilities.is_set (Docket) then -- for cite report when |docket= is set ID = sepc .. ' ' .. Docket; -- overwrite ID even if |id= is set end if utilities.is_set (URL) then URL = " " .. external_link( URL, nil, URL_origin, UrlAccess ); end -- We check length of PostScript here because it will have been nuked by -- the quote parameters. We'd otherwise emit a message even if there wasn't -- a displayed postscript. -- TODO: Should the max size (1) be configurable? -- TODO: Should we check a specific pattern? if utilities.is_set(PostScript) and mw.ustring.len(PostScript) > 1 then utilities.set_message ('maint_postscript') end local Archived; if utilities.is_set (ArchiveURL) then if not utilities.is_set (ArchiveDate) then -- ArchiveURL set but ArchiveDate not set utilities.set_message ('err_archive_missing_date'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end else if utilities.is_set (ArchiveDate) then -- ArchiveURL not set but ArchiveDate is set utilities.set_message ('err_archive_date_missing_url'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end end if utilities.is_set (ArchiveURL) then if "live" == UrlStatus then if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cfg.messages['archived-live'], { external_link( ArchiveURL, cs2_lower(cfg.messages['archived']), A:ORIGIN('ArchiveURL'), nil) .. ArchiveFormat, ArchiveDate } ); else Archived = ''; end if not utilities.is_set (OriginalURL) then utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (OriginalURL) then -- UrlStatus is empty, 'dead', 'unfit', 'usurped', 'bot: unknown' if utilities.in_array (UrlStatus, {'unfit', 'usurped', 'bot: unknown'}) then Archived = sepc .. ' ' .. utilities.substitute ( cs2_lower(cfg.messages['archived-unfit']), ArchiveDate); if 'bot: unknown' == UrlStatus then utilities.set_message ('maint_bot_unknown'); -- and add a category if not already added else utilities.add_prop_cat ('unfit'); -- and add a category if not already added end else -- UrlStatus is empty, 'dead' if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cs2_lower(cfg.messages['archived-dead']), { external_link( OriginalURL, cfg.messages['original'], OriginalURL_origin, OriginalAccess ) .. OriginalFormat, ArchiveDate } ); else Archived = ''; -- unset for concatenation end end else -- OriginalUrl not set utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (ArchiveFormat) then Archived = ArchiveFormat; -- if set and ArchiveURL not set ArchiveFormat has error message else Archived = ''; end local TranscriptURL = A['TranscriptURL'] local TranscriptFormat = A['TranscriptFormat']; TranscriptFormat = style_format (TranscriptFormat, TranscriptURL, 'transcript-format', 'transcripturl'); local Transcript = A['Transcript']; local TranscriptURL_origin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL if utilities.is_set (Transcript) then if utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, Transcript, TranscriptURL_origin, nil ); end Transcript = sepc .. ' ' .. Transcript .. TranscriptFormat; elseif utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, nil, TranscriptURL_origin, nil ); end local Publisher; if utilities.is_set (PublicationDate) then PublicationDate = wrap_msg ('published', PublicationDate); end if utilities.is_set (PublisherName) then if utilities.is_set (PublicationPlace) then Publisher = sepc .. " " .. PublicationPlace .. ": " .. PublisherName .. PublicationDate; else Publisher = sepc .. " " .. PublisherName .. PublicationDate; end elseif utilities.is_set (PublicationPlace) then Publisher= sepc .. " " .. PublicationPlace .. PublicationDate; else Publisher = PublicationDate; end -- Several of the above rely upon detecting this as nil, so do it last. if (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical)) then if utilities.is_set (Title) or utilities.is_set (TitleNote) then Periodical = sepc .. " " .. format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); else Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); end end local Language = A['Language']; if utilities.is_set (Language) then Language = language_parameter (Language); -- format, categories, name from ISO639-1, etc. else Language=''; -- language not specified so make sure this is an empty string; --[[ TODO: need to extract the wrap_msg from language_parameter so that we can solve parentheses bunching problem with Format/Language/TitleType ]] end --[[ Handle the oddity that is cite speech. This code overrides whatever may be the value assigned to TitleNote (through |department=) and forces it to be " (Speech)" so that the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided). ]] if "speech" == config.CitationClass then -- cite speech only TitleNote = TitleType; -- move TitleType to TitleNote so that it renders ahead of |event= TitleType = ''; -- and unset if utilities.is_set (Periodical) then -- if Periodical, perhaps because of an included |website= or |journal= parameter if utilities.is_set (Conference) then -- and if |event= is set Conference = Conference .. sepc .. " "; -- then add appropriate punctuation to the end of the Conference variable before rendering end end end -- Piece all bits together at last. Here, all should be non-nil. -- We build things this way because it is more efficient in LUA -- not to keep reassigning to the same string variable over and over. local tcommon; local tcommon2; -- used for book cite when |contributor= is set local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (Periodical) then -- special cases for book cites if utilities.is_set (Contributors) then -- when we are citing foreword, preface, introduction, etc. tcommon = safe_join ({Title, TitleNote}, sepc); -- author and other stuff will come after this and before tcommon2 tcommon2 = safe_join ({TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); else tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); end elseif 'map' == config.CitationClass then -- special cases for cite map if utilities.is_set (Chapter) then -- map in a book; TitleType is part of Chapter tcommon = safe_join ({Title, Edition, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); elseif utilities.is_set (Periodical) then -- map in a periodical tcommon = safe_join ({Title, TitleType, Periodical, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); else -- a sheet or stand-alone map tcommon = safe_join ({Title, TitleType, Edition, Scale, Series, Language, Cartography, Others, Publisher}, sepc); end elseif 'episode' == config.CitationClass then -- special case for cite episode tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Edition, Publisher}, sepc); else -- all other CS1 templates tcommon = safe_join ({Title, TitleNote, Conference, Periodical, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc); end if #ID_list_t > 0 then ID_list_t = safe_join( { sepc .. " ", table.concat( ID_list_t, sepc .. " " ), ID }, sepc ); else ID_list_t = ID; end local Via = A['Via']; Via = utilities.is_set (Via) and wrap_msg ('via', Via) or ''; local idcommon; if 'audio-visual' == config.CitationClass or 'episode' == config.CitationClass then -- special case for cite AV media & cite episode position transcript idcommon = safe_join( { ID_list_t, URL, Archived, Transcript, AccessDate, Via, Quote }, sepc ); else idcommon = safe_join( { ID_list_t, URL, Archived, AccessDate, Via, Quote }, sepc ); end local text; -- local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; local OrigDate = A['OrigDate']; OrigDate = utilities.is_set (OrigDate) and wrap_msg ('origdate', OrigDate) or ''; if utilities.is_set (Date) then if utilities.is_set (Authors) or utilities.is_set (Editors) then -- date follows authors or editors when authors not set Date = " (" .. Date .. ")" .. OrigDate .. sepc .. " "; -- in parentheses else -- neither of authors and editors set if (string.sub(tcommon, -1, -1) == sepc) then -- if the last character of tcommon is sepc Date = " " .. Date .. OrigDate; -- Date does not begin with sepc else Date = sepc .. " " .. Date .. OrigDate; -- Date begins with sepc end end end if utilities.is_set (Authors) then if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Authors termination Authors = terminate_name_list (Authors, sepc); -- when no date, terminate with 0 or 1 sepc and a space end if utilities.is_set (Editors) then local in_text = ''; local post_text; if utilities.is_set (Chapter) and 0 == #c then in_text = cfg.messages['in'] .. ' '; in_text = cs2_lower(in_text); -- lowercase for cs2 end if EditorCount <= 1 then post_text = ' (' .. cfg.messages['editor'] .. ')'; -- be consistent with no-author, no-date case else post_text = ' (' .. cfg.messages['editors'] .. ')'; end Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space end if utilities.is_set (Contributors) then -- book cite and we're citing the intro, preface, etc. local by_text = sepc .. ' ' .. cfg.messages['by'] .. ' '; by_text = cs2_lower(by_text); -- lowercase for cs2 Authors = by_text .. Authors; -- author follows title so tweak it here if utilities.is_set (Editors) and utilities.is_set (Date) then -- when Editors make sure that Authors gets terminated Authors = terminate_name_list (Authors, sepc); -- terminate with 0 or 1 sepc and a space end if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Contributors termination Contributors = terminate_name_list (Contributors, sepc); -- terminate with 0 or 1 sepc and a space end text = safe_join( {Contributors, Date, Chapter, tcommon, Authors, Place, Editors, tcommon2, pgtext, idcommon }, sepc ); else text = safe_join( {Authors, Date, Chapter, Place, Editors, tcommon, pgtext, idcommon }, sepc ); end elseif utilities.is_set (Editors) then if utilities.is_set (Date) then if EditorCount <= 1 then Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editor']; else Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editors']; end else if EditorCount <= 1 then Editors = Editors .. " (" .. cfg.messages['editor'] .. ")" .. sepc .. " " else Editors = Editors .. " (" .. cfg.messages['editors'] .. ")" .. sepc .. " " end end text = safe_join( {Editors, Date, Chapter, Place, tcommon, pgtext, idcommon}, sepc ); else if utilities.in_array (config.CitationClass, {"journal", "citation"}) and utilities.is_set (Periodical) then text = safe_join( {Chapter, Place, tcommon, pgtext, Date, idcommon}, sepc ); else text = safe_join( {Chapter, Place, tcommon, Date, pgtext, idcommon}, sepc ); end end if utilities.is_set (PostScript) and PostScript ~= sepc then text = safe_join( {text, sepc}, sepc ); -- Deals with italics, spaces, etc. if '.' == sepc then -- remove final seperator if present text = text:gsub ('%' .. sepc .. '$', ''); -- dot must be escaped here else text = mw.ustring.gsub (text, sepc .. '$', ''); -- using ustring for non-dot sepc (likely a non-Latin character) end end text = safe_join( {text, PostScript}, sepc ); -- Now enclose the whole thing in a <cite> element local options_t = {}; options_t.class = cite_class_attribute_make (config.CitationClass, Mode); local Ref = is_valid_parameter_value (A['Ref'], A:ORIGIN('Ref'), cfg.keywords_lists['ref'], nil, true); -- nil when |ref=harv; A['Ref'] else if 'none' ~= cfg.keywords_xlate[(Ref and Ref:lower()) or ''] then local namelist_t = {}; -- holds selected contributor, author, editor name list local year = first_set ({Year, anchor_year}, 2); -- Year first for legacy citations and for YMD dates that require disambiguation if #c > 0 then -- if there is a contributor list namelist_t = c; -- select it elseif #a > 0 then -- or an author list namelist_t = a; elseif #e > 0 then -- or an editor list namelist_t = e; end local citeref_id; if #namelist_t > 0 then -- if there are names in namelist_t citeref_id = make_citeref_id (namelist_t, year); -- go make the CITEREF anchor if mw.uri.anchorEncode (citeref_id) == ((Ref and mw.uri.anchorEncode (Ref)) or '') then -- Ref may already be encoded (by {{sfnref}}) so citeref_id must be encoded before comparison utilities.set_message ('maint_ref_duplicates_default'); end else citeref_id = ''; -- unset end options_t.id = Ref or citeref_id; end if string.len (text:gsub('%b<>', '')) <= 2 then -- remove html and html-like tags; then get length of what remains; z.error_cats_t = {}; -- blank the categories list z.error_msgs_t = {}; -- blank the error messages list OCinSoutput = nil; -- blank the metadata string text = ''; -- blank the the citation utilities.set_message ('err_empty_citation'); -- set empty citation message and category end local render_t = {}; -- here we collect the final bits for concatenation into the rendered citation if is_preview_mode and (0 ~= #z.error_msgs_t or 0 ~= #z.maint_cats_t) then -- when in preview mode if not utilities.is_set (options_t.id) then -- and when this template has not created an anchor ID math.randomseed (tonumber (mw.getLanguage ('en'):formatDate ('U')) * 10000 + os.clock() * 10000); options_t.id = 'CITEREF_temp_preview_id_' .. math.random (100000, 999999); -- create temporary anchor ID for preview mode end end if utilities.is_set (options_t.id) then -- here we wrap the rendered citation in <cite ...>...</cite> tags options_t.id = mw.uri.anchorEncode(options_t.id); -- do this here; also used when adding preview warning messages table.insert (render_t, utilities.substitute (cfg.presentation['cite-id'], {options_t.id, mw.text.nowiki(options_t.class), text})); -- when |ref= is set or when there is a namelist else table.insert (render_t, utilities.substitute (cfg.presentation['cite'], {mw.text.nowiki(options_t.class), text})); -- when |ref=none or when namelist_t empty and |ref= is missing or is empty end if OCinSoutput then -- blanked when citation is 'empty' so don't bother to add boilerplate metadata span table.insert (render_t, utilities.substitute (cfg.presentation['ocins'], OCinSoutput)); -- format and append metadata to the citation end local template_name = cfg.citation_class_map_t[config.CitationClass]; local template_link = '[[Template:' .. template_name .. '|' .. template_name .. ']]'; local msg_prefix = '<code class="cs1-code">{{' .. template_link .. '}}</code>: '; if 0 ~= #z.error_msgs_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_e, {template_link, options_t.id})); table.insert (render_t, ' '); -- insert a space between citation and its error messages table.sort (z.error_msgs_t); -- sort the error messages list; sorting includes wrapping <span> and <code> tags; hidden-error sorts ahead of visible-error local hidden = true; -- presume that the only error messages emited by this template are hidden for _, v in ipairs (z.error_msgs_t) do -- spin through the list of error messages if v:find ('cs1-visible-error', 1, true) then -- look for the visible error class name hidden = false; -- found one; so don't hide the error message prefix break; -- and done because no need to look further end end z.error_msgs_t[1] = table.concat ({utilities.error_comment (msg_prefix, hidden), z.error_msgs_t[1]}); -- add error message prefix to first error message to prevent extraneous punctuation table.insert (render_t, table.concat (z.error_msgs_t, '; ')); -- make a big string of error messages and add it to the rendering end if 0 ~= #z.maint_cats_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_m, {template_link, options_t.id})); table.sort (z.maint_cats_t); -- sort the maintenance messages list local maint_msgs_t = {}; -- here we collect all of the maint messages if 0 == #z.error_msgs_t then -- if no error messages table.insert (maint_msgs_t, msg_prefix); -- insert message prefix in maint message livery end for _, v in ipairs( z.maint_cats_t ) do -- append maintenance categories table.insert (maint_msgs_t, -- assemble new maint message and add it to the maint_msgs_t table table.concat ({v, ' (', utilities.substitute (cfg.messages[':cat wikilink'], v), ')'}) ); end table.insert (render_t, utilities.substitute (cfg.presentation['hidden-maint'], table.concat (maint_msgs_t, ' '))); -- wrap the group of maint messages with proper presentation and save end if not no_tracking_cats then local sort_key; local cat_wikilink = 'cat wikilink'; if cfg.enable_sort_keys then -- when namespace sort keys enabled local namespace_number = mw.title.getCurrentTitle().namespace; -- get namespace number for this wikitext sort_key = (0 ~= namespace_number and (cfg.name_space_sort_keys[namespace_number] or cfg.name_space_sort_keys.other)) or nil; -- get sort key character; nil for mainspace cat_wikilink = (not sort_key and 'cat wikilink') or 'cat wikilink sk'; -- make <cfg.messages> key end for _, v in ipairs (z.error_cats_t) do -- append error categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end if cfg.id_limits_data_load_fail then -- boolean true when load failed utilities.set_message ('maint_id_limit_load_fail'); -- done here because this maint cat emits no message end for _, v in ipairs (z.maint_cats_t) do -- append maintenance categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end for _, v in ipairs (z.prop_cats_t) do -- append properties categories table.insert (render_t, utilities.substitute (cfg.messages['cat wikilink'], v)); -- no sort keys end end return table.concat (render_t); -- make a big string and done end --[[--------------------------< V A L I D A T E >-------------------------------------------------------------- Looks for a parameter's name in one of several whitelists. Parameters in the whitelist can have three values: true - active, supported parameters false - deprecated, supported parameters nil - unsupported parameters ]] local function validate (name, cite_class, empty) local enum_name; -- parameter name with enumerator (if any) replaced with '#' local state; local function state_test () -- local function to do testing of state values; operates on the upvalues <state> and <name> if true == state then return true; end -- valid actively supported parameter if false == state then if empty then return nil; end -- empty deprecated parameters are treated as unknowns deprecated_parameter (name); -- parameter is deprecated but still supported return true; end if 'tracked' == state then local base_name = name:gsub ('%d', ''); -- strip enumerators from parameter names that have them to get the base name utilities.add_prop_cat ('tracked-param', {base_name}, base_name); -- add a properties category; <base_name> modifies <key> return true; end return nil; end if 'string' ~= type (name) or name:find ('#') then -- # is a cs1|2 reserved character so parameters with # not permitted; positional params are 'number' type; not supported return nil; end -- replace enumerator digit(s) with # (|last25= becomes |last#=) (mw.ustring because non-Western 'local' digits) enum_name = mw.ustring.gsub (name, '%d+$', '#'); -- where enumerator is last charaters in parameter name (these to protect |s2cid=) enum_name = mw.ustring.gsub (enum_name, '%d+([%-l])', '#%1'); -- where enumerator is in the middle of the parameter name; |author#link= is the oddity if 'document' == cite_class then -- special case for {{cite document}} state = whitelist.document_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test () then return true; end return false; end if utilities.in_array (cite_class, whitelist.preprint_template_list_t) then -- limited parameter sets allowed for these templates state = whitelist.limited_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test () then return true; end state = whitelist.preprint_arguments_t[cite_class][name]; -- look in the parameter-list for the template identified by cite_class if true == state_test () then return true; end return false; -- not supported because not found or name is set to nil end -- end limited parameter-set templates if utilities.in_array (cite_class, whitelist.unique_param_template_list_t) then -- template-specific parameters for templates that accept parameters from the basic argument list state = whitelist.unique_arguments_t[cite_class][name]; -- look in the template-specific parameter-lists for the template identified by cite_class if true == state_test () then return true; end end -- if here, fall into general validation state = whitelist.common_parameters_t[enum_name]; -- all other templates; all normal parameters allowed; this list holds enumerated and nonenumerated parameters if true == state_test () then return true; end return false; -- not supported because not found or name is set to nil end --[=[-------------------------< I N T E R _ W I K I _ C H E C K >---------------------------------------------- check <value> for inter-language interwiki-link markup. <prefix> must be a MediaWiki-recognized language code. when these values have the form (without leading colon): [[<prefix>:link|label]] return label as plain-text [[<prefix>:link]] return <prefix>:link as plain-text return value as is else ]=] local function inter_wiki_check (parameter, value) local prefix = value:match ('%[%[(%a+):'); -- get an interwiki prefix if one exists local _; if prefix and cfg.inter_wiki_map[prefix:lower()] then -- if prefix is in the map, needs preceding colon so utilities.set_message ('err_bad_paramlink', parameter); -- emit an error message _, value, _ = utilities.is_wikilink (value); -- extract label portion from wikilink end return value; end --[[--------------------------< M I S S I N G _ P I P E _ C H E C K >------------------------------------------ Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal sign, compare the alphanumeric string to the list of cs1|2 parameters. If found, then the string is possibly a parameter that is missing its pipe. There are two tests made: {{cite ... |title=Title access-date=2016-03-17}} -- the first parameter has a value and whitespace separates that value from the missing pipe parameter name {{cite ... |title=access-date=2016-03-17}} -- the first parameter has no value (whitespace after the first = is trimmed by MediaWiki) cs1|2 shares some parameter names with XML/HTML attributes: class=, title=, etc. To prevent false positives XML/HTML tags are removed before the search. If a missing pipe is detected, this function adds the missing pipe maintenance category. ]] local function missing_pipe_check (parameter, value) local capture; value = value:gsub ('%b<>', ''); -- remove XML/HTML tags because attributes: class=, title=, etc. capture = value:match ('%s+(%a[%w%-]+)%s*=') or value:match ('^(%a[%w%-]+)%s*='); -- find and categorize parameters with possible missing pipes if capture and validate (capture) then -- if the capture is a valid parameter name utilities.set_message ('err_missing_pipe', parameter); end end --[[--------------------------< H A S _ E X T R A N E O U S _ P U N C T >-------------------------------------- look for extraneous terminal punctuation in most parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_punc (param, value) if 'number' == type (param) then return; end param = param:gsub ('%d+', '#'); -- enumerated name-list mask params allow terminal punct; normalize if cfg.punct_skip[param] then return; -- parameter name found in the skip table so done end if value:match ('[,;:]$') then utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end if value:match ('^=') then -- sometimes an extraneous '=' character appears ... utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end end --[[--------------------------< H A S _ T W L _ U R L >-------------------------------------------------------- look for The Wikipedia Library urls in url-holding parameters. TWL urls are accessible only for readers who are active extended confirmed Wikipedia editors. This function sets an error message when such urls are discovered and when appropriate, sets the |<param>-url-access=subscription. returns nothing. looks for: '.wikipedialibrary.idm.oclc.org' ]] local function has_twl_url (url_params_t, cite_args_t) local url_error_t = {}; -- sequence of url-holding parameters that have a TWL url for param, value in pairs (url_params_t) do if value:find ('%.wikipedialibrary%.idm%.oclc%.org') then -- has the TWL base url? table.insert (url_error_t, param); -- add parameter name to the error list end end if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); -- sor for error messaging for i, param in ipairs (url_error_t) do if cfg.url_access_map_t[param] then -- if <param> has a matching -access parameter cite_args_t[cfg.url_access_map_t[param]] = cfg.keywords_xlate.subscription; -- set |<param>-url-access=subscription end url_error_t[i] = utilities.wrap_style ('parameter', param); -- make the parameter pretty for error message end utilities.set_message ('err_param_has_twl_url', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< M I S C _ U R L _ D E T E C T >------------------------------------------------ look for miscellaneous urls that might be converted to, or are duplicates of, identifiers. ]] local misc_url_patterns_t = { 'idm%.oclc%.org', -- but not wikipedialibrary.idm.oclc.org; has_twl_url() 'https?://citeseerx?%.ist%.psu%.edu/', -- simplified so we catch all citeseer and citeseerx urls except ~/document/... (the 'new' form) } local ignore_patterns_t = { 'wikipedialibrary.idm.oclc.org', -- handled by has_twl_url() 'https?://citeseerx?%.ist%.psu%.edu/document', -- 'new'-form citeseerx urls that mostly work; ignore for now } local function misc_url_detect (url_params_t) local ignore_flag = false; for _, value in pairs (url_params_t) do for _, ignore_pattern in ipairs (ignore_patterns_t) do if value:find (ignore_pattern) then -- matches this ignore_pattern? ignore_flag = true; -- found a pattern to ignore break; -- end end if not ignore_flag then -- if ignore_flag is set then don't bother to test this url <value> for _, misc_pattern in ipairs (misc_url_patterns_t) do if value:find (misc_pattern) then -- matches this misc_pattern? utilities.set_message ('maint_misc_url'); -- found one; set the message return; -- and done; no need to test other <value>s end end end ignore_flag = false; -- reset end end --[[--------------------------< H A S _ E X T R A N E O U S _ U R L >------------------------------------------ look for extraneous url parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_url (non_url_param_t) local url_error_t = {}; check_for_url (non_url_param_t, url_error_t); -- extraneous url check if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); utilities.set_message ('err_param_has_ext_link', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< _ C I T A T I O N >------------------------------------------------------------ Module entry point frame – from template call (citation()); may be nil when called from another module args_t – table of all cs1|2 parameters in the template (the parent frame) config_t – table of template-supplied parameter (the #invoke frame) ]] local function _citation (frame, args_t, config_t) -- save a copy in case we need to display an error message in preview mode if not frame then frame = mw.getCurrentFrame(); -- if called from another module, get a frame for frame-provided functions end -- i18n: set the name that your wiki uses to identify sandbox subpages from sandbox template invoke (or can be set here) local sandbox = ((config_t.SandboxPath and '' ~= config_t.SandboxPath) and config_t.SandboxPath) or '/sandbox'; -- sandbox path from {{#invoke:Citation/CS1/sandbox|citation|SandboxPath=/...}} is_sandbox = nil ~= string.find (frame:getTitle(), sandbox, 1, true); -- is this invoke the sandbox module? sandbox = is_sandbox and sandbox or ''; -- use i18n sandbox to load sandbox modules when this module is the sandox; live modules else cfg = mw.loadData ('Module:Citation/CS1/Configuration' .. sandbox); -- load sandbox versions of support modules when {{#invoke:Citation/CS1/sandbox|...}}; live modules else whitelist = mw.loadData ('Module:Citation/CS1/Whitelist' .. sandbox); utilities = require ('Module:Citation/CS1/Utilities' .. sandbox); validation = require ('Module:Citation/CS1/Date_validation' .. sandbox); identifiers = require ('Module:Citation/CS1/Identifiers' .. sandbox); metadata = require ('Module:Citation/CS1/COinS' .. sandbox); utilities.set_selected_modules (cfg); -- so that functions in Utilities can see the selected cfg tables identifiers.set_selected_modules (cfg, utilities); -- so that functions in Identifiers can see the selected cfg tables and selected Utilities module validation.set_selected_modules (cfg, utilities); -- so that functions in Date validataion can see selected cfg tables and the selected Utilities module metadata.set_selected_modules (cfg, utilities); -- so that functions in COinS can see the selected cfg tables and selected Utilities module z = utilities.z; -- table of error and category tables in Module:Citation/CS1/Utilities local cite_args_t = {}; -- because args_t is the parent (template) frame args (which cannot be modified); params and their values will be placed here is_preview_mode = not utilities.is_set (frame:preprocess ('{{REVISIONID}}')); local suggestions = {}; -- table where we store suggestions if we need to loadData them local error_text; -- used as a flag local capture; -- the single supported capture when matching unknown parameters using patterns local empty_unknowns = {}; -- sequence table to hold empty unknown params for error message listing for k, v in pairs (args_t) do -- get parameters from the parent (template) frame v = mw.ustring.gsub (v, '^%s*(.-)%s*$', '%1'); -- trim leading/trailing whitespace; when v is only whitespace, becomes empty string if v ~= '' then if cfg.enum_needs_xlation and 'string' == type (k) then -- for wikis that set date_names['local_digits'] to non-western digits k = mw.ustring.gsub (k, '%d', cfg.date_names.local_digits); -- translate 'local' digits enumerators to Western 0-9 end if not validate( k, config_t.CitationClass ) then if type (k) ~= 'string' then -- exclude empty numbered parameters if v:match("%S+") ~= nil then error_text = utilities.set_message ('err_text_ignored', {v}); end elseif validate (k:lower(), config_t.CitationClass) then error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, k:lower()}); -- suggest the lowercase version of the parameter else if nil == suggestions.suggestions then -- if this table is nil then we need to load it suggestions = mw.loadData ('Module:Citation/CS1/Suggestions' .. sandbox); --load sandbox version of suggestion module when {{#invoke:Citation/CS1/sandbox|...}}; live module else end for pattern, param in pairs (suggestions.patterns) do -- loop through the patterns to see if we can suggest a proper parameter capture = k:match (pattern); -- the whole match if no capture in pattern else the capture if a match if capture then -- if the pattern matches param = utilities.substitute (param, capture); -- add the capture to the suggested parameter (typically the enumerator) if validate (param, config_t.CitationClass) then -- validate the suggestion to make sure that the suggestion is supported by this template (necessary for limited parameter lists) error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, param}); -- set the suggestion error message else error_text = utilities.set_message ('err_parameter_ignored', {k}); -- suggested param not supported by this template v = ''; -- unset end end end if not utilities.is_set (error_text) then -- couldn't match with a pattern, is there an explicit suggestion? if (suggestions.suggestions[ k:lower() ] ~= nil) and validate (suggestions.suggestions[ k:lower() ], config_t.CitationClass) then utilities.set_message ('err_parameter_ignored_suggest', {k, suggestions.suggestions[ k:lower() ]}); else utilities.set_message ('err_parameter_ignored', {k}); v = ''; -- unset value assigned to unrecognized parameters (this for the limited parameter lists) end end end end cite_args_t[k] = v; -- save this parameter and its value elseif not utilities.is_set (v) then -- for empty parameters if not validate (k, config_t.CitationClass, true) then -- is this empty parameter a valid parameter k = ('' == k) and cfg.err_msg_supl.empty_str or k; -- when k is empty string (or was space(s) trimmed to empty string), replace with descriptive text table.insert (empty_unknowns, utilities.wrap_style ('parameter', k)); -- format for error message and add to the list end end end if 0 ~= #empty_unknowns then -- create empty unknown error message utilities.set_message ('err_param_unknown_empty', { 1 == #empty_unknowns and '' or 's', utilities.make_sep_list (#empty_unknowns, empty_unknowns) }); end local non_url_param_t = {}; -- table of parameters and values that are not url-holding parameters local url_param_t = {}; -- table of url-holding paramters and their values for k, v in pairs (cite_args_t) do if 'string' == type (k) then -- don't evaluate positional parameters has_invisible_chars (k, v); -- look for invisible characters end has_extraneous_punc (k, v); -- look for extraneous terminal punctuation in parameter values missing_pipe_check (k, v); -- do we think that there is a parameter that is missing a pipe? cite_args_t[k] = inter_wiki_check (k, v); -- when language interwiki-linked parameter missing leading colon replace with wiki-link label if 'string' == type (k) then -- when parameter k is not positional if not cfg.url_skip[k] then -- and not in url skip table non_url_param_t[k] = v; -- make a parameter/value list for extraneous url check else -- and is in url skip table (a url-holding parameter) url_param_t[k] = v; -- make a parameter/value list to check for values that are The Wikipedia Library url end end end if cfg.suppress_archive_today_urls then has_archive_today_url (cite_args_t); -- look for and suppress archive.today urls and dependent parameters for all templates end has_extraneous_url (non_url_param_t); -- look for url in parameter values where a url does not belong has_twl_url (url_param_t, cite_args_t); -- look for url-holding parameters that hold a The Wikipedia Library url misc_url_detect (url_param_t); -- look for url-holding parameters that hold certain miscellaneous urls return table.concat ({ frame:extensionTag ('templatestyles', '', {src='Module:Citation/CS1' .. sandbox .. '/styles.css'}), citation0 (config_t, cite_args_t) }); end --[[--------------------------< C I T A T I O N >-------------------------------------------------------------- Template entry point ]] local function citation (frame) local config_t = {}; -- table to store parameters from the module {{#invoke:}} local args_t = frame:getParent().args; -- get template's preset parameters for k, v in pairs (frame.args) do -- get parameters from the {{#invoke}} frame config_t[k] = v; -- args_t[k] = v; -- crude debug support that allows us to render a citation from module {{#invoke:}}; skips parameter validation; TODO: keep? end return _citation (frame, args_t, config_t) end --[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------ ]] return { citation = citation, -- template entry point _citation = _citation, -- module entry point } mzkfjlhyhvftcb93lj0ik7zu7t1myhw 736720 241982 2023-01-18T01:49:02Z Paine Ellsworth 4319 add [[WP:RCAT|rcat template]]s 736720 wikitext text/x-wiki #Redirect [[Help talk:Citation Style 1]] {{Rcat shell| {{R from remote talk page}} {{R from subpage}} }} ki2dfcz3fvxrree9yz3aa62tqyzrqnm 736721 736705 2026-10-07T14:40:43Z King ChristLike 13051 1 revision imported from [[:en:Module_talk:Citation/CS1]] 736704 Scribunto text/plain require ('strict'); --[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- each of these counts against the Lua upvalue limit ]] local validation; -- functions in Module:Citation/CS1/Date_validation local utilities; -- functions in Module:Citation/CS1/Utilities local z = {}; -- table of tables in Module:Citation/CS1/Utilities local identifiers; -- functions and tables in Module:Citation/CS1/Identifiers local metadata; -- functions in Module:Citation/CS1/COinS local cfg = {}; -- table of configuration tables that are defined in Module:Citation/CS1/Configuration local whitelist = {}; -- table of tables listing valid template parameter names; defined in Module:Citation/CS1/Whitelist --[[------------------< P A G E S C O P E V A R I A B L E S >--------------- declare variables here that have page-wide scope that are not brought in from other modules; that are created here and used here ]] local added_deprecated_cat; -- boolean flag so that the category is added only once local added_vanc_errs; -- boolean flag so we only emit one Vancouver error / category local added_generic_name_errs; -- boolean flag so we only emit one generic name error / category and stop testing names once an error is encountered local added_numeric_name_errs; -- boolean flag so we only emit one numeric name error / category and stop testing names once an error is encountered local added_numeric_name_maint; -- boolean flag so we only emit one numeric name maint category and stop testing names once a category has been emitted local is_preview_mode; -- true when article is in preview mode; false when using 'Preview page with this template' (previewing the module) local is_sandbox; -- true when using sandbox modules to render citation local url_was_archive_today; -- boolean flag set to true when has_archive_today_url() has unset |url= because it held a deprecated archive.today url --[[--------------------------< F I R S T _ S E T >------------------------------------------------------------ Locates and returns the first set value in a table of values where the order established in the table, left-to-right (or top-to-bottom), is the order in which the values are evaluated. Returns nil if none are set. This version replaces the original 'for _, val in pairs do' and a similar version that used ipairs. With the pairs version the order of evaluation could not be guaranteed. With the ipairs version, a nil value would terminate the for-loop before it reached the actual end of the list. ]] local function first_set (list, count) local i = 1; while i <= count do -- loop through all items in list if utilities.is_set( list[i] ) then return list[i]; -- return the first set list member end i = i + 1; -- point to next end end --[[--------------------------< A D D _ V A N C _ E R R O R >---------------------------------------------------- Adds a single Vancouver system error message to the template's output regardless of how many error actually exist. To prevent duplication, added_vanc_errs is nil until an error message is emitted. added_vanc_errs is a Boolean declared in page scope variables above ]] local function add_vanc_error (source, position) if added_vanc_errs then return end added_vanc_errs = true; -- note that we've added this category utilities.set_message ('err_vancouver', {source, position}); end --[[--------------------------< I S _ S C H E M E >------------------------------------------------------------ does this thing that purports to be a URI scheme seem to be a valid scheme? The scheme is checked to see if it is in agreement with http://tools.ietf.org/html/std66#section-3.1 which says: Scheme names consist of a sequence of characters beginning with a letter and followed by any combination of letters, digits, plus ("+"), period ("."), or hyphen ("-"). returns true if it does, else false ]] local function is_scheme (scheme) return scheme and scheme:match ('^%a[%a%d%+%.%-]*:'); -- true if scheme is set and matches the pattern end --[=[-------------------------< I S _ D O M A I N _ N A M E >-------------------------------------------------- Does this thing that purports to be a domain name seem to be a valid domain name? Syntax defined here: http://tools.ietf.org/html/rfc1034#section-3.5 BNF defined here: https://tools.ietf.org/html/rfc4234 Single character names are generally reserved; see https://tools.ietf.org/html/draft-ietf-dnsind-iana-dns-01#page-15; see also [[Single-letter second-level domain]] list of TLDs: https://www.iana.org/domains/root/db RFC 952 (modified by RFC 1123) requires the first and last character of a hostname to be a letter or a digit (see http://tools.ietf.org/html/rfc952 §GRAMMATICAL HOST TABLE SPECIFICATION §§B. Lexical grammar <name>; see http://tools.ietf.org/html/rfc1123#section-2). Between the first and last characters the name may use letters, digits, and the hyphen. Also allowed are IPv4 addresses. IPv6 not supported domain is expected to be stripped of any path so that the last character in the last character of the TLD. tld is two or more alpha characters. Any preceding '//' (from splitting a URL with a scheme) will be stripped here. Perhaps not necessary but retained in case it is necessary for IPv4 dot decimal. There are several tests: the first character of the whole domain name including subdomains must be a letter or a digit internationalized domain name (ASCII characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the TLD) see https://tools.ietf.org/html/rfc3490 single-letter/digit second-level domains in the .org, .cash, and .today TLDs q, x, and z SL domains in the .com TLD i and q SL domains in the .net TLD single-letter SL domains in the ccTLDs (where the ccTLD is two letters) two-character SL domains in gTLDs (where the gTLD is two or more letters) three-plus-character SL domains in gTLDs (where the gTLD is two or more letters) IPv4 dot-decimal address format; TLD not allowed returns true if domain appears to be a proper name and TLD or IPv4 address, else false ]=] local function is_domain_name (domain) if not domain then return false; -- if not set, abandon end domain = domain:gsub ('^//', ''); -- strip '//' from domain name if present; done here so we only have to do it once local sl_domain = domain:match ('[^%.]+') or domain; -- test the second level domain name if not (sl_domain:match ('^%w') and sl_domain:match ('%w$') and -- first and last characters must be letter or digit sl_domain:match ('^[%w%-]+$')) then -- all other characters must be letters, digits, or hyphen-minus return false; end if domain:match ('^%a+:') then -- hack to detect things that look like s:Page:Title where Page: is namespace at Wikisource return false; end local patterns = { -- patterns that look like URLs '%f[%w][%w][%w%-]+[%w]%.%a%a+$', -- three or more character hostname.hostname or hostname.tld '%f[%w][%w][%w%-]+[%w]%.xn%-%-[%w]+$', -- internationalized domain name with ACE prefix '%f[%a][qxz]%.com$', -- assigned one character .com hostname (x.com times out 2015-12-10) '%f[%a][iq]%.net$', -- assigned one character .net hostname (q.net registered but not active 2015-12-10) '%f[%w][%w]%.%a%a$', -- one character hostname and ccTLD (2 chars) '%f[%w][%w][%w]%.%a%a+$', -- two character hostname and TLD '^%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?', -- IPv4 address '[%a%d]+%:?' -- IPv6 address } for _, pattern in ipairs (patterns) do -- loop through the patterns list if domain:match (pattern) then return true; -- if a match then we think that this thing that purports to be a URL is a URL end end for _, d in ipairs (cfg.single_letter_2nd_lvl_domains_t) do -- look for single letter second level domain names for these top level domains if domain:match ('%f[%w][%w]%.' .. d) then return true end end return false; -- no matches, we don't know what this thing is end --[[--------------------------< I S _ U R L >------------------------------------------------------------------ returns true if the scheme and domain parts of a URL appear to be a valid URL; else false. This function is the last step in the validation process. This function is separate because there are cases that are not covered by split_url(), for example is_parameter_ext_wikilink() which is looking for bracketted external wikilinks. ]] local function is_url (scheme, domain) if utilities.is_set (scheme) then -- if scheme is set check it and domain return is_scheme (scheme) and is_domain_name (domain); else return is_domain_name (domain); -- scheme not set when URL is protocol-relative end end --[[--------------------------< S P L I T _ U R L >------------------------------------------------------------ Split a URL into a scheme, authority indicator, and domain. First remove Fully Qualified Domain Name terminator (a dot following TLD) (if any) and any path(/), query(?) or fragment(#). If protocol-relative URL, return nil scheme and domain else return nil for both scheme and domain. When not protocol-relative, get scheme, authority indicator, and domain. If there is an authority indicator (one or more '/' characters immediately following the scheme's colon), make sure that there are only 2. Any URL that does not have news: scheme must have authority indicator (//). TODO: are there other common schemes like news: that don't use authority indicator? Strip off any port and path; ]] local function split_url (url_str) local scheme, authority, domain; url_str = url_str:gsub ('([%a%d])%.?[/%?#].*$', '%1'); -- strip FQDN terminator and path(/), query(?), fragment (#) (the capture prevents false replacement of '//') if url_str:match ('^//%S*') then -- if there is what appears to be a protocol-relative URL domain = url_str:match ('^//(%S*)') elseif url_str:match ('%S-:/*%S+') then -- if there is what appears to be a scheme, optional authority indicator, and domain name scheme, authority, domain = url_str:match ('(%S-:)(/*)(%S+)'); -- extract the scheme, authority indicator, and domain portions if utilities.is_set (authority) then authority = authority:gsub ('//', '', 1); -- replace place 1 pair of '/' with nothing; if utilities.is_set(authority) then -- if anything left (1 or 3+ '/' where authority should be) then return scheme; -- return scheme only making domain nil which will cause an error message end else if not scheme:match ('^news:') then -- except for news:..., MediaWiki won't link URLs that do not have authority indicator; TODO: a better way to do this test? return scheme; -- return scheme only making domain nil which will cause an error message end end domain = domain:gsub ('(%a):%d+', '%1'); -- strip port number if present end return scheme, domain; end --[[--------------------------< L I N K _ P A R A M _ O K >--------------------------------------------------- checks the content of |title-link=, |series-link=, |author-link=, etc. for properly formatted content: no wikilinks, no URLs Link parameters are to hold the title of a Wikipedia article, so none of the WP:TITLESPECIALCHARACTERS are allowed: # < > [ ] | { } _ except the underscore which is used as a space in wiki URLs and # which is used for section links returns false when the value contains any of these characters. When there are no illegal characters, this function returns TRUE if value DOES NOT appear to be a valid URL (the |<param>-link= parameter is ok); else false when value appears to be a valid URL (the |<param>-link= parameter is NOT ok). ]] local function link_param_ok (value) local scheme, domain; if value:find ('[<>%[%]|{}]') then -- if any prohibited characters return false; end scheme, domain = split_url (value); -- get scheme or nil and domain or nil from URL; return not is_url (scheme, domain); -- return true if value DOES NOT appear to be a valid URL end --[[--------------------------< L I N K _ T I T L E _ O K >--------------------------------------------------- Use link_param_ok() to validate |<param>-link= value and its matching |<title>= value. |<title>= may be wiki-linked but not when |<param>-link= has a value. This function emits an error message when that condition exists check <link> for inter-language interwiki-link prefix. prefix must be a MediaWiki-recognized language code and must begin with a colon. ]] local function link_title_ok (link, lorig, title, torig) local orig; if utilities.is_set (link) then -- don't bother if <param>-link doesn't have a value if not link_param_ok (link) then -- check |<param>-link= markup orig = lorig; -- identify the failing link parameter elseif title:find ('%[%[') then -- check |title= for wikilink markup orig = torig; -- identify the failing |title= parameter elseif link:match ('^%a+:') then -- if the link is what looks like an interwiki local prefix = link:match ('^(%a+):'):lower(); -- get the interwiki prefix if cfg.inter_wiki_map[prefix] then -- if prefix is in the map, must have preceding colon orig = lorig; -- flag as error end end end if utilities.is_set (orig) then link = ''; -- unset utilities.set_message ('err_bad_paramlink', orig); -- URL or wikilink in |title= with |title-link=; end return link; -- link if ok, empty string else end --[[--------------------------< C H E C K _ U R L >------------------------------------------------------------ Determines whether a URL string appears to be valid. First we test for space characters. If any are found, return false. Then split the URL into scheme and domain portions, or for protocol-relative (//example.com) URLs, just the domain. Use is_url() to validate the two portions of the URL. If both are valid, or for protocol-relative if domain is valid, return true, else false. Because it is different from a standard URL, and because this module used external_link() to make external links that work for standard and news: links, we validate newsgroup names here. The specification for a newsgroup name is at https://tools.ietf.org/html/rfc5536#section-3.1.4 ]] local function check_url( url_str ) if nil == url_str:match ("^%S+$") then -- if there are any spaces in |url=value it can't be a proper URL return false; end local scheme, domain; scheme, domain = split_url (url_str); -- get scheme or nil and domain or nil from URL; if 'news:' == scheme then -- special case for newsgroups return domain:match('^[%a%d%+%-_]+%.[%a%d%+%-_%.]*[%a%d%+%-_]$'); end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[=[-------------------------< I S _ P A R A M E T E R _ E X T _ W I K I L I N K >---------------------------- Return true if a parameter value has a string that begins and ends with square brackets [ and ] and the first non-space characters following the opening bracket appear to be a URL. The test will also find external wikilinks that use protocol-relative URLs. Also finds bare URLs. The frontier pattern prevents a match on interwiki-links which are similar to scheme:path URLs. The tests that find bracketed URLs are required because the parameters that call this test (currently |title=, |chapter=, |work=, and |publisher=) may have wikilinks and there are articles or redirects like '//Hus' so, while uncommon, |title=[[//Hus]] is possible as might be [[en://Hus]]. ]=] local function is_parameter_ext_wikilink (value) local scheme, domain; if value:match ('%f[%[]%[%a%S*:%S+.*%]') then -- if ext. wikilink with scheme and domain: [xxxx://yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(%a%S*:%S+).*%]')); elseif value:match ('%f[%[]%[//%S+.*%]') then -- if protocol-relative ext. wikilink: [//yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(//%S+).*%]')); elseif value:match ('%a%S*:%S+') then -- if bare URL with scheme; may have leading or trailing plain text scheme, domain = split_url (value:match ('(%a%S*:%S+)')); elseif value:match ('^//%S+') or value:match ('%s//%S+') then -- if protocol-relative bare URL: //yyyyy.zzz; authority indicator (//) must be be preceded nothing or by whitespace scheme, domain = split_url (value:match ('(//%S+)')); -- what is left should be the domain else return false; -- didn't find anything that is obviously a URL end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[[--------------------------< I S _ A R C H I V E _ T O D A Y _ U R L >-------------------------------------- archive.today (and .ph, .is, .md, .li, .fo, .vn) are deprecated. See Wikipedia:Requests_for_comment/Archive.is_RFC_5 (Special:Permalink/1339352976) <val> is a string that may or may not be a url ]] local function is_archive_today_url (val) if is_parameter_ext_wikilink (val) then -- is <val> a url? local tld = val:match ('archive%.(%l+)/'); -- get the tld; real archive.today urls have a '/' after the tld return tld and cfg.archive_today_tlds_t[tld]; -- return true if <tld> is one of the archive.today tlds; nil else end end --[[--------------------------< H A S _ A R C H I V E _ T O D A Y _ U R L >------------------------------------ blank any parameter that holds one of the archive.today tlds (.today, .ph, .is, .md, .li, .fo, .vn) and also blank parameters that are dependent on the offending parameter. input <cite_args_t> is a table of all of this template's parameters This function modifies <cite_args_t> when |url= or its alias |URL= hold an archive.today url, this function sets the flag <url_was_archive_today> which is used later to suppress the missing url error message from {{citation}} when it has |website=<summat> or from the templates {{cite web}}, {{cite podcast}}, {{cite mailing list}} which all require a url. returns nothing ]] local function has_archive_today_url (cite_args_t) local unset_params_t = {}; -- to hold a sequence of parameters to unset from cite_args_t for p, v in pairs (cite_args_t) do -- look at each parameter in the template if is_archive_today_url (v:lower()) then -- if it has a parameter with an archive.today url table.insert (unset_params_t, p); -- add the url-holding parameter name to our list of parameters to unset (may or may not be a legitimate url parameter) if 'url' == p:lower() then -- if this parameter is |url= or |URL= url_was_archive_today = true; -- set a flag so that cite web / podcast / mailinglist don't emit a missing url error message end if p:match ('archive%-?url') and ('usurped' == cite_args_t['url-status'] or 'unfit' == cite_args_t['url-status']) then -- if |archive-url=archive.today and |url-status=unfit/usurped url_was_archive_today = true; -- set a flag so that cite web / podcast / mailinglist don't emit a missing url error message table.insert (unset_params_t, 'url'); -- add the url parameter name to our list of parameters to unset (may or may not be a legitimate url parameter) table.insert (unset_params_t, 'URL'); -- this one because both are possible end if cfg.dependencies_t[p] then -- if this url-holding parameter (<p>) has dependencies for _, dependent in ipairs (cfg.dependencies_t[p]) do -- loop through the url-holding parameter's dependency sequence table.insert (unset_params_t, dependent); -- add dependent parameter to the list to be unset end end end end if 0 < #unset_params_t then -- when there are parameters to unset if not is_preview_mode then -- when in preview mode do not suppress any parameters for _, unset_param in ipairs (unset_params_t) do -- loop through the sequence cite_args_t[unset_param] = nil; -- and unset the url-holding parameter and its dependent parameters to avoid parameter-requires-other-parameter errors end end utilities.set_message ('maint_deprecated_archive'); -- add a maintenance message end end --[[-------------------------< C H E C K _ F O R _ U R L >----------------------------------------------------- loop through a list of parameters and their values. Look at the value and if it has an external link, emit an error message. ]] local function check_for_url (parameter_list, error_list) for k, v in pairs (parameter_list) do -- for each parameter in the list if is_parameter_ext_wikilink (v) then -- look at the value; if there is a URL add an error message table.insert (error_list, utilities.wrap_style ('parameter', k)); end end end --[[--------------------------< S A F E _ F O R _ U R L >------------------------------------------------------ Escape sequences for content that will be used for URL descriptions ]] local function safe_for_url( str ) if str:match( "%[%[.-%]%]" ) ~= nil then utilities.set_message ('err_wikilink_in_url', {}); end return str:gsub( '[%[%]\n]', { ['['] = '&#91;', [']'] = '&#93;', ['\n'] = ' ' } ); end --[[--------------------------< E X T E R N A L _ L I N K >---------------------------------------------------- Format an external link with error checking ]] local function external_link (URL, label, source, access) local domain; local path; local base_url; if not utilities.is_set (label) then label = URL; if utilities.is_set (source) then utilities.set_message ('err_bare_url_missing_title', {utilities.wrap_style ('parameter', source)}); else error (cfg.messages["bare_url_no_origin"]); -- programmer error; valid parameter name does not have matching meta-parameter end end if not check_url (URL) then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); end domain, path = URL:match ('^([/%.%-%+:%a%d]+)([/%?#].*)$'); -- split the URL into scheme plus domain and path if path then -- if there is a path portion path = path:gsub ('[%[%]]', {['['] = '%5b', [']'] = '%5d'}); -- replace '[' and ']' with their percent-encoded values URL = table.concat ({domain, path}); -- and reassemble end base_url = table.concat ({ "[", URL, " ", safe_for_url (label), "]" }); -- assemble a wiki-markup URL if utilities.is_set (access) then -- access level (subscription, registration, limited) base_url = utilities.substitute (cfg.presentation['ext-link-access-signal'], {cfg.presentation[access].class, cfg.presentation[access].title, base_url}); -- add the appropriate icon end return base_url; end --[[--------------------------< D E P R E C A T E D _ P A R A M E T E R >-------------------------------------- Categorize and emit an error message when the citation contains one or more deprecated parameters. The function includes the offending parameter name to the error message. Only one error message is emitted regardless of the number of deprecated parameters in the citation. added_deprecated_cat is a Boolean declared in page scope variables above ]] local function deprecated_parameter(name) if not added_deprecated_cat then added_deprecated_cat = true; -- note that we've added this category utilities.set_message ('err_deprecated_params', {name}); -- add error message end end --[=[-------------------------< K E R N _ Q U O T E S >-------------------------------------------------------- Apply kerning to open the space between the quote mark provided by the module and a leading or trailing quote mark contained in a |title= or |chapter= parameter's value. This function will positive kern either single or double quotes: "'Unkerned title with leading and trailing single quote marks'" " 'Kerned title with leading and trailing single quote marks' " (in real life the kerning isn't as wide as this example) Double single quotes (italic or bold wiki-markup) are not kerned. Replaces Unicode quote marks in plain text or in the label portion of a [[L|D]] style wikilink with typewriter quote marks regardless of the need for kerning. Unicode quote marks are not replaced in simple [[D]] wikilinks. Call this function for chapter titles, for website titles, etc.; not for book titles. ]=] local function kern_quotes (str) local wl_type, label, link; wl_type, label, link = utilities.is_wikilink (str); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] if 1 == wl_type then -- [[D]] simple wikilink with or without quote marks if mw.ustring.match (str, '%[%[[\"“”\'‘’].+[\"“”\'‘’]%]%]') then -- leading and trailing quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); str = utilities.substitute (cfg.presentation['kern-right'], str); elseif mw.ustring.match (str, '%[%[[\"“”\'‘’].+%]%]') then -- leading quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); elseif mw.ustring.match (str, '%[%[.+[\"“”\'‘’]%]%]') then -- trailing quote marks str = utilities.substitute (cfg.presentation['kern-right'], str); end else -- plain text or [[L|D]]; text in label variable label = mw.ustring.gsub (label, '[“”]', '\"'); -- replace “” (U+201C & U+201D) with " (typewriter double quote mark) label = mw.ustring.gsub (label, '[‘’]', '\''); -- replace ‘’ (U+2018 & U+2019) with ' (typewriter single quote mark) local cap = mw.ustring.match (label, "^([\"\'][^\'].+)"); -- match leading double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-left'], cap); end cap = mw.ustring.match (label, "^(.+[^\'][\"\'])$") -- match trailing double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-right'], cap); end if 2 == wl_type then str = utilities.make_wikilink (link, label); -- reassemble the wikilink else str = label; end end return str; end --[[--------------------------< F O R M A T _ S C R I P T _ V A L U E >---------------------------------------- |script-title= holds title parameters that are not written in Latin-based scripts: Chinese, Japanese, Arabic, Hebrew, etc. These scripts should not be italicized and may be written right-to-left. The value supplied by |script-title= is concatenated onto Title after Title has been wrapped in italic markup. Regardless of language, all values provided by |script-title= are wrapped in <bdi>...</bdi> tags to isolate RTL languages from the English left to right. |script-title= provides a unique feature. The value in |script-title= may be prefixed with a two-character ISO 639-1 language code and a colon: |script-title=ja:*** *** (where * represents a Japanese character) Spaces between the two-character code and the colon and the colon and the first script character are allowed: |script-title=ja : *** *** |script-title=ja: *** *** |script-title=ja :*** *** Spaces preceding the prefix are allowed: |script-title = ja:*** *** The prefix is checked for validity. If it is a valid ISO 639-1 language code, the lang attribute (lang="ja") is added to the <bdi> tag so that browsers can know the language the tag contains. This may help the browser render the script more correctly. If the prefix is invalid, the lang attribute is not added. At this time there is no error message for this condition. Supports |script-title=, |script-chapter=, |script-<periodical>= ]] local function format_script_value (script_value, script_param) local lang=''; -- initialize to empty string local name; if script_value:match('^%l%l%l?%s*:') then -- if first 3 or 4 non-space characters are script language prefix lang = script_value:match('^(%l%l%l?)%s*:%s*%S.*'); -- get the language prefix or nil if there is no script if not utilities.is_set (lang) then utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing title part']}); -- prefix without 'title'; add error message return ''; -- script_value was just the prefix so return empty string end -- if we get this far we have prefix and script name = cfg.lang_tag_remap[lang] or mw.language.fetchLanguageName( lang, cfg.this_wiki_code ); -- get language name so that we can use it to categorize if utilities.is_set (name) then -- is prefix a proper ISO 639-1 language code? script_value = script_value:gsub ('^%l+%s*:%s*', ''); -- strip prefix from script -- is prefix one of these language codes? if utilities.in_array (lang, cfg.script_lang_codes) then utilities.add_prop_cat ('script', {name, lang}) else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['unknown language code']}); -- unknown script-language; add error message end lang = ' lang="' .. lang .. '" '; -- convert prefix into a lang attribute else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['invalid language code']}); -- invalid language code; add error message lang = ''; -- invalid so set lang to empty string end else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing prefix']}); -- no language code prefix; add error message end script_value = utilities.substitute (cfg.presentation['bdi'], {lang, script_value}); -- isolate in case script is RTL return script_value; end --[[--------------------------< S C R I P T _ C O N C A T E N A T E >------------------------------------------ Initially for |title= and |script-title=, this function concatenates those two parameter values after the script value has been wrapped in <bdi> tags. ]] local function script_concatenate (title, script, script_param) if utilities.is_set (script) then script = format_script_value (script, script_param); -- <bdi> tags, lang attribute, categorization, etc.; returns empty string on error if utilities.is_set (script) then title = title .. ' ' .. script; -- concatenate title and script title end end return title; end --[[--------------------------< W R A P _ M S G >-------------------------------------------------------------- Applies additional message text to various parameter values. Supplied string is wrapped using a message_list configuration taking one argument. Supports lower case text for {{citation}} templates. Additional text taken from citation_config.messages - the reason this function is similar to but separate from wrap_style(). ]] local function wrap_msg (key, str, lower) if not utilities.is_set ( str ) then return ""; end if true == lower then local msg; msg = cfg.messages[key]:lower(); -- set the message to lower case before return utilities.substitute ( msg, str ); -- including template text else return utilities.substitute ( cfg.messages[key], str ); end end --[[----------------< W I K I S O U R C E _ U R L _ M A K E >------------------- Makes a Wikisource URL from Wikisource interwiki-link. Returns the URL and appropriate label; nil else. str is the value assigned to |chapter= (or aliases) or |title= or |title-link= ]] local function wikisource_url_make (str) local wl_type, D, L; local ws_url, ws_label; local wikisource_prefix = table.concat ({'https://', cfg.this_wiki_code, '.wikisource.org/wiki/'}); wl_type, D, L = utilities.is_wikilink (str); -- wl_type is 0 (not a wikilink), 1 (simple wikilink), 2 (complex wikilink) if 0 == wl_type then -- not a wikilink; might be from |title-link= str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 1 == wl_type then -- simple wikilink: [[Wikisource:ws article]] str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 2 == wl_type then -- non-so-simple wikilink: [[Wikisource:ws article|displayed text]] ([[L|D]]) str = L:match ('^[Ww]ikisource:(.+)') or L:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_label = D; -- get ws article name from display portion of interwiki link ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title without namespace from link portion of wikilink }); end end if ws_url then ws_url = mw.uri.encode (ws_url, 'WIKI'); -- make a usable URL ws_url = ws_url:gsub ('%%23', '#'); -- undo percent-encoding of fragment marker end return ws_url, ws_label, L or D; -- return proper URL or nil and a label or nil end --[[----------------< F O R M A T _ P E R I O D I C A L >----------------------- Format the three periodical parameters: |script-<periodical>=, |<periodical>=, and |trans-<periodical>= into a single Periodical meta-parameter. ]] local function format_periodical (script_periodical, script_periodical_source, periodical, trans_periodical) if not utilities.is_set (periodical) then periodical = ''; -- to be safe for concatenation else periodical = utilities.wrap_style ('italic-title', periodical); -- style end periodical = script_concatenate (periodical, script_periodical, script_periodical_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (trans_periodical) then trans_periodical = utilities.wrap_style ('trans-italic-title', trans_periodical); if utilities.is_set (periodical) then periodical = periodical .. ' ' .. trans_periodical; else -- here when trans-periodical without periodical or script-periodical periodical = trans_periodical; utilities.set_message ('err_trans_missing_title', {'periodical'}); end end return periodical; end --[[------------------< F O R M A T _ C H A P T E R _ T I T L E >--------------- Format the four chapter parameters: |script-chapter=, |chapter=, |trans-chapter=, and |chapter-url= into a single chapter meta- parameter (chapter_url_source used for error messages). ]] local function format_chapter_title (script_chapter, script_chapter_source, chapter, trans_chapter, trans_chapter_source, chapter_url, chapter_url_source, no_quotes, access) local ws_url, ws_label, L = wikisource_url_make (chapter); -- make a wikisource URL and label from a wikisource interwiki link if ws_url then ws_label = ws_label:gsub ('_', ' '); -- replace underscore separators with space characters chapter = ws_label; end if not utilities.is_set (chapter) then chapter = ''; -- to be safe for concatenation else if false == no_quotes then chapter = kern_quotes (chapter); -- if necessary, separate chapter title's leading and trailing quote marks from module provided quote marks chapter = utilities.wrap_style ('quoted-title', chapter); end end chapter = script_concatenate (chapter, script_chapter, script_chapter_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (chapter_url) then chapter = external_link (chapter_url, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate elseif ws_url then chapter = external_link (ws_url, chapter .. '&nbsp;', 'ws link in chapter'); -- adds bare_url_missing_title error if appropriate; space char to move icon away from chap text; TODO: better way to do this? chapter = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, chapter}); end if utilities.is_set (trans_chapter) then trans_chapter = utilities.wrap_style ('trans-quoted-title', trans_chapter); if utilities.is_set (chapter) then chapter = chapter .. ' ' .. trans_chapter; else -- here when trans_chapter without chapter or script-chapter chapter = trans_chapter; utilities.set_message ('err_trans_missing_title', {trans_chapter_source:match ('trans%-?(.+)')}); -- when no chapter, get matching name from trans-<param> end end return chapter; end --[[----------------< H A S _ I N V I S I B L E _ C H A R S >------------------- This function searches a parameter's value for non-printable or invisible characters. The search stops at the first match. This function will detect the visible replacement character when it is part of the Wikisource. Detects but ignores nowiki and math stripmarkers. Also detects other named stripmarkers (gallery, math, pre, ref) and identifies them with a slightly different error message. See also coins_cleanup(). Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker that was detected along with its position (or, for multi-byte characters, the position of its first byte) in the parameter value. ]] local function has_invisible_chars (param, v) local position; -- position of invisible char or starting position of stripmarker local capture; -- used by stripmarker detection to hold name of the stripmarker local stripmarker; -- boolean set true when a stripmarker is found capture = string.match (v, '[%w%p ]*'); -- test for values that are simple ASCII text and bypass other tests if true if capture == v then -- if same there are no Unicode characters return; end for _, invisible_char in ipairs (cfg.invisible_chars) do local char_name = invisible_char[1]; -- the character or group name local pattern = invisible_char[2]; -- the pattern used to find it position, _, capture = mw.ustring.find (v, pattern); -- see if the parameter value contains characters that match the pattern if position and (cfg.invisible_defs.zwj == capture) then -- if we found a zero-width joiner character if mw.ustring.find (v, cfg.indic_script) then -- it's ok if one of the Indic scripts position = nil; -- unset position elseif cfg.emoji_t[mw.ustring.codepoint (v, position+1)] then -- is zwj followed by a character listed in emoji{}? position = nil; -- unset position end end if position then if 'nowiki' == capture or 'math' == capture or -- nowiki and math stripmarkers (not an error condition) ('templatestyles' == capture and utilities.in_array (param, {'id', 'quote'})) then -- templatestyles stripmarker allowed in these parameters stripmarker = true; -- set a flag elseif true == stripmarker and cfg.invisible_defs.del == capture then -- because stripmakers begin and end with the delete char, assume that we've found one end of a stripmarker position = nil; -- unset; for now, ignore linter warning else local err_msg; if capture and not (cfg.invisible_defs.del == capture or cfg.invisible_defs.zwj == capture) then err_msg = utilities.substitute (cfg.messages.invisible_1, {capture, char_name}); -- <capture> here is stripmarker name else err_msg = utilities.substitute (cfg.messages.invisible_2, char_name); end utilities.set_message ('err_invisible_char', {err_msg, utilities.wrap_style ('parameter', param), position}); -- add error message return; -- and done with this parameter end end end end --[[-------------------< A R G U M E N T _ W R A P P E R >---------------------- Argument wrapper. This function provides support for argument mapping defined in the configuration file so that multiple names can be transparently aliased to single internal variable. ]] local function argument_wrapper ( args ) local origin = {}; return setmetatable({ ORIGIN = function ( self, k ) local dummy = self[k]; -- force the variable to be loaded; for now, ignore linter warning return origin[k]; end }, { __index = function ( tbl, k ) if origin[k] ~= nil then return nil; end local v; local list = cfg.aliases[k]; if type( list ) == 'table' then v, origin[k] = utilities.select_one ( args, list, 'err_redundant_parameters' ); if origin[k] == nil then origin[k] = ''; -- Empty string, not nil end elseif list ~= nil then v, origin[k] = args[list], list; else -- maybe let through instead of raising an error? -- v, origin[k] = args[k], k; error( cfg.messages['unknown_argument_map'] .. ': ' .. k); end -- Empty strings, not nil; if v == nil then v = ''; origin[k] = ''; end -- tbl = rawset( tbl, k, v ); rawset( tbl, k, v ); return v; end, }); end --[[--------------------------< N O W R A P _ D A T E >------------------------- When date is YYYY-MM-DD format wrap in nowrap span: <span ...>YYYY-MM-DD</span>. When date is DD MMMM YYYY or is MMMM DD, YYYY then wrap in nowrap span: <span ...>DD MMMM</span> YYYY or <span ...>MMMM DD,</span> YYYY DOES NOT yet support MMMM YYYY or any of the date ranges. ]] local function nowrap_date (date) local cap; local cap2; if date:match("^%d%d%d%d%-%d%d%-%d%d$") then date = utilities.substitute (cfg.presentation['nowrap1'], date); elseif date:match("^%a+%s*%d%d?,%s+%d%d%d%d$") or date:match ("^%d%d?%s*%a+%s+%d%d%d%d$") then cap, cap2 = string.match (date, "^(.*)%s+(%d%d%d%d)$"); date = utilities.substitute (cfg.presentation['nowrap2'], {cap, cap2}); end return date; end --[[--------------------------< S E T _ T I T L E T Y P E >--------------------- This function sets default title types (equivalent to the citation including |type=<default value>) for those templates that have defaults. Also handles the special case where it is desirable to omit the title type from the rendered citation (|type=none). ]] local function set_titletype (cite_class, title_type) if utilities.is_set (title_type) then if 'none' == cfg.keywords_xlate[title_type] then title_type = ''; -- if |type=none then type parameter not displayed end return title_type; -- if |type= has been set to any other value use that value end return cfg.title_types [cite_class] or ''; -- set template's default title type; else empty string for concatenation end --[[--------------------------< S A F E _ J O I N >----------------------------- Joins a sequence of strings together while checking for duplicate separation characters. ]] local function safe_join( tbl, duplicate_char ) local f = {}; -- create a function table appropriate to type of 'duplicate character' if 1 == #duplicate_char then -- for single byte ASCII characters use the string library functions f.gsub = string.gsub f.match = string.match f.sub = string.sub else -- for multi-byte characters use the ustring library functions f.gsub = mw.ustring.gsub f.match = mw.ustring.match f.sub = mw.ustring.sub end local str = ''; -- the output string for _, value in ipairs( tbl ) do if value == nil then value = ''; end if str == '' then -- if output string is empty str = value; -- assign value to it (first time through the loop) elseif value ~= '' then local comp; -- what does 'comp' mean? if value:sub(1, 1) == '<' then -- special case of values enclosed in spans and other markup. comp = value:gsub( "%b<>", "" ); -- remove HTML markup (<span>string</span> -> string) else comp = value; end -- typically duplicate_char is sepc if f.sub(comp, 1, 1) == duplicate_char then -- is first character same as duplicate_char? why test first character? -- Because individual string segments often (always?) begin with terminal punct for the -- preceding segment: 'First element' .. 'sepc next element' .. etc.? local trim = false; local end_chr = f.sub(str, -1, -1); -- get the last character of the output string -- str = str .. "<HERE(enchr=" .. end_chr .. ")" -- debug stuff? if end_chr == duplicate_char then -- if same as separator str = f.sub(str, 1, -2); -- remove it elseif end_chr == "'" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "''" then -- if last three chars of str are sepc'' str = f.sub(str, 1, -4) .. "''"; -- remove them and add back '' elseif f.sub(str, -5, -1) == duplicate_char .. "]]''" then -- if last five chars of str are sepc]]'' trim = true; -- why? why do this and next differently from previous? elseif f.sub(str, -4, -1) == duplicate_char .. "]''" then -- if last four chars of str are sepc]'' trim = true; -- same question end elseif end_chr == "]" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "]]" then -- if last three chars of str are sepc]] wikilink trim = true; elseif f.sub(str, -3, -1) == duplicate_char .. '"]' then -- if last three chars of str are sepc"] quoted external link trim = true; elseif f.sub(str, -2, -1) == duplicate_char .. "]" then -- if last two chars of str are sepc] external link trim = true; elseif f.sub(str, -4, -1) == duplicate_char .. "'']" then -- normal case when |url=something & |title=Title. trim = true; end elseif end_chr == " " then -- if last char of output string is a space if f.sub(str, -2, -1) == duplicate_char .. " " then -- if last two chars of str are <sepc><space> str = f.sub(str, 1, -3); -- remove them both end end if trim then if value ~= comp then -- value does not equal comp when value contains HTML markup local dup2 = duplicate_char; if f.match(dup2, "%A" ) then dup2 = "%" .. dup2; end -- if duplicate_char not a letter then escape it value = f.gsub(value, "(%b<>)" .. dup2, "%1", 1 ) -- remove duplicate_char if it follows HTML markup else value = f.sub(value, 2, -1 ); -- remove duplicate_char when it is first character end end end str = str .. value; -- add it to the output string end end return str; end --[[--------------------------< I S _ S U F F I X >----------------------------- returns true if suffix is properly formed Jr, Sr, or ordinal in the range 1–9. Puncutation not allowed. ]] local function is_suffix (suffix) if utilities.in_array (suffix, {'Jr', 'Sr', 'Jnr', 'Snr', '1st', '2nd', '3rd'}) or suffix:match ('^%dth$') then return true; end return false; end --[[--------------------< I S _ G O O D _ V A N C _ N A M E >------------------- For Vancouver style, author/editor names are supposed to be rendered in Latin (read ASCII) characters. When a name uses characters that contain diacritical marks, those characters are to be converted to the corresponding Latin character. When a name is written using a non-Latin alphabet or logogram, that name is to be transliterated into Latin characters. The module doesn't do this so editors may/must. This test allows |first= and |last= names to contain any of the letters defined in the four Unicode Latin character sets [http://www.unicode.org/charts/PDF/U0000.pdf C0 Controls and Basic Latin] 0041–005A, 0061–007A [http://www.unicode.org/charts/PDF/U0080.pdf C1 Controls and Latin-1 Supplement] 00C0–00D6, 00D8–00F6, 00F8–00FF [http://www.unicode.org/charts/PDF/U0100.pdf Latin Extended-A] 0100–017F [http://www.unicode.org/charts/PDF/U0180.pdf Latin Extended-B] 0180–01BF, 01C4–024F |lastn= also allowed to contain hyphens, spaces, and apostrophes. (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) |firstn= also allowed to contain hyphens, spaces, apostrophes, and periods This original test: if nil == mw.ustring.find (last, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%'%.]+[2-6%a]*$") then was written outside of the code editor and pasted here because the code editor gets confused between character insertion point and cursor position. The test has been rewritten to use decimal character escape sequence for the individual bytes of the Unicode characters so that it is not necessary to use an external editor to maintain this code. \195\128-\195\150 – À-Ö (U+00C0–U+00D6 – C0 controls) \195\152-\195\182 – Ø-ö (U+00D8-U+00F6 – C0 controls) \195\184-\198\191 – ø-ƿ (U+00F8-U+01BF – C0 controls, Latin extended A & B) \199\132-\201\143 – DŽ-ɏ (U+01C4-U+024F – Latin extended B) ]] local function is_good_vanc_name (last, first, suffix, position) if not suffix then if first:find ('[,%s]') then -- when there is a space or comma, might be first name/initials + generational suffix first = first:match ('(.-)[,%s]+'); -- get name/initials suffix = first:match ('[,%s]+(.+)$'); -- get generational suffix end end if utilities.is_set (suffix) then if not is_suffix (suffix) then add_vanc_error (cfg.err_msg_supl.suffix, position); return false; -- not a name with an appropriate suffix end end if nil == mw.ustring.find (last, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%'%.]*$") then add_vanc_error (cfg.err_msg_supl['non-Latin char'], position); return false; -- not a string of Latin characters; Vancouver requires Romanization end; return true; end --[[--------------------------< R E D U C E _ T O _ I N I T I A L S >------------------------------------------ Attempts to convert names to initials in support of |name-list-style=vanc. Names in |firstn= may be separated by spaces or hyphens, or for initials, a period. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35062/. Vancouver style requires family rank designations (Jr, II, III, etc.) to be rendered as Jr, 2nd, 3rd, etc. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35085/. This code only accepts and understands generational suffix in the Vancouver format because Roman numerals look like, and can be mistaken for, initials. This function uses ustring functions because firstname initials may be any of the Unicode Latin characters accepted by is_good_vanc_name (). ]] local function reduce_to_initials (first, position) if first:find (',', 1, true) then return first; -- commas not allowed; abandon end local name, suffix = mw.ustring.match (first, "^(%u+) ([%dJS][%drndth]+)$"); if not name then -- if not initials and a suffix name = mw.ustring.match (first, "^(%u+)$"); -- is it just initials? end if name then -- if first is initials with or without suffix if 3 > mw.ustring.len (name) then -- if one or two initials if suffix then -- if there is a suffix if is_suffix (suffix) then -- is it legitimate? return first; -- one or two initials and a valid suffix so nothing to do else add_vanc_error (cfg.err_msg_supl.suffix, position); -- one or two initials with invalid suffix so error message return first; -- and return first unmolested end else return first; -- one or two initials without suffix; nothing to do end end end -- if here then name has 3 or more uppercase letters so treat them as a word local initials_t = {}; -- table to hold initials local i = 1; -- counter for number of initials local names_t = mw.text.split (first, '[%s%-]+'); -- split into a sequence of names and possible suffix while names_t[i] do -- loop through the sequence if 1 < i and names_t[i]:match ('[%dJS][%drndth]+%.?$') then -- if not the first name, and looks like a suffix (may have trailing dot) names_t[i] = names_t[i]:gsub ('%.', ''); -- remove terminal dot if present if is_suffix (names_t[i]) then -- if a legitimate suffix table.insert (initials_t, ' ' .. names_t[i]); -- add a separator space, insert at end of initials sequence break; -- and done because suffix must fall at the end of a name end -- no error message if not a suffix; possibly because of Romanization end if 3 > i then table.insert (initials_t, mw.ustring.sub (names_t[i], 1, 1)); -- insert the initial at end of initials sequence end i = i + 1; -- bump the counter end return table.concat (initials_t); -- Vancouver format does not include spaces. end --[[--------------------------< I N T E R W I K I _ P R E F I X E N _ G E T >---------------------------------- extract interwiki prefixen from <value>. Returns two one or two values: false – no prefixen nil – prefix exists but not recognized project prefix, language prefix – when value has either of: :<project>:<language>:<article> :<language>:<project>:<article> project prefix, nil – when <value> has only a known single-letter prefix nil, language prefix – when <value> has only a known language prefix accepts single-letter project prefixen: 'd' (wikidata), 's' (wikisource), and 'w' (wikipedia) prefixes; at this writing, the other single-letter prefixen (b (wikibook), c (commons), m (meta), n (wikinews), q (wikiquote), and v (wikiversity)) are not supported. ]] local function interwiki_prefixen_get (value, is_link) if not value:find (':%l+:') then -- if no prefix return false; -- abandon; boolean here to distinguish from nil fail returns later end local prefix_patterns_linked_t = { -- sequence of valid interwiki and inter project prefixen '^%[%[:([dsw]):(%l%l+):', -- wikilinked; project and language prefixes '^%[%[:(%l%l+):([dsw]):', -- wikilinked; language and project prefixes '^%[%[:([dsw]):', -- wikilinked; project prefix '^%[%[:(%l%l+):', -- wikilinked; language prefix } local prefix_patterns_unlinked_t = { -- sequence of valid interwiki and inter project prefixen '^:([dsw]):(%l%l+):', -- project and language prefixes '^:(%l%l+):([dsw]):', -- language and project prefixes '^:([dsw]):', -- project prefix '^:(%l%l+):', -- language prefix } local cap1, cap2; for _, pattern in ipairs ((is_link and prefix_patterns_linked_t) or prefix_patterns_unlinked_t) do cap1, cap2 = value:match (pattern); if cap1 then break; -- found a match so stop looking end end if cap1 and cap2 then -- when both then :project:language: or :language:project: (both forms allowed) if 1 == #cap1 then -- length == 1 then :project:language: if cfg.inter_wiki_map[cap2] then -- is language prefix in the interwiki map? return cap1, cap2; -- return interwiki project and interwiki language end else -- here when :language:project: if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return cap2, cap1; -- return interwiki project and interwiki language end end return nil; -- unknown interwiki language elseif not (cap1 or cap2) then -- both are nil? return nil; -- we got something that looks like a project prefix but isn't; return fail elseif 1 == #cap1 then -- here when one capture return cap1, nil; -- length is 1 so return project, nil language else -- here when one capture and its length it more than 1 if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return nil, cap1; -- return nil project, language end end end --[[--------------------------< L I S T _ P E O P L E >-------------------------- Formats a list of people (authors, contributors, editors, interviewers, translators) names in the list will be linked when |<name>-link= has a value |<name>-mask- does NOT have a value; masked names are presumed to have been rendered previously so should have been linked there when |<name>-mask=0, the associated name is not rendered ]] local function list_people (control, people, etal) local sep; local namesep; local format = control.format; local maximum = control.maximum; local name_list = {}; if 'vanc' == format then -- Vancouver-like name styling? sep = cfg.presentation['sep_nl_vanc']; -- name-list separator between names is a comma namesep = cfg.presentation['sep_name_vanc']; -- last/first separator is a space else sep = cfg.presentation['sep_nl']; -- name-list separator between names is a semicolon namesep = cfg.presentation['sep_name']; -- last/first separator is <comma><space> end if sep:sub (-1, -1) ~= " " then sep = sep .. " " end if utilities.is_set (maximum) and maximum < 1 then return "", 0; end -- returned 0 is for EditorCount; not used for other names for i, person in ipairs (people) do if utilities.is_set (person.last) then local mask = person.mask; local one; local sep_one = sep; if utilities.is_set (maximum) and i > maximum then etal = true; break; end if mask then local n = tonumber (mask); -- convert to a number if it can be converted; nil else if n then one = 0 ~= n and string.rep("&mdash;", n) or nil; -- make a string of (n > 0) mdashes, nil else, to replace name person.link = nil; -- don't create link to name if name is replaces with mdash string or has been set nil else one = mask; -- replace name with mask text (must include name-list separator) sep_one = " "; -- modify name-list separator end else one = person.last; -- get surname local first = person.first -- get given name if utilities.is_set (first) then if ("vanc" == format) then -- if Vancouver format one = one:gsub ('%.', ''); -- remove periods from surnames (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) if not person.corporate and is_good_vanc_name (one, first, nil, i) then -- and name is all Latin characters; corporate authors not tested first = reduce_to_initials (first, i); -- attempt to convert first name(s) to initials end end one = one .. namesep .. first; end end if utilities.is_set (person.link) then one = utilities.make_wikilink (person.link, one); -- link author/editor end if one then -- if <one> has a value (name, mdash replacement, or mask text replacement) local proj, tag = interwiki_prefixen_get (one, true); -- get the interwiki prefixen if present if 'w' == proj and ('Wikipedia' == mw.site.namespaces.Project['name']) then proj = nil; -- for stuff like :w:de:<article>, :w is unnecessary TODO: maint cat? end if proj then local proj_name = ({['d'] = cfg.messages.wikidata, ['s'] = cfg.messages.wikisource, ['w'] = cfg.messages.wikipedia})[proj]; -- :w (wikipedia) for linking from a non-wikipedia project if proj_name then one = one .. utilities.wrap_style ('interproj', proj_name); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interproj-linked-name', proj); -- categorize it; <proj> is sort key tag = nil; -- unset; don't do both project and language end end if tag == cfg.this_wiki_code then tag = nil; -- stuff like :en:<article> at en.wiki is pointless TODO: maint cat? end if tag then local lang = cfg.lang_tag_remap[tag] or cfg.mw_languages_by_tag_t[tag]; if lang then -- error messaging done in extract_names() where we know parameter names one = one .. utilities.wrap_style ('interwiki', lang); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interwiki-linked-name', tag); -- categorize it; <tag> is sort key end end table.insert (name_list, one); -- add it to the list of names table.insert (name_list, sep_one); -- add the proper name-list separator end end end local count = #name_list / 2; -- (number of names + number of separators) divided by 2 if 0 < count then if 1 < count and not etal then if 'amp' == format then name_list[#name_list-2] = " & "; -- replace last separator with ampersand text elseif 'and' == format then if 2 == count then name_list[#name_list-2] = cfg.presentation.sep_nl_and; -- replace last separator with 'and' text else name_list[#name_list-2] = cfg.presentation.sep_nl_end; -- replace last separator with '(sep) and' text end end end name_list[#name_list] = nil; -- erase the last separator end local result = table.concat (name_list); -- construct list if etal and utilities.is_set (result) then -- etal may be set by |display-authors=etal but we might not have a last-first list result = result .. sep .. cfg.messages['et al']; -- we've got a last-first list and etal so add et al. end return result, count; -- return name-list string and count of number of names (count used for editor names only) end --[[--------------------< M A K E _ C I T E R E F _ I D >----------------------- Generates a CITEREF anchor ID if we have at least one name or a date. Otherwise returns an empty string. namelist is one of the contributor-, author-, or editor-name lists chosen in that order. year is Year or anchor_year. ]] local function make_citeref_id (namelist, year) local names={}; -- a table for the one to four names and year for i,v in ipairs (namelist) do -- loop through the list and take up to the first four last names names[i] = v.last if i == 4 then break end -- if four then done end table.insert (names, year); -- add the year at the end local id = table.concat(names); -- concatenate names and year for CITEREF id if utilities.is_set (id) then -- if concatenation is not an empty string return "CITEREF" .. id; -- add the CITEREF portion else return ''; -- return an empty string; no reason to include CITEREF id in this citation end end --[[--------------------------< C I T E _ C L A S S _A T T R I B U T E _M A K E >------------------------------ construct <cite> tag class attribute for this citation. <cite_class> – config.CitationClass from calling template <mode> – value from |mode= parameter ]] local function cite_class_attribute_make (cite_class, mode) local class_t = {}; table.insert (class_t, 'citation'); -- required for blue highlight if 'citation' ~= cite_class then table.insert (class_t, cite_class); -- identify this template for user css table.insert (class_t, utilities.is_set (mode) and mode or 'cs1'); -- identify the citation style for user css or javascript else table.insert (class_t, utilities.is_set (mode) and mode or 'cs2'); -- identify the citation style for user css or javascript end for _, prop_key in ipairs (z.prop_keys_t) do table.insert (class_t, prop_key); -- identify various properties for user css or javascript end return table.concat (class_t, ' '); -- make a big string and done end --[[---------------------< N A M E _ H A S _ E T A L >-------------------------- Evaluates the content of name parameters (author, editor, etc.) for variations on the theme of et al. If found, the et al. is removed, a flag is set to true and the function returns the modified name and the flag. This function never sets the flag to false but returns its previous state because it may have been set by previous passes through this function or by the associated |display-<names>=etal parameter ]] local function name_has_etal (name, etal, nocat, param) if utilities.is_set (name) then -- name can be nil in which case just return local patterns = cfg.et_al_patterns; -- get patterns from configuration for _, pattern in ipairs (patterns) do -- loop through all of the patterns if name:match (pattern) then -- if this 'et al' pattern is found in name name = name:gsub (pattern, ''); -- remove the offending text etal = true; -- set flag (may have been set previously here or by |display-<names>=etal) if not nocat then -- no categorization for |vauthors= utilities.set_message ('err_etal', {param}); -- and set an error if not added end end end end return name, etal; end --[[---------------------< N A M E _ I S _ N U M E R I C >---------------------- Add an error message and category when <name> parameter value does not contain letters. Add a maintenance category when <name> parameter value has numeric characters mixed with characters that are not numeric characters; could be letters and/or punctuation characters. This function will only emit one error and one maint message for the current template. Does not emit both error and maint messages/categories for the same parameter value. returns nothing ]] local function name_is_numeric (name, name_alias, list_name) local patterns = { '^%D+%d', -- <name> must have digits preceded by other characters '^%D*%d+%D+', -- <name> must have digits followed by other characters } if not added_numeric_name_errs and mw.ustring.match (name, '^[%A]+$') then -- if we have not already set an error message and <name> does not have any alpha characters utilities.set_message ('err_numeric_names', name_alias); -- add an error message added_numeric_name_errs = true; -- set the flag so we emit only one error message return; -- when here no point in further testing; abandon end if not added_numeric_name_maint then -- if we have already set a maint message for _, pattern in ipairs (patterns) do -- spin through list of patterns if mw.ustring.match (name, pattern) then -- digits preceded or followed by anything but digits; %D+ includes punctuation utilities.set_message ('maint_numeric_names', cfg.special_case_translation [list_name]); -- add a maint cat for this template added_numeric_name_maint = true; -- set the flag so we emit only one maint message return; -- when here no point in further testing; abandon end end end end --[[-----------------< N A M E _ H A S _ M U L T _ N A M E S >------------------ Evaluates the content of last/surname (authors etc.) parameters for multiple names. Multiple names are indicated if there is more than one comma or any "unescaped" semicolons. Escaped semicolons are ones used as part of selected HTML entities. If the condition is met, the function adds the multiple name maintenance category. Same test for first except that commas should not appear in given names (MOS:JR says that the generational suffix does not take a separator character). Titles, degrees, postnominals, affiliations, all normally comma separated don't belong in a citation. <name> – name parameter value <list_name> – AuthorList, EditorList, etc <limit> – number of allowed commas; 1 (default) for surnames; 0 for given names returns nothing ]] local function name_has_mult_names (name, list_name, limit) local _, commas, semicolons, nbsps; limit = limit and limit or 1; if utilities.is_set (name) then _, commas = name:gsub (',', ''); -- count the number of commas _, semicolons = name:gsub (';', ''); -- count the number of semicolons -- nbsps probably should be its own separate count rather than merged in -- some way with semicolons because Lua patterns do not support the -- grouping operator that regex does, which means there is no way to add -- more entities to escape except by adding more counts with the new -- entities _, nbsps = name:gsub ('&nbsp;',''); -- count nbsps -- There is exactly 1 semicolon per &nbsp; entity, so subtract nbsps -- from semicolons to 'escape' them. If additional entities are added, -- they also can be subtracted. if limit < commas or 0 < (semicolons - nbsps) then utilities.set_message ('maint_mult_names', cfg.special_case_translation [list_name]); -- add a maint message end end end --[=[-------------------------< I S _ G E N E R I C >---------------------------------------------------------- Compares values assigned to various parameters according to the string provided as <item> in the function call. <item> can have on of two values: 'generic_names' – for name-holding parameters: |last=, |first=, |editor-last=, etc 'generic_titles' – for |title= There are two types of generic tests. The 'accept' tests look for a pattern that should not be rejected by the 'reject' test. For example, |author=[[John Smith (author)|Smith, John]] would be rejected by the 'author' reject test. But piped wikilinks with 'author' disambiguation should not be rejected so the 'accept' test prevents that from happening. Accept tests are always performed before reject tests. Each of the 'accept' and 'reject' sequence tables hold tables for en.wiki (['en']) and local.wiki (['local']) that each can hold a test sequence table The sequence table holds, at index [1], a test pattern, and, at index [2], a boolean control value. The control value tells string.find() or mw.ustring.find() to do plain-text search (true) or a pattern search (false). The intent of all this complexity is to make these searches as fast as possible so that we don't run out of processing time on very large articles. Returns true when a reject test finds the pattern or string false when an accept test finds the pattern or string nil else ]=] local function is_generic (item, value) local str_lower = { -- use string.lower() for en.wiki (['en']) and use mw.ustring.lower() or local.wiki (['local']) ['en'] = string.lower, ['local'] = mw.ustring.lower, } local str_find = { -- use string.find() for en.wiki (['en']) and use mw.ustring.find() or local.wiki (['local']) ['en'] = string.find, ['local'] = mw.ustring.find, } local function test (val, test_t, wiki) -- local function to do the testing; <wiki> selects lower() and find() functions val = test_t[2] and str_lower[wiki](value) or val; -- when <test_t[2]> set to 'true', plaintext search using lowercase value return str_find[wiki] (val, test_t[1], 1, test_t[2]); -- return nil when not found or matched end local test_types_t = {'accept', 'reject'}; -- test accept patterns first, then reject patterns local wikis_t = {'en', 'local'}; -- do tests for each of these keys; en.wiki first, local.wiki second for _, test_type in ipairs (test_types_t) do -- for each test type for _, generic_value in pairs (cfg.special_case_translation[item][test_type]) do -- spin through the list of generic value fragments to accept or reject for _, wiki in ipairs (wikis_t) do if generic_value[wiki] then if test (value, generic_value[wiki], wiki) then -- go do the test return ('reject' == test_type); -- param value rejected, return true; false else end end end end end end --[[--------------------------< N A M E _ I S _ G E N E R I C >------------------------------------------------ calls is_generic() to determine if <name> is a 'generic name' listed in cfg.generic_names; <name_alias> is the parameter name used in error messaging ]] local function name_is_generic (name, name_alias) if not added_generic_name_errs and is_generic ('generic_names', name) then utilities.set_message ('err_generic_name', name_alias); -- set an error message added_generic_name_errs = true; end end --[[--------------------------< N A M E _ C H E C K S >-------------------------------------------------------- This function calls various name checking functions used to validate the content of the various name-holding parameters. ]] local function name_checks (last, first, list_name, last_alias, first_alias) local accept_name; if utilities.is_set (last) then last, accept_name = utilities.has_accept_as_written (last); -- remove accept-this-as-written markup when it wraps all of <last> if not accept_name then -- <last> not wrapped in accept-as-written markup name_has_mult_names (last, list_name); -- check for multiple names in the parameter name_is_numeric (last, last_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (last, last_alias); -- check for names found in the generic names list end end if utilities.is_set (first) then first, accept_name = utilities.has_accept_as_written (first); -- remove accept-this-as-written markup when it wraps all of <first> if not accept_name then -- <first> not wrapped in accept-as-written markup name_has_mult_names (first, list_name, 0); -- check for multiple names in the parameter; 0 is number of allowed commas in a given name name_is_numeric (first, first_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (first, first_alias); -- check for names found in the generic names list end local wl_type, D = utilities.is_wikilink (first); if 0 ~= wl_type then first = D; utilities.set_message ('err_bad_paramlink', first_alias); end end return last, first; -- done end --[[----------------------< E X T R A C T _ N A M E S >------------------------- Gets name list from the input arguments Searches through args in sequential order to find |lastn= and |firstn= parameters (or their aliases), and their matching link and mask parameters. Stops searching when both |lastn= and |firstn= are not found in args after two sequential attempts: found |last1=, |last2=, and |last3= but doesn't find |last4= and |last5= then the search is done. This function emits an error message when there is a |firstn= without a matching |lastn=. When there are 'holes' in the list of last names, |last1= and |last3= are present but |last2= is missing, an error message is emitted. |lastn= is not required to have a matching |firstn=. When an author or editor parameter contains some form of 'et al.', the 'et al.' is stripped from the parameter and a flag (etal) returned that will cause list_people() to add the static 'et al.' text from Module:Citation/CS1/Configuration. This keeps 'et al.' out of the template's metadata. When this occurs, an error is emitted. ]] local function extract_names(args, list_name) local names = {}; -- table of names local last; -- individual name components local first; local link; local mask; local i = 1; -- loop counter/indexer local n = 1; -- output table indexer local count = 0; -- used to count the number of times we haven't found a |last= (or alias for authors, |editor-last or alias for editors) local etal = false; -- return value set to true when we find some form of et al. in an author parameter local last_alias, first_alias, link_alias; -- selected parameter aliases used in error messaging while true do last, last_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'err_redundant_parameters', i ); -- search through args for name components beginning at 1 first, first_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'err_redundant_parameters', i ); link, link_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ); mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); if last then -- error check |lastn= alias for unknown interwiki link prefix; done here because this is where we have the parameter name local project, language = interwiki_prefixen_get (last, true); -- true because we expect interwiki links in |lastn= to be wikilinked if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', last_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? last = utilities.remove_wiki_link (last); -- remove wikilink markup; show display value only end end if link then -- error check |linkn= alias for unknown interwiki link prefix local project, language = interwiki_prefixen_get (link, false); -- false because wiki links in |author-linkn= is an error if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', link_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? link = nil; -- unset so we don't link link_alias = nil; end end last, etal = name_has_etal (last, etal, false, last_alias); -- find and remove variations on et al. first, etal = name_has_etal (first, etal, false, first_alias); -- find and remove variations on et al. last, first = name_checks (last, first, list_name, last_alias, first_alias); -- multiple names, extraneous annotation, etc. checks if first and not last then -- if there is a firstn without a matching lastn local alias = first_alias:find ('given', 1, true) and 'given' or 'first'; -- get first or given form of the alias utilities.set_message ('err_first_missing_last', { first_alias, -- param name of alias missing its mate first_alias:gsub (alias, {['first'] = 'last', ['given'] = 'surname'}), -- make param name appropriate to the alias form }); -- add this error message elseif not first and not last then -- if both firstn and lastn aren't found, are we done? count = count + 1; -- number of times we haven't found last and first if 2 <= count then -- two missing names and we give up break; -- normal exit or there is a two-name hole in the list; can't tell which end else -- we have last with or without a first link = link_title_ok (link, link_alias, last, last_alias); -- check for improper wiki-markup if first then link = link_title_ok (link, link_alias, first, first_alias); -- check for improper wiki-markup end names[n] = {last = last, first = first, link = link, mask = mask, corporate = false}; -- add this name to our names list (corporate for |vauthors= only) n = n + 1; -- point to next location in the names table if 1 == count then -- if the previous name was missing utilities.set_message ('err_missing_name', {list_name:match ("(%w+)List"):lower(), i - 1}); -- add this error message end count = 0; -- reset the counter, we're looking for two consecutive missing names end i = i + 1; -- point to next args location end return names, etal; -- all done, return our list of names and the etal flag end --[[--------------------------< N A M E _ T A G _ G E T >------------------------------------------------------ attempt to decode |language=<lang_param> and return language name and matching tag; nil else. This function looks for: <lang_param> as a tag in cfg.lang_tag_remap{} <lang_param> as a name in cfg.lang_name_remap{} <lang_param> as a name in cfg.mw_languages_by_name_t <lang_param> as a tag in cfg.mw_languages_by_tag_t when those fail, presume that <lang_param> is an IETF-like tag that MediaWiki does not recognize. Strip all script, region, variant, whatever subtags from <lang_param> to leave just a two or three character language tag and look for the new <lang_param> in cfg.mw_languages_by_tag_t{} on success, returns name (in properly capitalized form) and matching tag (in lowercase); on failure returns nil ]] local function name_tag_get (lang_param) local lang_param_lc = mw.ustring.lower (lang_param); -- use lowercase as an index into the various tables local name; local tag; name = cfg.lang_tag_remap[lang_param_lc]; -- assume <lang_param_lc> is a tag; attempt to get remapped language name if name then -- when <name>, <lang_param> is a tag for a remapped language name if cfg.lang_name_remap[name:lower()][2] ~= lang_param_lc then utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added return name, cfg.lang_name_remap[name:lower()][2]; -- so return name and tag from lang_name_remap[name]; special case to xlate sr-ec and sr-el to sr-cyrl and sr-latn end return name, lang_param_lc; -- so return <name> from remap and <lang_param_lc> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- still assuming that <lang_param_lc> is a tag; strip script, region, variant subtags name = cfg.lang_tag_remap[tag]; -- attempt to get remapped language name with language subtag only if name then -- when <name>, <tag> is a tag for a remapped language name return name, tag; -- so return <name> from remap and <tag> end if cfg.lang_name_remap[lang_param_lc] then -- not a remapped tag, assume <lang_param_lc> is a name; attempt to get remapped language tag return cfg.lang_name_remap[lang_param_lc][1], cfg.lang_name_remap[lang_param_lc][2]; -- for this <lang_param_lc>, return a (possibly) new name and appropriate tag end name = cfg.mw_languages_by_tag_t[lang_param_lc]; -- assume that <lang_param_lc> is a tag; attempt to get its matching language name if name then return name, lang_param_lc; -- <lang_param_lc> is a tag so return it and <name> end tag = cfg.mw_languages_by_name_t[lang_param_lc]; -- assume that <lang_param_lc> is a language name; attempt to get its matching tag if tag then return cfg.mw_languages_by_tag_t[tag], tag; -- <lang_param_lc> is a name so return the name from the table and <tag> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- is <lang_param_lc> an IETF-like tag that MediaWiki doesn't recognize? <tag> gets the language subtag; nil else if tag then name = cfg.mw_languages_by_tag_t[tag]; -- attempt to get a language name using the shortened <tag> if name then return name, tag; -- <lang_param_lc> is an unrecognized IETF-like tag so return <name> and language subtag end end end --[[-------------------< L A N G U A G E _ P A R A M E T E R >------------------ Gets language name from a provided two- or three-character ISO 639 code. If a code is recognized by MediaWiki, use the returned name; if not, then use the value that was provided with the language parameter. When |language= contains a recognized language (either code or name), the page is assigned to the category for that code: Category:Norwegian-language sources (no). For valid three-character code languages, the page is assigned to the single category for '639-2' codes: Category:CS1 ISO 639-2 language sources. Languages that are the same as the local wiki are not categorized. MediaWiki does not recognize three-character equivalents of two-character codes: code 'ar' is recognized but code 'ara' is not. This function supports multiple languages in the form |language=nb, French, th where the language names or codes are separated from each other by commas with optional space characters. ]] local function language_parameter (lang) local tag; -- some form of IETF-like language tag; language subtag with optional region, sript, vatiant, etc subtags local lang_subtag; -- ve populates |language= with mostly unecessary region subtags that MediaWiki does not recognize; this is the base language subtag local name; -- the language name local language_list = {}; -- table of language names to be rendered local names_t = mw.text.split (lang, '%s*,%s*'); -- names should be a comma separated list for _, lang in ipairs (names_t) do -- reuse lang here because we don't yet know if lang is a language name or a language tag; for now, ignore linter warning name, tag = name_tag_get (lang); -- attempt to get name/tag pair for <lang>; <name> has proper capitalization; <tag> is lowercase if utilities.is_set (tag) then lang_subtag = tag:gsub ('^(%a%a%a?)%-.*', '%1'); -- for categorization, strip any IETF-like tags from language tag if cfg.this_wiki_code ~= lang_subtag then -- when the language is not the same as this wiki's language if 2 == lang_subtag:len() then -- and is a two-character tag utilities.add_prop_cat ('foreign-lang-source', {name, tag}, lang_subtag); -- categorize it; tag appended to allow for multiple language categorization else -- or is a recognized language (but has a three-character tag) utilities.add_prop_cat ('foreign-lang-source-2', {lang_subtag}, lang_subtag); -- categorize it differently TODO: support multiple three-character tag categories per cs1|2 template? end elseif cfg.local_lang_cat_enable then -- when the language and this wiki's language are the same and categorization is enabled utilities.add_prop_cat ('local-lang-source', {name, lang_subtag}); -- categorize it end else name = lang; -- return whatever <lang> has so that we show something utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added end table.insert (language_list, name); end name = utilities.make_sep_list (#language_list, language_list); if (1 == #language_list) and (lang_subtag == cfg.this_wiki_code) then -- when only one language, find lang name in this wiki lang name; for |language=en-us, 'English' in 'American English' return ''; -- if one language and that language is this wiki's return an empty string (no annotation) end return (" " .. wrap_msg ('language', name)); -- otherwise wrap with '(in ...)' --[[ TODO: should only return blank or name rather than full list so we can clean up the bunched parenthetical elements Language, Type, Format ]] end --[[-----------------------< S E T _ C S _ S T Y L E >-------------------------- Gets the default CS style configuration for the given mode. Returns default separator and either postscript as passed in or the default. In CS1, the default postscript and separator are '.'. In CS2, the default postscript is the empty string and the default separator is ','. ]] local function set_cs_style (postscript, mode) if utilities.is_set(postscript) then -- emit a maintenance message if user postscript is the default cs1 postscript -- we catch the opposite case for cs2 in set_style if mode == 'cs1' and postscript == cfg.presentation['ps_' .. mode] then utilities.set_message ('maint_postscript'); end else postscript = cfg.presentation['ps_' .. mode]; end return cfg.presentation['sep_' .. mode], postscript; end --[[--------------------------< S E T _ S T Y L E >----------------------------- Sets the separator and postscript styles. Checks the |mode= first and the #invoke CitationClass second. Removes the postscript if postscript == none. ]] local function set_style (mode, postscript, cite_class) local sep; if 'cs2' == mode then sep, postscript = set_cs_style (postscript, 'cs2'); elseif 'cs1' == mode then sep, postscript = set_cs_style (postscript, 'cs1'); elseif 'citation' == cite_class then sep, postscript = set_cs_style (postscript, 'cs2'); else sep, postscript = set_cs_style (postscript, 'cs1'); end if cfg.keywords_xlate[postscript:lower()] == 'none' then -- emit a maintenance message if user postscript is the default cs2 postscript -- we catch the opposite case for cs1 in set_cs_style if 'cs2' == mode or ('cs1' ~= mode and 'citation' == cite_class) then -- {{citation |title=Title |mode=cs1 |postscript=none}} should not emit maint message utilities.set_message ('maint_postscript'); end postscript = ''; end return sep, postscript end --[=[-------------------------< I S _ P D F >----------------------------------- Determines if a URL has the file extension that is one of the PDF file extensions used by [[MediaWiki:Common.css]] when applying the PDF icon to external links. returns true if file extension is one of the recognized extensions, else false ]=] local function is_pdf (url) return url:match ('%.pdf$') or url:match ('%.PDF$') or url:match ('%.pdf[%?#]') or url:match ('%.PDF[%?#]') or url:match ('%.PDF&#035') or url:match ('%.pdf&#035'); end --[[--------------------------< S T Y L E _ F O R M A T >----------------------- Applies CSS style to |format=, |chapter-format=, etc. Also emits an error message if the format parameter does not have a matching URL parameter. If the format parameter is not set and the URL contains a file extension that is recognized as a PDF document by MediaWiki's commons.css, this code will set the format parameter to (PDF) with the appropriate styling. ]] local function style_format (format, url, fmt_param, url_param) if utilities.is_set (format) then format = utilities.wrap_style ('format', format); -- add leading space, parentheses, resize if not utilities.is_set (url) then utilities.set_message ('err_format_missing_url', {fmt_param, url_param}); -- add an error message end elseif is_pdf (url) then -- format is not set so if URL is a PDF file then format = utilities.wrap_style ('format', 'PDF'); -- set format to PDF else format = ''; -- empty string for concatenation end return format; end --[[---------------------< G E T _ D I S P L A Y _ N A M E S >------------------ Returns a number that defines the number of names displayed for author and editor name lists and a Boolean flag to indicate when et al. should be appended to the name list. When the value assigned to |display-xxxxors= is a number greater than or equal to zero, return the number and the previous state of the 'etal' flag (false by default but may have been set to true if the name list contains some variant of the text 'et al.'). When the value assigned to |display-xxxxors= is the keyword 'etal', return a number that is one greater than the number of authors in the list and set the 'etal' flag true. This will cause the list_people() to display all of the names in the name list followed by 'et al.' In all other cases, returns nil and the previous state of the 'etal' flag. inputs: max: A['DisplayAuthors'] or A['DisplayEditors'], etc; a number or some flavor of etal count: #a or #e list_name: 'authors' or 'editors' etal: author_etal or editor_etal This function sets an error message when |display-xxxxors= value greater than or equal to number of names but not when <max> comes from {{cs1 config}} global settings. When using global settings, <param> is set to the keyword 'cs1 config' which is used to supress the normal error. Error is suppressed because it is to be expected that some citations in an article will have the same or fewer names that the limit specified in {{cs1 config}}. ]] local function get_display_names (max, count, etal, param) if utilities.is_set (max) then if 'etal' == cfg.keywords_xlate[max:lower():gsub("[ '%.]", '')] then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings max = count + 1; -- number of authors + 1 so display all author name plus et al. etal = true; -- overrides value set by extract_names() elseif max:match ('^%d+$') then -- if is a string of numbers max = tonumber (max); -- make it a number if (max >= count) and ('cs1 config' ~= param) then -- error when local |display-xxxxors= value greater than or equal to number of names; not an error when using global setting utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; end else -- not a valid keyword or number utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; -- unset; as if |display-xxxxors= had not been set end end return max, etal; end --[[----------< E X T R A _ T E X T _ I N _ P A G E _ C H E C K >--------------- Adds error if |page=, |pages=, |quote-page=, |quote-pages= has what appears to be some form of p. or pp. abbreviation in the first characters of the parameter content. check page for extraneous p, p., pp, pp., pg, pg. at start of parameter value: good pattern: '^P[^%.P%l]' matches when page begins PX or P# but not Px where x and X are letters and # is a digit bad pattern: '^[Pp][PpGg]' matches when page begins pp, pP, Pp, PP, pg, pG, Pg, PG ]] local function extra_text_in_page_check (val, name) if not val:match (cfg.vol_iss_pg_patterns.good_ppattern) then for _, pattern in ipairs (cfg.vol_iss_pg_patterns.bad_ppatterns) do -- spin through the selected sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message ('err_extra_text_pages', name); -- add error message return; -- and done end end end end --[[--------------------------< E X T R A _ T E X T _ I N _ V O L _ I S S _ C H E C K >------------------------ Adds error if |volume= or |issue= has what appears to be some form of redundant 'type' indicator. Applies to both; this function looks for issue text in both |issue= and |volume= and looks for volume-like text in |voluem= and |issue=. For |volume=: 'V.', or 'Vol.' (with or without the dot) abbreviations or 'Volume' in the first characters of the parameter content (all case insensitive). 'V' and 'v' (without the dot) are presumed to be roman numerals so are allowed. For |issue=: 'No.', 'I.', 'Iss.' (with or without the dot) abbreviations, or 'Issue' in the first characters of the parameter content (all case insensitive); numero styling: 'n°' with degree sign U+00B0, and № precomposed numero sign U+2116. Single character values ('v', 'i', 'n') allowed when not followed by separator character ('.', ':', '=', or whitespace character) – param values are trimmed of whitespace by MediaWiki before delivered to the module. <val> is |volume= or |issue= parameter value <name> is |volume= or |issue= parameter name for error message <selector> is 'v' for |volume=, 'i' for |issue= sets error message on failure; returns nothing ]] local function extra_text_in_vol_iss_check (val, name, selector) if not utilities.is_set (val) then return; end local handler = 'v' == selector and 'err_extra_text_volume' or 'err_extra_text_issue'; local accept_val; -- for now, ignore linter warning val, accept_val = utilities.has_accept_as_written (val); --if accept_val then -- if uncomment this, |volume=((vol. 1)) suppresses error -- return; --end --val = mw.text.unstripNoWiki (val); -- if uncomment this, |volume=<nowiki>vol. 1</nowiki> shows error val = val:lower(); -- force parameter value to lower case for _, pattern in ipairs (cfg.vol_iss_pg_patterns.vi_patterns_t) do -- spin through the sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message (handler, name); -- add error message return; -- and done end end end --[=[-------------------------< G E T _ V _ N A M E _ T A B L E >---------------------------------------------- split apart a |vauthors= or |veditors= parameter. This function allows for corporate names, wrapped in doubled parentheses to also have commas; in the old version of the code, the doubled parentheses were included in the rendered citation and in the metadata. Individual author names may be wikilinked |vauthors=Jones AB, [[E. B. White|White EB]], ((Black, Brown, and Co.)) ]=] local function get_v_name_table (vparam, output_table, output_link_table) local _, accept = utilities.has_accept_as_written (vparam); if accept then utilities.add_prop_cat ('vanc-accept'); -- add properties category end local name_table = mw.text.split(vparam, "%s*,%s*"); -- names are separated by commas local wl_type, label, link; -- wl_type not used here; just a placeholder local i = 1; while name_table[i] do if name_table[i]:match ('^%(%(.*[^%)][^%)]$') then -- first segment of corporate with one or more commas; this segment has the opening doubled parentheses local name = name_table[i]; i = i + 1; -- bump indexer to next segment while name_table[i] do name = name .. ', ' .. name_table[i]; -- concatenate with previous segments if name_table[i]:match ('^.*%)%)$') then -- if this table member has the closing doubled parentheses break; -- and done reassembling so end i = i + 1; -- bump indexer end table.insert (output_table, name); -- and add corporate name to the output table table.insert (output_link_table, ''); -- no wikilink else wl_type, label, link = utilities.is_wikilink (name_table[i]); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] table.insert (output_table, label); -- add this name if 1 == wl_type then table.insert (output_link_table, label); -- simple wikilink [[D]] else table.insert (output_link_table, link); -- no wikilink or [[L|D]]; add this link if there is one, else empty string end end i = i + 1; end return output_table; end --[[--------------------------< P A R S E _ V A U T H O R S _ V E D I T O R S >-------------------------------- This function extracts author / editor names from |vauthors= or |veditors= and finds matching |xxxxor-maskn= and |xxxxor-linkn= in args. It then returns a table of assembled names just as extract_names() does. Author / editor names in |vauthors= or |veditors= must be in Vancouver system style. Corporate or institutional names may sometimes be required and because such names will often fail the is_good_vanc_name() and other format compliance tests, are wrapped in doubled parentheses ((corporate name)) to suppress the format tests. Supports generational suffixes Jr, 2nd, 3rd, 4th–6th. This function sets the Vancouver error when a required comma is missing and when there is a space between an author's initials. ]] local function parse_vauthors_veditors (args, vparam, list_name) local names = {}; -- table of names assembled from |vauthors=, |author-maskn=, |author-linkn= local v_name_table = {}; local v_link_table = {}; -- when name is wikilinked, targets go in this table local etal = false; -- return value set to true when we find some form of et al. vauthors parameter local last, first, link, mask, suffix; local corporate = false; vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period) v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); -- names are separated by commas for i, v_name in ipairs(v_name_table) do first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor local accept_name; v_name, accept_name = utilities.has_accept_as_written (v_name); -- remove accept-this-as-written markup when it wraps all of <v_name> if accept_name then last = v_name; corporate = true; -- flag used in list_people() elseif string.find(v_name, "%s") then if v_name:find('[;%.]') then -- look for commonly occurring punctuation characters; add_vanc_error (cfg.err_msg_supl.punctuation, i); end local lastfirst_t = mw.text.split(v_name, "%s+"); first = table.remove (lastfirst_t); -- removes and returns value of last element in table which should be initials or generational suffix if not mw.ustring.match (first, '^%u+$') then -- mw.ustring here so that later we will catch non-Latin characters suffix = first; -- not initials so assume that whatever we got is a generational suffix first = table.remove (lastfirst_t); -- get what should be the initials from the table end last = table.concat (lastfirst_t, ' '); -- returns a string that is the concatenation of all other names that are not initials and generational suffix if not utilities.is_set (last) then first = ''; -- unset last = v_name; -- last empty because something wrong with first add_vanc_error (cfg.err_msg_supl.name, i); end if mw.ustring.match (last, '%a+%s+%u+%s+%a+') then add_vanc_error (cfg.err_msg_supl['missing comma'], i); -- matches last II last; the case when a comma is missing end if mw.ustring.match (v_name, ' %u %u$') then -- this test is in the wrong place TODO: move or replace with a more appropriate test add_vanc_error (cfg.err_msg_supl.initials, i); -- matches a space between two initials end else last = v_name; -- last name or single corporate name? Doesn't support multiword corporate names? do we need this? end if utilities.is_set (first) then if not mw.ustring.match (first, "^%u?%u$") then -- first shall contain one or two upper-case letters, nothing else add_vanc_error (cfg.err_msg_supl.initials, i); -- too many initials; mixed case initials (which may be ok Romanization); hyphenated initials end is_good_vanc_name (last, first, suffix, i); -- check first and last before restoring the suffix which may have a non-Latin digit if utilities.is_set (suffix) then first = first .. ' ' .. suffix; -- if there was a suffix concatenate with the initials suffix = ''; -- unset so we don't add this suffix to all subsequent names end else if not corporate then is_good_vanc_name (last, '', nil, i); end end link = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ) or v_link_table[i]; mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); names[i] = {last = last, first = first, link = link, mask = mask, corporate = corporate}; -- add this assembled name to our names list end return names, etal; -- all done, return our list of names end --[[--------------------------< S E L E C T _ A U T H O R _ E D I T O R _ S O U R C E >------------------------ Select one of |authors=, |authorn= / |lastn / firstn=, or |vauthors= as the source of the author name list or select one of |editorn= / editor-lastn= / |editor-firstn= or |veditors= as the source of the editor name list. Only one of these appropriate three will be used. The hierarchy is: |authorn= (and aliases) highest and |authors= lowest; |editorn= (and aliases) highest and |veditors= lowest (support for |editors= withdrawn) When looking for |authorn= / |editorn= parameters, test |xxxxor1= and |xxxxor2= (and all of their aliases); stops after the second test which mimicks the test used in extract_names() when looking for a hole in the author name list. There may be a better way to do this, I just haven't discovered what that way is. Emits an error message when more than one xxxxor name source is provided. In this function, vxxxxors = vauthors or veditors; xxxxors = authors as appropriate. ]] local function select_author_editor_source (vxxxxors, xxxxors, args, list_name) local lastfirst = false; if utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 1 ) or -- do this twice in case we have a |first1= without a |last1=; this ... utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 1 ) or -- ... also catches the case where |first= is used with |vauthors= utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 2 ) or utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 2 ) then lastfirst = true; end if (utilities.is_set (vxxxxors) and true == lastfirst) or -- these are the three error conditions (utilities.is_set (vxxxxors) and utilities.is_set (xxxxors)) or (true == lastfirst and utilities.is_set (xxxxors)) then utilities.set_message ('err_redundant_parameters', utilities.substitute (cfg.special_case_translation.name_list_params, ('AuthorList' == list_name) and cfg.special_case_translation.author or cfg.special_case_translation.editor)); -- add error message end if true == lastfirst then return 1 end; -- return a number indicating which author name source to use if utilities.is_set (vxxxxors) then return 2 end; if utilities.is_set (xxxxors) then return 3 end; return 1; -- no authors so return 1; this allows missing author name test to run in case there is a first without last end --[[--------------------------< I S _ V A L I D _ P A R A M E T E R _ V A L U E >------------------------------ This function is used to validate a parameter's assigned value for those parameters that have only a limited number of allowable values (yes, y, true, live, dead, etc.). When the parameter value has not been assigned a value (missing or empty in the source template) the function returns the value specified by ret_val. If the parameter value is one of the list of allowed values returns the translated value; else, emits an error message and returns the value specified by ret_val. TODO: explain <invert> ]] local function is_valid_parameter_value (value, name, possible, ret_val, invert) if not utilities.is_set (value) then return ret_val; -- an empty parameter is ok end if (not invert and utilities.in_array (value, possible)) then -- normal; <value> is in <possible> table return cfg.keywords_xlate[value]; -- return translation of parameter keyword elseif invert and not utilities.in_array (value, possible) then -- invert; <value> is not in <possible> table return value; -- return <value> as it is else utilities.set_message ('err_invalid_param_val', {name, value}); -- not an allowed value so add error message return ret_val; end end --[[--------------------------< T E R M I N A T E _ N A M E _ L I S T >---------------------------------------- This function terminates a name list (author, contributor, editor) with a separator character (sepc) and a space when the last character is not a sepc character or when the last three characters are not sepc followed by two closing square brackets (close of a wikilink). When either of these is true, the name_list is terminated with a single space character. ]] local function terminate_name_list (name_list, sepc) if (string.sub (name_list, -3, -1) == sepc .. '. ') then -- if already properly terminated return name_list; -- just return the name list elseif (string.sub (name_list, -1, -1) == sepc) or (string.sub (name_list, -3, -1) == sepc .. ']]') then -- if last name in list ends with sepc char return name_list .. " "; -- don't add another else return name_list .. sepc .. ' '; -- otherwise terminate the name list end end --[[-------------------------< F O R M A T _ V O L U M E _ I S S U E >----------------------------------------- returns the concatenation of the formatted volume and issue (or journal article number) parameters as a single string; or formatted volume or formatted issue, or an empty string if neither are set. ]] local function format_volume_issue (volume, issue, article, cite_class, origin, sepc, lower) if not utilities.is_set (volume) and not utilities.is_set (issue) and not utilities.is_set (article) then return ''; end -- same condition as in format_pages_sheets() local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); local is_numeric_vol = volume and (volume:match ('^[MDCLXVI]+$') or volume:match ('^%d+$')); -- is only uppercase roman numerals or only digits? local is_long_vol = volume and (4 < mw.ustring.len(volume)); -- is |volume= value longer than 4 characters? if volume and (not is_numeric_vol and is_long_vol) then -- when not all digits or Roman numerals, is |volume= longer than 4 characters? utilities.add_prop_cat ('long-vol'); -- yes, add properties cat end if is_journal then -- journal-style formatting local vol = ''; if utilities.is_set (volume) then if is_numeric_vol then -- |volume= value all digits or all uppercase Roman numerals? vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, volume}); -- render in bold face elseif is_long_vol then -- not all digits or Roman numerals; longer than 4 characters? vol = utilities.substitute (cfg.messages['j-vol'], {sepc, utilities.hyphen_to_dash (volume)}); -- not bold else -- four or fewer characters vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, utilities.hyphen_to_dash (volume)}); -- bold end end vol = vol .. (utilities.is_set (issue) and utilities.substitute (cfg.messages['j-issue'], issue) or '') vol = vol .. (utilities.is_set (article) and utilities.substitute (cfg.messages['j-article-num'], article) or '') return vol; end if 'podcast' == cite_class and utilities.is_set (issue) then return wrap_msg ('issue', {sepc, issue}, lower); end if 'conference' == cite_class and utilities.is_set (article) then -- |article-number= supported only in journal and conference cites if utilities.is_set (volume) and utilities.is_set (article) then -- both volume and article number return wrap_msg ('vol-art', {sepc, utilities.hyphen_to_dash (volume), article}, lower); elseif utilities.is_set (article) then -- article number alone; when volume alone, handled below return wrap_msg ('art', {sepc, article}, lower); end end -- all other types of citation if utilities.is_set (volume) and utilities.is_set (issue) then return wrap_msg ('vol-no', {sepc, utilities.hyphen_to_dash (volume), issue}, lower); elseif utilities.is_set (volume) then return wrap_msg ('vol', {sepc, utilities.hyphen_to_dash (volume)}, lower); else return wrap_msg ('issue', {sepc, issue}, lower); end end --[[-------------------------< F O R M A T _ P A G E S _ S H E E T S >----------------------------------------- adds static text to one of |page(s)= or |sheet(s)= values and returns it with all of the others set to empty strings. The return order is: page, pages, sheet, sheets Singular has priority over plural when both are provided. ]] local function format_pages_sheets (page, pages, sheet, sheets, cite_class, origin, sepc, nopp, lower) if 'map' == cite_class then -- only cite map supports sheet(s) as in-source locators if utilities.is_set (sheet) then if 'journal' == origin then return '', '', wrap_msg ('j-sheet', sheet, lower), ''; else return '', '', wrap_msg ('sheet', {sepc, sheet}, lower), ''; end elseif utilities.is_set (sheets) then if 'journal' == origin then return '', '', '', wrap_msg ('j-sheets', sheets, lower); else return '', '', '', wrap_msg ('sheets', {sepc, sheets}, lower); end end end local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); if utilities.is_set (page) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], page), '', '', ''; elseif not nopp then return utilities.substitute (cfg.messages['p-prefix'], {sepc, page}), '', '', ''; else return utilities.substitute (cfg.messages['nopp'], {sepc, page}), '', '', ''; end elseif utilities.is_set (pages) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], pages), '', '', ''; elseif tonumber(pages) ~= nil and not nopp then -- if pages is only digits, assume a single page number return '', utilities.substitute (cfg.messages['p-prefix'], {sepc, pages}), '', ''; elseif not nopp then return '', utilities.substitute (cfg.messages['pp-prefix'], {sepc, pages}), '', ''; else return '', utilities.substitute (cfg.messages['nopp'], {sepc, pages}), '', ''; end end return '', '', '', ''; -- return empty strings end --[[--------------------------< I N S O U R C E _ L O C _ G E T >---------------------------------------------- returns one of the in-source locators: page, pages, or at. If any of these are interwiki links to Wikisource, returns the label portion of the interwiki-link as plain text for use in COinS. This COinS thing is done because here we convert an interwiki-link to an external link and add an icon span around that; get_coins_pages() doesn't know about the span. TODO: should it? TODO: add support for sheet and sheets?; streamline; TODO: make it so that this function returns only one of the three as the single in-source (the return value assigned to a new name)? ]] local function insource_loc_get (page, page_orig, pages, pages_orig, at) local ws_url, ws_label, coins_pages, L; -- for Wikisource interwiki-links; TODO: this corrupts page metadata (span remains in place after cleanup; fix there?) if utilities.is_set (page) then if utilities.is_set (pages) or utilities.is_set (at) then pages = ''; -- unset the others at = ''; end extra_text_in_page_check (page, page_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (page); -- make ws URL from |page= interwiki link; link portion L becomes tooltip label if ws_url then page = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in page'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? page = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, page}); coins_pages = ws_label; end elseif utilities.is_set (pages) then if utilities.is_set (at) then at = ''; -- unset end extra_text_in_page_check (pages, pages_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (pages); -- make ws URL from |pages= interwiki link; link portion L becomes tooltip label if ws_url then pages = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in pages'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? pages = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, pages}); coins_pages = ws_label; end elseif utilities.is_set (at) then ws_url, ws_label, L = wikisource_url_make (at); -- make ws URL from |at= interwiki link; link portion L becomes tooltip label if ws_url then at = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in at'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? at = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, at}); coins_pages = ws_label; end end return page, pages, at, coins_pages; end --[[--------------------------< I S _ U N I Q U E _ A R C H I V E _ U R L >------------------------------------ add error message when |archive-url= value is same as |url= or chapter-url= (or alias...) value ]] local function is_unique_archive_url (archive, url, c_url, source, date) if utilities.is_set (archive) then if archive == url or archive == c_url then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); -- add error message return '', ''; -- unset |archive-url= and |archive-date= because same as |url= or |chapter-url= end end return archive, date; end --[=[-------------------------< A R C H I V E _ U R L _ C H E C K >-------------------------------------------- Check archive.org URLs to make sure they at least look like they are pointing at valid archives and not to the save snapshot URL or to calendar pages. When the archive URL is 'https://web.archive.org/save/' (or http://...) archive.org saves a snapshot of the target page in the URL. That is something that Wikipedia should not allow unwitting readers to do. When the archive.org URL does not have a complete timestamp, archive.org chooses a snapshot according to its own algorithm or provides a calendar 'search' result. [[WP:ELNO]] discourages links to search results. This function looks at the value assigned to |archive-url= and returns empty strings for |archive-url= and |archive-date= and an error message when: |archive-url= holds an archive.org save command URL |archive-url= is an archive.org URL that does not have a complete timestamp (YYYYMMDDhhmmss 14 digits) in the correct place otherwise returns |archive-url= and |archive-date= There are two mostly compatible archive.org URLs: //web.archive.org/<timestamp>... -- the old form //web.archive.org/web/<timestamp>... -- the new form The old form does not support or map to the new form when it contains a display flag. There are four identified flags ('id_', 'js_', 'cs_', 'im_') but since archive.org ignores others following the same form (two letters and an underscore) we don't check for these specific flags but we do check the form. This function supports a preview mode. When the article is rendered in preview mode, this function may return a modified archive URL: for save command errors, return undated wildcard (/*/) for timestamp errors when the timestamp has a wildcard, return the URL unmodified for timestamp errors when the timestamp does not have a wildcard, return with timestamp limited to six digits plus wildcard (/yyyymm*/) A secondary function is to return an archive-url timestamp from those archive urls that have them. The timestamp is used by validation.archive_date_check() to see if the value in |archive-date= matches the timestamp in the archive url. ]=] local function archive_url_check (url, date) local err_msg; -- start with the error message empty local path, timestamp, flag; -- portions of the archive.org URL local function is_ts_date_valid (ts, origin_date) -- local function to validate archive url taimestamp date; time ignored local y, m, d = ts:match ('(%d%d%d%d)(%d%d)(%d%d)'); -- split into parts if y and validation.is_valid_date (y, m, d) and (tonumber (y) >= 1996) then return true, tonumber (y) >= origin_date; -- <origin_date> is 1996 for archive.org end end if (not url:match('//web%.archive%.org/')) and (not url:match('//liveweb%.archive%.org/')) then -- also deprecated liveweb Wayback machine URL return url, date; -- not an archive.org archive, return ArchiveURL and ArchiveDate end if url:match('//web%.archive%.org/save/') then -- if a save command URL, we don't want to allow saving of the target page err_msg = cfg.err_msg_supl.save; url = url:gsub ('(//web%.archive%.org)/save/', '%1/*/', 1); -- for preview mode: modify ArchiveURL elseif url:match('//liveweb%.archive%.org/') then err_msg = cfg.err_msg_supl.liveweb; else path, timestamp, flag = url:match('//web%.archive%.org/([^%d]*)(%d+)([^/]*)/'); -- split out some of the URL parts for evaluation if not path then -- malformed in some way; pattern did not match err_msg = cfg.err_msg_supl.timestamp; elseif 14 ~= timestamp:len() then -- path and flag optional, must have 14-digit timestamp here err_msg = cfg.err_msg_supl.timestamp; if '*' ~= flag then local replacement = timestamp:match ('^%d%d%d%d%d%d') or timestamp:match ('^%d%d%d%d'); -- get the first 6 (YYYYMM) or first 4 digits (YYYY) if replacement then -- nil if there aren't at least 4 digits (year) replacement = replacement .. string.rep ('0', 14 - replacement:len()); -- year or yearmo (4 or 6 digits) zero-fill to make 14-digit timestamp url=url:gsub ('(//web%.archive%.org/[^%d]*)%d[^/]*', '%1' .. replacement .. '*', 1) -- for preview, modify ts to 14 digits plus splat for calendar display end end elseif not is_ts_date_valid (timestamp, 1996) then -- is ymd portion of timestamp a valid date? err_msg = cfg.err_msg_supl.timestamp; timestamp = nil; -- unset because invalid elseif utilities.is_set (path) and 'web/' ~= path then -- older archive URLs do not have the extra 'web/' path element err_msg = cfg.err_msg_supl.path; elseif utilities.is_set (flag) and not utilities.is_set (path) then -- flag not allowed with the old form URL (without the 'web/' path element) err_msg = cfg.err_msg_supl.flag; elseif utilities.is_set (flag) and not flag:match ('%a%a_') then -- flag if present must be two alpha characters and underscore (requires 'web/' path element) err_msg = cfg.err_msg_supl.flag; else return url, date, timestamp; -- return ArchiveURL, ArchiveDate, and timestamp from |archive-url= end end -- if here, something not right so utilities.set_message ('err_archive_url', {err_msg}); -- add error message and if is_preview_mode then return url, date, timestamp; -- preview mode so return ArchiveURL, ArchiveDate, and timestamp from |archive-url= else return '', ''; -- return empty strings for ArchiveURL and ArchiveDate end end --[[--------------------------< P L A C E _ C H E C K >-------------------------------------------------------- check |place=, |publication-place=, |location= to see if these params include digits. This function added because many editors misuse location to specify the in-source location (|page(s)= and |at= are supposed to do that) returns the original parameter value without modification; added maint cat when parameter value contains digits ]] local function place_check (param_val) if not utilities.is_set (param_val) then -- parameter empty or omitted return param_val; -- return that empty state end if mw.ustring.find (param_val, '%d') then -- not empty, are there digits in the parameter value utilities.set_message ('maint_location'); -- yep, add maint cat end return param_val; -- and done end --[[--------------------------< I S _ A R C H I V E D _ C O P Y >---------------------------------------------- compares |title= to 'Archived copy' (placeholder added by bots that can't find proper title); if matches, return true; nil else ]] local function is_archived_copy (title) title = mw.ustring.lower(title); -- switch title to lower case if title:find (cfg.special_case_translation.archived_copy.en) then -- if title is 'Archived copy' return true; elseif cfg.special_case_translation.archived_copy['local'] then if mw.ustring.find (title, cfg.special_case_translation.archived_copy['local']) then -- mw.ustring() because might not be Latin script return true; end end end --[[--------------------------< D I S P L A Y _ N A M E S _ S E L E C T >-------------------------------------- for any of the |display-authors=, |display-editors=, etc parameters, select either the local or global setting. When both are present, look at <local_display_names> value. When the value is some sort of 'et al.'string, special handling is required. When {{cs1 config}} has |display-<namelist>= AND this template has |display-<namelist>=etal AND: the number of names specified by <number_of_names> is: greater than the number specified in the global |display-<namelist>= parameter (<global_display_names>) use global |display-<namelist>= parameter value set overridden maint category less than or equal to the number specified in the global |display-<namelist>= parameter use local |display-<namelist>= parameter value The purpose of this function is to prevent categorizing a template that has fewer names than the global setting to keep the etal annotation specified by <local_display_names>. ]] local function display_names_select (global_display_names, local_display_names, param_name, number_of_names) if global_display_names and utilities.is_set (local_display_names) then -- when both if 'etal' == local_display_names:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings number_of_names = tonumber (number_of_names); -- convert these to numbers for comparison local global_display_names_num = tonumber (global_display_names); -- <global_display_names> not set when parameter value is not digits if number_of_names > global_display_names_num then -- template has more names than global config allows to be displayed? utilities.set_message ('maint_overridden_setting'); -- set a maint message because global is overriding local |display-<namelist>=etal return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local because fewer names so let <local_display_names> control end end -- here when <global_display_names> and <local_display_names> both numbers; <global_display_names> controls utilities.set_message ('maint_overridden_setting'); -- set a maint message return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) end -- here when only one of <global_display_names> or <local_display_names> set if global_display_names then return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local end end --[[--------------------------< M O D E _ S E T >-------------------------------------------------------------- fetch global mode setting from {{cs1 config}} (if present) or from |mode= (if present); global setting overrides local |mode= parameter value. When both are present, emit maintenance message ]] local function mode_set (Mode, Mode_origin) local mode; if cfg.global_cs1_config_t['Mode'] then -- global setting in {{cs1 config}}; nil when empty or assigned value invalid mode = is_valid_parameter_value (cfg.global_cs1_config_t['Mode'], 'cs1 config: mode', cfg.keywords_lists['mode'], ''); -- error messaging 'param' here is a hoax else mode = is_valid_parameter_value (Mode, Mode_origin, cfg.keywords_lists['mode'], ''); end if cfg.global_cs1_config_t['Mode'] and utilities.is_set (Mode) then -- when template has |mode=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end return mode; end --[[--------------------------< Q U O T E _ M A K E >---------------------------------------------------------- create quotation from |quote=, |trans-quote=, and/or script-quote= with or without |quote-page= or |quote-pages= when any of those three quote parameters are set, this function unsets <PostScript>. When none of those parameters are set, |quote-page= and |quote-pages= are unset to nil so that they are not included in the template's metadata ]] local function quote_make (quote, trans_quote, script_quote, quote_page, quote_pages, nopp, sepc, postscript) if utilities.is_set (quote) or utilities.is_set (trans_quote) or utilities.is_set (script_quote) then if utilities.is_set (quote) then if quote:sub(1, 1) == '"' and quote:sub(-1, -1) == '"' then -- if first and last characters of quote are quote marks quote = quote:sub(2, -2); -- strip them off end end quote = kern_quotes (quote); -- kern if needed quote = utilities.wrap_style ('quoted-text', quote ); -- wrap in <q>...</q> tags if utilities.is_set (script_quote) then quote = script_concatenate (quote, script_quote, 'script-quote'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after quote is wrapped end if utilities.is_set (trans_quote) then if trans_quote:sub(1, 1) == '"' and trans_quote:sub(-1, -1) == '"' then -- if first and last characters of |trans-quote are quote marks trans_quote = trans_quote:sub(2, -2); -- strip them off end quote = quote .. " " .. utilities.wrap_style ('trans-quoted-title', trans_quote ); end if utilities.is_set (quote_page) or utilities.is_set (quote_pages) then -- add page prefix local quote_prefix = ''; if utilities.is_set (quote_page) then extra_text_in_page_check (quote_page, 'quote-page'); -- add to maint cat if |quote-page= value begins with what looks like p., pp., etc. if not nopp then quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_page}); else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_page}); end elseif utilities.is_set (quote_pages) then extra_text_in_page_check (quote_pages, 'quote-pages'); -- add to maint cat if |quote-pages= value begins with what looks like p., pp., etc. if tonumber(quote_pages) ~= nil and not nopp then -- if only digits, assume single page quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_pages}); elseif not nopp then quote_prefix = utilities.substitute (cfg.messages['pp-prefix'], {sepc, quote_pages}); else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_pages}); end end quote = quote_prefix .. ": " .. quote; else quote = sepc .. " " .. quote; end postscript = ""; -- cs1|2 does not supply terminal punctuation when |quote= is set elseif utilities.is_set (quote_page) or utilities.is_set (quote_pages) then quote_page = nil; -- unset; these require |quote=; TODO: error message? quote_pages = nil; end return quote, quote_page, quote_pages, postscript; end --[[--------------------------< C H E C K _ P U B L I S H E R _ N A M E >-------------------------------------- look for variations of '<text>: <text>' that might be '<location>: <publisher>' in |publisher= parameter value. when found, emit a maintenance message; return nil else <publisher> is the value assigned to |publisher= or |institution= ]] local function check_publisher_name (publisher) local patterns_t = { '^[%w%s]+%s*:%s*[%w%s]+$', -- plain text <location>: <publisher> '^%[+[%w%s:|]+%]+%s*:%s*[%w%s]+$', -- partially wikilinked [[<location>]]: <publisher> '^[%w%s]+%s*:%s*%[+[%w%s:|]+%]+$', -- partially wikilinked <location>: [[<publisher>]] '^%[+[%w%s:|]+%]+%s*:%s*%[+[%w%s:|]+%]+$', -- wikilinked [[<location>]]: [[<publisher>]] } for _, pattern in ipairs (patterns_t) do -- spin through the patterns_t sequence if mw.ustring.match (publisher, pattern) then -- does this pattern match? utilities.set_message ('maint_publisher_location'); -- set a maint message return; -- and done end end end --[[--------------------------< I S _ P A G E _ A R T _ N U M >------------------------------------------------ compare the trailing (rightmost) characters of the |doi= value against the whole value assigned to |page(s)=. return boolean true when: |page(s)= has exactly 8 digits and a dot between the fourth and fifth digits matches the trailing 9 characters of the |doi= value: |page=12345678 → |page=1234.5678 matches |doi=10.xxxx/yyyy1234.5678 |page(s)= is 5 or more characters and matches |doi= values's trailing characters |page(s)= begins with a lowercase 'e' and |page(s)= without the 'e' matches |doi= values's trailing characters: |page=e12345 → |page=12345 matches |doi=10.xxxx/yyyy12345 |page(s)= begins with a uppercase 'CD' followed by (typically) six digits matches |doi= values that ends with 'CDxxxxxx.pubx' (where 'x' is any single digit) return nil when |page(s)= values: are ranges separated by underscore, hyphen, emdash, endash, figure dash, or minus character are comma- or semicolon-separated lists of pages have external urls (has text 'http') are digit-only values less than 10000 do not match |doi= values's trailing characters ]] local function is_page_art_num (page, doi) if not (utilities.is_set (page) and utilities.is_set (doi)) then -- both required return; -- abandon; nothing to do end if page:match ('[,;_−–—‒%-]') then -- when |page(s)= might be a page range or a separated list of pages return; -- abandon end page = page:lower(); -- because doi names are case insensitive doi = doi:lower(); -- force these to lowercase for testing if page:match ('http') then -- when |page(s)= appears to hold a url return; -- abandon end if tonumber (page) then -- is |page(s)= digits only if 10000 > tonumber (page) then -- when |page(s)= less than 10000 return; -- abandon end if doi:match (page .. '$') then -- digits only page number match the last digits in |doi=? return true; end if 8 == page:len() then -- special case when |page(s)= is exactly 8 digits local dot_page = page:gsub ('(%d%d%d%d)(%d%d%d%d)', '%1.%2'); -- make a |page=xxxx.yyyy version commonly used in |doi= if doi:match (dot_page .. '$') then -- 8-digit dotted page number match the last characters in |doi=? return true; end end else -- here when |page(s)= is alpha-numeric if 4 < page:len() then -- when |page(s)= is five or more characters if doi:match (page .. '$') then -- alpha-numeric page match the last characters in |doi=? return true; end local epage = page:match ('^e([%w]+)$'); -- if first character of |page= is 'e', remove it if epage and doi:match (epage .. '$') then -- page number match the last characters in |doi=? return true; end local cdpage = page:match ('^cd%d+$'); -- if first characters of |page= are 'CD' and last characters are digits (typically 6 digits) if cdpage and doi:match (cdpage .. '%.pub%d$') then -- page number matches doi 'CDxxxxxx.pubx' where 'x' is a digit return true; end end end end --[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------ This is the main function doing the majority of the citation formatting. ]] local function citation0( config, args ) --[[ Load Input Parameters The argument_wrapper facilitates the mapping of multiple aliases to single internal variable. ]] local A = argument_wrapper ( args ); -- Pick out the relevant fields from the arguments. Different citation templates -- define different field names for the same underlying things. local author_etal; local a = {}; -- authors list from |lastn= / |firstn= pairs or |vauthors= local Authors; local NameListStyle; if cfg.global_cs1_config_t['NameListStyle'] then -- global setting in {{cs1 config}} overrides local |name-list-style= parameter value; nil when empty or assigned value invalid NameListStyle = is_valid_parameter_value (cfg.global_cs1_config_t['NameListStyle'], 'cs1 config: name-list-style', cfg.keywords_lists['name-list-style'], ''); -- error messaging 'param' here is a hoax else NameListStyle = is_valid_parameter_value (A['NameListStyle'], A:ORIGIN('NameListStyle'), cfg.keywords_lists['name-list-style'], ''); end if cfg.global_cs1_config_t['NameListStyle'] and utilities.is_set (A['NameListStyle']) then -- when template has |name-list-style=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end local Collaboration = A['Collaboration']; do -- to limit scope of selected local selected = select_author_editor_source (A['Vauthors'], A['Authors'], args, 'AuthorList'); if 1 == selected then a, author_etal = extract_names (args, 'AuthorList'); -- fetch author list from |authorn= / |lastn= / |firstn=, |author-linkn=, and |author-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be a, author_etal = parse_vauthors_veditors (args, A['Vauthors'], 'AuthorList'); -- fetch author list from |vauthors=, |author-linkn=, and |author-maskn= elseif 3 == selected then Authors = A['Authors']; -- use content of |people= or |credits=; |authors= is deprecated; TODO: constrain |people= and |credits= to cite av media, episode, serial? end if utilities.is_set (Collaboration) then author_etal = true; -- so that |display-authors=etal not required end end local editor_etal; local e = {}; -- editors list from |editor-lastn= / |editor-firstn= pairs or |veditors= do -- to limit scope of selected local selected = select_author_editor_source (A['Veditors'], nil, args, 'EditorList'); -- support for |editors= withdrawn if 1 == selected then e, editor_etal = extract_names (args, 'EditorList'); -- fetch editor list from |editorn= / |editor-lastn= / |editor-firstn=, |editor-linkn=, and |editor-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be e, editor_etal = parse_vauthors_veditors (args, args.veditors, 'EditorList'); -- fetch editor list from |veditors=, |editor-linkn=, and |editor-maskn= end end local Chapter = A['Chapter']; -- done here so that we have access to |contribution= from |chapter= and |script-chapter= aliases local Chapter_origin = A:ORIGIN ('Chapter'); local ScriptChapter = A['ScriptChapter']; local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); local Contribution; -- because contribution is required for contributor(s) if 'contribution' == Chapter_origin then -- is there a |contribution= parameter? Contribution = Chapter; -- get the name of the contribution elseif 'script-contribution' == ScriptChapter_origin then -- no, so is there a |script-contribution= parameter? Contribution = ScriptChapter; -- get the name of the contribution end local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (A['Periodical']) then -- |contributor= and |contribution= only supported in book cites c = extract_names (args, 'ContributorList'); -- fetch contributor list from |contributorn= / |contributor-lastn=, -firstn=, -linkn=, -maskn= if 0 < #c then if not utilities.is_set (Contribution) then -- |contributor= requires |contribution= utilities.set_message ('err_contributor_missing_required_param', 'contribution'); -- add missing contribution error message c = {}; -- blank the contributors' table; it is used as a flag later end if 0 == #a then -- |contributor= requires |author= utilities.set_message ('err_contributor_missing_required_param', 'author'); -- add missing author error message c = {}; -- blank the contributors' table; it is used as a flag later end end else -- if not a book cite if utilities.select_one (args, cfg.aliases['ContributorList-Last'], 'err_redundant_parameters', 1 ) then -- are there contributor name list parameters? utilities.set_message ('err_contributor_ignored'); -- add contributor ignored error message end Contribution = nil; -- unset end local Title = A['Title']; local TitleLink = A['TitleLink']; local auto_select = ''; -- default is auto local accept_link; TitleLink, accept_link = utilities.has_accept_as_written (TitleLink, true); -- test for accept-this-as-written markup if (not accept_link) and utilities.in_array (TitleLink, {'none', 'pmc', 'doi'}) then -- check for special keywords auto_select = TitleLink; -- remember selection for later TitleLink = ''; -- treat as if |title-link= would have been empty end TitleLink = link_title_ok (TitleLink, A:ORIGIN ('TitleLink'), Title, 'title'); -- check for wiki-markup in |title-link= or wiki-markup in |title= when |title-link= is set local Section = ''; -- {{cite map}} only; preset to empty string for concatenation if not used if 'map' == config.CitationClass and 'section' == Chapter_origin then Section = A['Chapter']; -- get |section= from |chapter= alias list; |chapter= and the other aliases not supported in {{cite map}} Chapter = ''; -- unset for now; will be reset later from |map= if present end local Periodical = A['Periodical']; local Periodical_origin = A:ORIGIN('Periodical'); local ScriptPeriodical = A['ScriptPeriodical']; local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical'); local TransPeriodical = A['TransPeriodical']; local TransPeriodical_origin = A:ORIGIN ('TransPeriodical'); if (utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical))) then local param; if utilities.is_set (Periodical) then -- get a parameter name from one of these periodical related meta-parameters Periodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = Periodical_origin -- get parameter name for error messaging elseif utilities.is_set (TransPeriodical) then TransPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = TransPeriodical_origin; -- get parameter name for error messaging elseif utilities.is_set (ScriptPeriodical) then ScriptPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = ScriptPeriodical_origin; -- get parameter name for error messaging end if utilities.is_set (param) then -- if we found one utilities.set_message ('err_periodical_ignored', {param}); -- emit an error message end end if utilities.is_set (Periodical) then local i; Periodical, i = utilities.strip_apostrophe_markup (Periodical); -- strip apostrophe markup so that metadata isn't contaminated if i then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {Periodical_origin}); end end if 'mailinglist' == config.CitationClass then -- special case for {{cite mailing list}} if utilities.is_set (Periodical) and utilities.is_set (A ['MailingList']) then -- both set emit an error TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', Periodical_origin) .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'mailinglist')}); end Periodical = A ['MailingList']; -- error or no, set Periodical to |mailinglist= value because this template is {{cite mailing list}} Periodical_origin = A:ORIGIN('MailingList'); end -- web and news not tested for now because of -- Wikipedia:Administrators%27_noticeboard#Is_there_a_semi-automated_tool_that_could_fix_these_annoying_"Cite_Web"_errors? if not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) then -- 'periodical' templates require periodical parameter -- local p = {['journal'] = 'journal', ['magazine'] = 'magazine', ['news'] = 'newspaper', ['web'] = 'website'}; -- for error message local p = {['journal'] = 'journal', ['magazine'] = 'magazine'}; -- for error message if p[config.CitationClass] then utilities.set_message ('err_missing_periodical', {config.CitationClass, p[config.CitationClass]}); end end local Volume; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) then if not utilities.in_array (Periodical_origin, cfg.citation_no_volume_t) then -- {{citation}} does not render |volume= when these parameters are used Volume = A['Volume']; -- but does for all other 'periodicals' end elseif utilities.is_set (ScriptPeriodical) then if 'script-website' ~= ScriptPeriodical_origin then -- {{citation}} does not render volume for |script-website= Volume = A['Volume']; -- but does for all other 'periodicals' end else Volume = A['Volume']; -- and does for non-'periodical' cites end elseif utilities.in_array (config.CitationClass, cfg.templates_using_volume) then -- render |volume= for cs1 according to the configuration settings Volume = A['Volume']; end extra_text_in_vol_iss_check (Volume, A:ORIGIN ('Volume'), 'v'); local Issue; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) and utilities.in_array (Periodical_origin, cfg.citation_issue_t) then -- {{citation}} may render |issue= when these parameters are used Issue = A['Issue']; end elseif utilities.in_array (config.CitationClass, cfg.templates_using_issue) then -- conference & map books do not support issue; {{citation}} listed here because included in settings table if not (utilities.in_array (config.CitationClass, {'conference', 'map', 'citation'}) and not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical))) then Issue = A['Issue']; end end local ArticleNumber; if utilities.in_array (config.CitationClass, {'journal', 'conference'}) or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then ArticleNumber = A['ArticleNumber']; end extra_text_in_vol_iss_check (Issue, A:ORIGIN ('Issue'), 'i'); Issue = utilities.hyphen_to_dash (Issue); local Page; local Pages; local At; local QuotePage; local QuotePages; if not utilities.in_array (config.CitationClass, cfg.templates_not_using_page) then -- TODO: rewrite to emit ignored parameter error message? Page = A['Page']; Pages = utilities.hyphen_to_dash (A['Pages']); At = A['At']; QuotePage = A['QuotePage']; QuotePages = utilities.hyphen_to_dash (A['QuotePages']); end local NoPP = is_valid_parameter_value (A['NoPP'], A:ORIGIN('NoPP'), cfg.keywords_lists['yes_true_y'], nil); local Mode = mode_set (A['Mode'], A:ORIGIN('Mode')); -- separator character and postscript local sepc, PostScript = set_style (Mode:lower(), A['PostScript'], config.CitationClass); local Quote; Quote, QuotePage, QuotePages, PostScript = quote_make (A['Quote'], A['TransQuote'], A['ScriptQuote'], QuotePage, QuotePages, NoPP, sepc, PostScript); local Edition = A['Edition']; local PublicationPlace = place_check (A['PublicationPlace'], A:ORIGIN('PublicationPlace')); local Place = place_check (A['Place'], A:ORIGIN('Place')); local PublisherName = A['PublisherName']; local PublisherName_origin = A:ORIGIN('PublisherName'); if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then local i; PublisherName, i = utilities.strip_apostrophe_markup (PublisherName); -- strip apostrophe markup so that metadata isn't contaminated; publisher is never italicized if i and (0 < i) then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {PublisherName_origin}); end end if ('document' == config.CitationClass) and not utilities.is_set (PublisherName) then utilities.set_message ('err_missing_publisher', {config.CitationClass, 'publisher'}); end local Newsgroup = A['Newsgroup']; -- TODO: strip apostrophe markup? local Newsgroup_origin = A:ORIGIN('Newsgroup'); if 'newsgroup' == config.CitationClass then if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then -- general use parameter |publisher= not allowed in cite newsgroup utilities.set_message ('err_parameter_ignored', {PublisherName_origin}); end PublisherName = nil; -- ensure that this parameter is unset for the time being; will be used again after COinS end if 'book' == config.CitationClass or 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then local accept; PublisherName, accept = utilities.has_accept_as_written (PublisherName); -- check for and remove accept-as-written markup from |publisher= wrapped if not accept then -- when no accept-as-written markup check_publisher_name (PublisherName); -- emit maint message when |publisher= might be prefixed with publisher's location end end local URL = A['URL']; -- TODO: better way to do this for URL, ChapterURL, and MapURL? local UrlAccess = is_valid_parameter_value (A['UrlAccess'], A:ORIGIN('UrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (URL) and utilities.is_set (UrlAccess) then UrlAccess = nil; utilities.set_message ('err_param_access_requires_param', 'url'); end local ChapterURL = A['ChapterURL']; local ChapterUrlAccess = is_valid_parameter_value (A['ChapterUrlAccess'], A:ORIGIN('ChapterUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (ChapterURL) and utilities.is_set (ChapterUrlAccess) then ChapterUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {A:ORIGIN('ChapterUrlAccess'):gsub ('%-access', '')}); end local MapUrlAccess = is_valid_parameter_value (A['MapUrlAccess'], A:ORIGIN('MapUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (A['MapURL']) and utilities.is_set (MapUrlAccess) then MapUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {'map-url'}); end local this_page = mw.title.getCurrentTitle(); -- also used for COinS and for language local no_tracking_cats = is_valid_parameter_value (A['NoTracking'], A:ORIGIN('NoTracking'), cfg.keywords_lists['yes_true_y'], nil); -- check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories if not utilities.is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page if cfg.uncategorized_namespaces[this_page.namespace] then -- is this page's namespace id one of the uncategorized namespace ids? no_tracking_cats = "true"; -- set no_tracking_cats end for _, v in ipairs (cfg.uncategorized_subpages) do -- cycle through page name patterns if this_page.text:match (v) then -- test page name against each pattern no_tracking_cats = "true"; -- set no_tracking_cats break; -- bail out if one is found end end end -- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it) utilities.select_one (args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'err_redundant_parameters'); -- this is a dummy call simply to get the error message and category local coins_pages; Page, Pages, At, coins_pages = insource_loc_get (Page, A:ORIGIN('Page'), Pages, A:ORIGIN('Pages'), At); if utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- both |publication-place= and |place= (|location=) allowed if different utilities.add_prop_cat ('location-test'); -- add property cat to evaluate how often PublicationPlace and Place are used together if PublicationPlace == Place then Place = ''; -- unset; don't need both if they are the same end elseif not utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- when only |place= (|location=) is set ... PublicationPlace = Place; -- promote |place= (|location=) to |publication-place end if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same local URL_origin = A:ORIGIN('URL'); -- get name of parameter that holds URL local ChapterURL_origin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL -- local ScriptChapter = A['ScriptChapter']; -- local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); local Format = A['Format']; local ChapterFormat = A['ChapterFormat']; local TransChapter = A['TransChapter']; local TransChapter_origin = A:ORIGIN ('TransChapter'); local TransTitle = A['TransTitle']; local ScriptTitle = A['ScriptTitle']; --[[ Parameter remapping for cite encyclopedia: When the citation has these parameters: |encyclopedia= and |title= then map |title= to |article= and |encyclopedia= to |title= for rendering |encyclopedia= and |article= then map |encyclopedia= to |title= for rendering |trans-title= maps to |trans-chapter= when |title= is re-mapped |url= maps to |chapter-url= when |title= is remapped All other combinations of |encyclopedia=, |title=, and |article= are not modified ]] local Encyclopedia = A['Encyclopedia']; -- used as a flag by this module and by ~/COinS local ScriptEncyclopedia = A['ScriptEncyclopedia']; local TransEncyclopedia = A['TransEncyclopedia']; if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then -- emit error message when Encyclopedia set but template is other than {{cite encyclopedia}} or {{citation}} if 'encyclopaedia' ~= config.CitationClass and 'citation' ~= config.CitationClass then if utilities.is_set (Encyclopedia) then utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('Encyclopedia')}); else utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('ScriptEncyclopedia')}); end Encyclopedia = nil; -- unset these because not supported by this template ScriptEncyclopedia = nil; TransEncyclopedia = nil; end elseif utilities.is_set (TransEncyclopedia) then utilities.set_message ('err_trans_missing_title', {'encyclopedia'}); end if ('encyclopaedia' == config.CitationClass) or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Periodical) and utilities.is_set (Encyclopedia) then -- when both parameters set emit an error message; {{citation}} only; Periodical not allowed in {{cite encyclopedia}} utilities.set_message ('err_periodical_ignored', {Periodical_origin}); end if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then Periodical = Encyclopedia; -- error or no, set Periodical to Encyclopedia for rendering; {{citation}} could (not legitimately) have both; use Encyclopedia Periodical_origin = A:ORIGIN ('Encyclopedia'); ScriptPeriodical = ScriptEncyclopedia; ScriptPeriodical_origin = A:ORIGIN ('ScriptEncyclopedia'); if utilities.is_set (Title) or utilities.is_set (ScriptTitle) then if not utilities.is_set (Chapter) then Chapter = Title; -- |encyclopedia= and |title= are set so map |title= params to |article= params for rendering ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle') TransChapter = TransTitle; ChapterURL = URL; ChapterURL_origin = URL_origin; ChapterUrlAccess = UrlAccess; ChapterFormat = Format; if not utilities.is_set (ChapterURL) and utilities.is_set (TitleLink) then Chapter = utilities.make_wikilink (TitleLink, Chapter); end Title = Periodical; -- now map |encyclopedia= params to |title= params for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; URL = ''; Format = ''; TitleLink = ''; end elseif utilities.is_set (Chapter) or utilities.is_set (ScriptChapter) then -- |title= not set Title = Periodical; -- |encyclopedia= set and |article= set so map |encyclopedia= to |title= for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; end end end -- special case for cite techreport. local ID = A['ID']; if (config.CitationClass == "techreport") then -- special case for cite techreport if utilities.is_set (A['Number']) then -- cite techreport uses 'number', which other citations alias to 'issue' if not utilities.is_set (ID) then -- can we use ID for the "number"? ID = A['Number']; -- yes, use it else -- ID has a value so emit error message utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'id') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'number')}); end end end -- Account for the oddity that is {{cite conference}}, before generation of COinS data. local ChapterLink -- = A['ChapterLink']; -- deprecated as a parameter but still used internally by cite episode local Conference = A['Conference']; local BookTitle = A['BookTitle']; local TransTitle_origin = A:ORIGIN ('TransTitle'); if 'conference' == config.CitationClass then if utilities.is_set (BookTitle) then Chapter = Title; Chapter_origin = 'title'; -- ChapterLink = TitleLink; -- |chapter-link= is deprecated ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; URL_origin = ''; ChapterFormat = Format; TransChapter = TransTitle; TransChapter_origin = TransTitle_origin; Title = BookTitle; Format = ''; -- TitleLink = ''; TransTitle = ''; URL = ''; end elseif 'speech' ~= config.CitationClass then Conference = ''; -- not cite conference or cite speech so make sure this is empty string end local cs2_lower = function (text) -- if mode is cs2, use lower case if (sepc ~= '.') then return text:lower(); end return text; end local use_lowercase = ( sepc == ',' ); -- controls capitalization of certain static text -- cite map oddities local Cartography = ""; local Scale = ""; local Sheet = A['Sheet'] or ''; local Sheets = A['Sheets'] or ''; if config.CitationClass == "map" then if utilities.is_set (Chapter) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'map') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', Chapter_origin)}); -- add error message end Chapter = A['Map']; Chapter_origin = A:ORIGIN('Map'); -- for now, ignore linter warning ChapterURL = A['MapURL']; ChapterURL_origin = A:ORIGIN('MapURL'); TransChapter = A['TransMap']; ScriptChapter = A['ScriptMap'] ScriptChapter_origin = A:ORIGIN('ScriptMap') ChapterUrlAccess = MapUrlAccess; ChapterFormat = A['MapFormat']; Cartography = A['Cartography']; if utilities.is_set ( Cartography ) then Cartography = sepc .. " " .. wrap_msg ('cartography', Cartography, use_lowercase); end Scale = A['Scale']; if utilities.is_set ( Scale ) then Scale = sepc .. " " .. Scale; end end -- Account for the oddities that are {{cite episode}} and {{cite serial}}, before generation of COinS data. local Series = A['Series']; if 'episode' == config.CitationClass or 'serial' == config.CitationClass then local SeriesLink = A['SeriesLink']; SeriesLink = link_title_ok (SeriesLink, A:ORIGIN ('SeriesLink'), Series, 'series'); -- check for wiki-markup in |series-link= or wiki-markup in |series= when |series-link= is set local Network = A['Network']; local Station = A['Station']; local s, n = {}, {}; -- do common parameters first if utilities.is_set (Network) then table.insert(n, Network); end if utilities.is_set (Station) then table.insert(n, Station); end ID = table.concat(n, sepc .. ' '); if 'episode' == config.CitationClass then -- handle the oddities that are strictly {{cite episode}} local Season = A['Season']; local SeriesNumber = A['SeriesNumber']; if utilities.is_set (Season) and utilities.is_set (SeriesNumber) then -- these are mutually exclusive so if both are set TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'season') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'seriesno')}); -- add error message SeriesNumber = ''; -- unset; prefer |season= over |seriesno= end -- assemble a table of parts concatenated later into Series if utilities.is_set (Season) then table.insert(s, wrap_msg ('season', Season, use_lowercase)); end if utilities.is_set (SeriesNumber) then table.insert(s, wrap_msg ('seriesnum', SeriesNumber, use_lowercase)); end if utilities.is_set (Issue) then table.insert(s, wrap_msg ('episode', Issue, use_lowercase)); end Issue = ''; -- unset because this is not a unique parameter Chapter = Title; -- promote title parameters to chapter ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle'); ChapterLink = TitleLink; -- alias |episode-link= TransChapter = TransTitle; ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; ChapterFormat = Format; Title = Series; -- promote series to title TitleLink = SeriesLink; Series = table.concat(s, sepc .. ' '); -- this is concatenation of season, seriesno, episode number if utilities.is_set (ChapterLink) and not utilities.is_set (ChapterURL) then -- link but not URL Chapter = utilities.make_wikilink (ChapterLink, Chapter); elseif utilities.is_set (ChapterLink) and utilities.is_set (ChapterURL) then -- if both are set, URL links episode; Series = utilities.make_wikilink (ChapterLink, Series); end URL = ''; -- unset TransTitle = ''; ScriptTitle = ''; Format = ''; else -- now oddities that are cite serial Issue = ''; -- unset because this parameter no longer supported by the citation/core version of cite serial Chapter = A['Episode']; -- TODO: make |episode= available to cite episode someday? if utilities.is_set (Series) and utilities.is_set (SeriesLink) then Series = utilities.make_wikilink (SeriesLink, Series); end Series = utilities.wrap_style ('italic-title', Series); -- series is italicized end end -- end of {{cite episode}} stuff -- handle type parameter for those CS1 citations that have default values local TitleType = A['TitleType']; local Degree = A['Degree']; if utilities.in_array (config.CitationClass, {'AV-media-notes', 'document', 'interview', 'mailinglist', 'map', 'podcast', 'pressrelease', 'report', 'speech', 'techreport', 'thesis'}) then TitleType = set_titletype (config.CitationClass, TitleType); if utilities.is_set (Degree) and "Thesis" == TitleType then -- special case for cite thesis TitleType = Degree .. ' ' .. cfg.title_types ['thesis']:lower(); end end if utilities.is_set (TitleType) then -- if type parameter is specified TitleType = utilities.substitute ( cfg.messages['type'], TitleType); -- display it in parentheses -- TODO: Hack on TitleType to fix bunched parentheses problem end -- legacy: promote PublicationDate to Date if neither Date nor Year are set. local Date = A['Date']; local Date_origin; -- to hold the name of parameter promoted to Date; required for date error messaging local PublicationDate = A['PublicationDate']; local Year = A['Year']; if utilities.is_set (Year) then validation.year_check (Year); -- returns nothing; emits maint message when |year= doesn't hold a 'year' value end if not utilities.is_set (Date) then Date = Year; -- promote Year to Date Year = nil; -- make nil so Year as empty string isn't used for CITEREF if not utilities.is_set (Date) and utilities.is_set (PublicationDate) then -- use PublicationDate when |date= and |year= are not set Date = PublicationDate; -- promote PublicationDate to Date PublicationDate = ''; -- unset, no longer needed Date_origin = A:ORIGIN('PublicationDate'); -- save the name of the promoted parameter else Date_origin = A:ORIGIN('Year'); -- save the name of the promoted parameter end else Date_origin = A:ORIGIN('Date'); -- not a promotion; name required for error messaging end if PublicationDate == Date then PublicationDate = ''; end -- if PublicationDate is same as Date, don't display in rendered citation --[[ Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates. This must be done before we do COinS because here is where we get the date used in the metadata. Date validation supporting code is in Module:Citation/CS1/Date_validation ]] local DF = is_valid_parameter_value (A['DF'], A:ORIGIN('DF'), cfg.keywords_lists['df'], ''); if not utilities.is_set (DF) then DF = cfg.global_df; -- local |df= if present overrides global df set by {{use xxx date}} template end local ArchiveURL; local ArchiveDate; local ArchiveFormat = A['ArchiveFormat']; local archive_url_timestamp; -- timestamp from wayback machine url ArchiveURL, ArchiveDate, archive_url_timestamp = archive_url_check (A['ArchiveURL'], A['ArchiveDate']) ArchiveFormat = style_format (ArchiveFormat, ArchiveURL, 'archive-format', 'archive-url'); ArchiveURL, ArchiveDate = is_unique_archive_url (ArchiveURL, URL, ChapterURL, A:ORIGIN('ArchiveURL'), ArchiveDate); -- add error message when URL or ChapterURL == ArchiveURL local AccessDate = A['AccessDate']; local COinS_date = {}; -- holds date info extracted from |date= for the COinS metadata by Module:Date verification local DoiBroken = A['DoiBroken']; local Embargo = A['Embargo']; local anchor_year; -- used in the CITEREF identifier do -- create defined block to contain local variables date_parameters_list, mismatch local date_parameters_list = { -- AirDate has been promoted to Date so not necessary to check it ['access-date'] = {val = AccessDate, name = A:ORIGIN ('AccessDate')}, ['archive-date'] = {val = ArchiveDate, name = A:ORIGIN ('ArchiveDate')}, ['date'] = {val = Date, name = Date_origin}, ['doi-broken-date'] = {val = DoiBroken, name = A:ORIGIN ('DoiBroken')}, ['pmc-embargo-date'] = {val = Embargo, name = A:ORIGIN ('Embargo')}, ['publication-date'] = {val = PublicationDate, name = A:ORIGIN ('PublicationDate')}, ['year'] = {val = Year, name = A:ORIGIN ('Year')}, }; local error_list = {}; anchor_year, Embargo = validation.dates(date_parameters_list, COinS_date, error_list); if utilities.is_set (Year) and utilities.is_set (Date) then -- both |date= and |year= not normally needed; validation.year_date_check (Year, A:ORIGIN ('Year'), Date, A:ORIGIN ('Date'), error_list); end if 0 == #error_list then -- error free dates only; 0 when error_list is empty local modified = false; -- flag if utilities.is_set (DF) then -- if we need to reformat dates modified = validation.reformat_dates (date_parameters_list, DF); -- reformat to DF format, use long month names if appropriate end if true == validation.date_hyphen_to_dash (date_parameters_list) then -- convert hyphens to dashes where appropriate modified = true; utilities.set_message ('maint_date_format'); -- hyphens were converted so add maint category end -- for those wikis that can and want to have English date names translated to the local language; not supported at en.wiki if cfg.date_name_auto_xlate_enable and validation.date_name_xlate (date_parameters_list, cfg.date_digit_auto_xlate_enable ) then utilities.set_message ('maint_date_auto_xlated'); -- add maint cat modified = true; end if modified then -- if the date_parameters_list values were modified AccessDate = date_parameters_list['access-date'].val; -- overwrite date holding parameters with modified values ArchiveDate = date_parameters_list['archive-date'].val; Date = date_parameters_list['date'].val; DoiBroken = date_parameters_list['doi-broken-date'].val; PublicationDate = date_parameters_list['publication-date'].val; end if archive_url_timestamp and utilities.is_set (ArchiveDate) then validation.archive_date_check (ArchiveDate, archive_url_timestamp, DF); -- does YYYYMMDD in archive_url_timestamp match date in ArchiveDate end else utilities.set_message ('err_bad_date', {utilities.make_sep_list (#error_list, error_list)}); -- add this error message end end -- end of do if utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) or -- {{cite book}}, {{cite encyclopedia}}; TODO: {{cite conference}} and others? ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) or -- {{citation}} as an encylopedia citation ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then -- {{citation}} as a book citation if utilities.is_set (PublicationPlace) then if not utilities.is_set (PublisherName) then local date = COinS_date.rftdate and tonumber (COinS_date.rftdate:match ('%d%d%d%d')); -- get year portion of COinS date (because in Arabic numerals); convert string to number if date and (1850 <= date) then -- location has no publisher; if date is 1850 or later utilities.set_message ('maint_location_no_publisher'); -- add maint cat end else -- PublisherName has a value if cfg.keywords_xlate['none'] == PublisherName then -- if that value is 'none' (only for book and encyclopedia citations) PublisherName = ''; -- unset end end end end local ID_list_t; -- sequence table of rendered identifiers local ID_list_coins_t; -- table of identifiers and their values from args; key is same as cfg.id_handlers's key local Class = A['Class']; -- arxiv class identifier local ID_support = { {A['ASINTLD'], 'ASIN', 'err_asintld_missing_asin', A:ORIGIN ('ASINTLD')}, {DoiBroken, 'DOI', 'err_doibroken_missing_doi', A:ORIGIN ('DoiBroken')}, {Embargo, 'PMC', 'err_embargo_missing_pmc', A:ORIGIN ('Embargo')}, } ID_list_t, ID_list_coins_t = identifiers.identifier_lists_get (args, { DoiBroken = DoiBroken, -- for |doi= ASINTLD = A['ASINTLD'], -- for |asin= Embargo = Embargo, -- for |pmc= Class = Class, -- for |arxiv= CitationClass = config.CitationClass, -- for |arxiv= Year=anchor_year, -- for |isbn= }, ID_support); for _, id in ipairs (ID_list_t) do -- search through the ID_list_t sequence looking for an ISBN identifier string if id:find ('ISBN', 3, true) then -- plain find, start at index 3 ([[ISBN) if 'citation' == config.CitationClass then -- catch ve/citoid malformed book cites in {{citation}} templates if utilities.is_set (Periodical) then -- when a |work= alias is set utilities.set_message ('maint_work_isbn'); -- add maint cat break; -- and abandon end elseif ({['journal'] = true, ['magazine'] = true, ['news'] = true, ['web'] = true})[config.CitationClass] then utilities.set_message ('maint_periodical_has_isbn'); -- add maint cat break; -- and abandon end end end -- if 'citation' == config.CitationClass then -- catch ve/citoid malformed book cites in {{citation}} templates -- for _, id in ipairs (ID_list_t) do -- search through the ID_list_t sequence looking for an ISBN identifier string -- if id:find ('ISBN', 3, true) then -- plain find, start at index 3 ([[ISBN) -- if utilities.is_set (Periodical) then -- when a |work= alias is set -- utilities.set_message ('maint_work_isbn'); -- add maint cat -- end -- end -- end -- end -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, {{cite ssrn}}, before generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv=, |citeseerx=, |medrxiv=, |ssrn= required for their templates if not (args[cfg.id_handlers[config.CitationClass:upper()].parameters[1]] or -- can't use ID_list_coins_t k/v table here because invalid parameters omitted args[cfg.id_handlers[config.CitationClass:upper()].parameters[2]]) then -- which causes unexpected parameter missing error message utilities.set_message ('err_' .. config.CitationClass .. '_missing'); -- add error message end Periodical = ({['arxiv'] = 'arXiv', ['biorxiv'] = 'bioRxiv', ['citeseerx'] = 'CiteSeerX', ['medrxiv'] = 'medRxiv', ['ssrn'] = 'Social Science Research Network'})[config.CitationClass]; end -- Link the title of the work if no |url= was provided, but we have a |pmc= or a |doi= with |doi-access=free if config.CitationClass == "journal" and not utilities.is_set (URL) and not utilities.is_set (TitleLink) and not utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) then -- TODO: remove 'none' once existing citations have been switched to 'off', so 'none' can be used as token for "no title" instead if 'none' ~= cfg.keywords_xlate[auto_select] then -- if auto-linking not disabled if identifiers.auto_link_urls[auto_select] then -- manual selection URL = identifiers.auto_link_urls[auto_select]; -- set URL to be the same as identifier's external link URL_origin = cfg.id_handlers[auto_select:upper()].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['pmc'] then -- auto-select PMC URL = identifiers.auto_link_urls['pmc']; -- set URL to be the same as the PMC external link if not embargoed URL_origin = cfg.id_handlers['PMC'].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['doi'] then -- auto-select DOI URL = identifiers.auto_link_urls['doi']; URL_origin = cfg.id_handlers['DOI'].parameters[1]; end end if utilities.is_set (URL) then -- set when using an identifier-created URL if utilities.is_set (AccessDate) then -- |access-date= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_accessdate_missing_url'); -- add an error message AccessDate = ''; -- unset end if utilities.is_set (ArchiveURL) then -- |archive-url= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_archive_missing_url'); -- add an error message ArchiveURL = ''; -- unset end end end -- At this point fields may be nil if they weren't specified in the template use. We can use that fact. -- Test if citation has no title if not utilities.is_set (Title) and not utilities.is_set (TransTitle) and not utilities.is_set (ScriptTitle) then -- has special case for cite episode utilities.set_message ('err_citation_missing_title', {'episode' == config.CitationClass and 'series' or 'title'}); end if utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) and utilities.in_array (config.CitationClass, {'journal', 'citation'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and ('journal' == Periodical_origin or 'script-journal' == ScriptPeriodical_origin) then -- special case for journal cites Title = ''; -- set title to empty string utilities.set_message ('maint_untitled'); -- add maint cat end if 'journal' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then if is_page_art_num (((utilities.is_set (Page) and Page) or (utilities.is_set (Pages) and Pages)) or nil, ID_list_coins_t['DOI']) then -- does |page(s)= look like it holds an article number utilities.set_message ('maint_page_art_num'); -- add maint cat end end -- COinS metadata (see <http://ocoins.info/>) for automated parsing of citation information. -- handle the oddity that is cite encyclopedia and {{citation |encyclopedia=something}}. Here we presume that -- when Periodical, Title, and Chapter are all set, then Periodical is the book (encyclopedia) title, Title -- is the article title, and Chapter is a section within the article. So, we remap local coins_chapter = Chapter; -- default assuming that remapping not required local coins_title = Title; -- et tu if 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Chapter) and utilities.is_set (Title) and utilities.is_set (Periodical) then -- if all are used then coins_chapter = Title; -- remap coins_title = Periodical; end end local coins_author = a; -- default for coins rft.au if 0 < #c then -- but if contributor list coins_author = c; -- use that instead end -- this is the function call to COinS() local OCinSoutput = metadata.COinS({ ['Periodical'] = utilities.strip_apostrophe_markup (Periodical), -- no markup in the metadata ['Encyclopedia'] = Encyclopedia, -- just a flag; content ignored by ~/COinS ['Chapter'] = metadata.make_coins_title (coins_chapter, ScriptChapter), -- Chapter and ScriptChapter stripped of bold / italic / accept-as-written markup ['Degree'] = Degree; -- cite thesis only ['Title'] = metadata.make_coins_title (coins_title, ScriptTitle), -- Title and ScriptTitle stripped of bold / italic / accept-as-written markup ['PublicationPlace'] = PublicationPlace, ['Date'] = COinS_date.rftdate, -- COinS_date.* has correctly formatted date values if Date is valid; ['Season'] = COinS_date.rftssn, ['Quarter'] = COinS_date.rftquarter, ['Chron'] = COinS_date.rftchron, ['Series'] = Series, ['Volume'] = Volume, ['Issue'] = Issue, ['ArticleNumber'] = ArticleNumber, ['Pages'] = coins_pages or metadata.get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At, QuotePage, QuotePages}, 7)), -- pages stripped of external links ['Edition'] = Edition, ['PublisherName'] = PublisherName or Newsgroup, -- any apostrophe markup already removed from PublisherName ['URL'] = first_set ({ChapterURL, URL}, 2), ['Authors'] = coins_author, ['ID_list'] = ID_list_coins_t, ['RawPage'] = this_page.prefixedText, }, config.CitationClass); -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, and {{cite ssrn}} AFTER generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- we have set rft.jtitle in COinS to arXiv, bioRxiv, CiteSeerX, medRxiv, or ssrn now unset so it isn't displayed Periodical = ''; -- periodical not allowed in these templates; if article has been published, use cite journal end -- special case for cite newsgroup. Do this after COinS because we are modifying Publishername to include some static text if 'newsgroup' == config.CitationClass and utilities.is_set (Newsgroup) then PublisherName = utilities.substitute (cfg.messages['newsgroup'], external_link( 'news:' .. Newsgroup, Newsgroup, Newsgroup_origin, nil )); end local Editors; local EditorCount; -- used only for choosing {ed.) or (eds.) annotation at end of editor name-list local Contributors; -- assembled contributors name list local contributor_etal = nil; -- must be intentionally initialized local Translators; -- assembled translators name list local translator_etal = nil; -- must be intentionally initialized local t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= local Interviewers; local interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters local interviewer_etal = nil; -- must be intentionally initialized -- Now perform various field substitutions. -- We also add leading spaces and surrounding markup and punctuation to the -- various parts of the citation, but only when they are non-nil. do local last_first_list; local control = { format = NameListStyle, -- empty string, '&', 'amp', 'and', or 'vanc' maximum = nil, -- as if display-authors or display-editors not set mode = Mode }; do -- do editor name list first because the now unsupported coauthors used to modify control table local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayEditors'], A['DisplayEditors'], A:ORIGIN ('DisplayEditors'), #e); control.maximum, editor_etal = get_display_names (display_names, #e, editor_etal, param); Editors, EditorCount = list_people (control, e, editor_etal); if 1 == EditorCount and (true == editor_etal or 1 < #e) then -- only one editor displayed but includes etal then EditorCount = 2; -- spoof to display (eds.) annotation end end do -- now do interviewers local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayInterviewers'], A['DisplayInterviewers'], A:ORIGIN ('DisplayInterviewers'), #interviewers_list); control.maximum, interviewer_etal = get_display_names (display_names, #interviewers_list, interviewer_etal, param); Interviewers = list_people (control, interviewers_list, interviewer_etal); end do -- now do translators local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayTranslators'], A['DisplayTranslators'], A:ORIGIN ('DisplayTranslators'), #t); control.maximum, translator_etal = get_display_names (display_names, #t, translator_etal, param); Translators = list_people (control, t, translator_etal); end do -- now do contributors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayContributors'], A['DisplayContributors'], A:ORIGIN ('DisplayContributors'), #c); control.maximum, contributor_etal = get_display_names (display_names, #c, contributor_etal, param); Contributors = list_people (control, c, contributor_etal); end do -- now do authors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayAuthors'], A['DisplayAuthors'], A:ORIGIN ('DisplayAuthors'), #a, author_etal); control.maximum, author_etal = get_display_names (display_names, #a, author_etal, param); last_first_list = list_people (control, a, author_etal); if utilities.is_set (Authors) then Authors, author_etal = name_has_etal (Authors, author_etal, false, 'authors'); -- find and remove variations on et al. if author_etal then Authors = Authors .. ' ' .. cfg.messages['et al']; -- add et al. to authors parameter end else Authors = last_first_list; -- either an author name list or an empty string end end -- end of do if utilities.is_set (Authors) and utilities.is_set (Collaboration) then Authors = utilities.substitute (cfg.messages['collaboration'], {Authors, Collaboration}); -- add collaboration after et al. end end local ConferenceFormat = A['ConferenceFormat']; local ConferenceURL = A['ConferenceURL']; ConferenceFormat = style_format (ConferenceFormat, ConferenceURL, 'conference-format', 'conference-url'); Format = style_format (Format, URL, 'format', 'url'); -- special case for chapter format so no error message or cat when chapter not supported if not (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia))) then ChapterFormat = style_format (ChapterFormat, ChapterURL, 'chapter-format', 'chapter-url'); end if not utilities.is_set (URL) then if utilities.in_array (config.CitationClass, {"web", "podcast", "mailinglist"}) or -- |url= required for {{cite web}}, {{cite podcast}}, and {{cite mailing list}} ('citation' == config.CitationClass and ('website' == Periodical_origin or 'script-website' == ScriptPeriodical_origin)) then -- and required for {{citation}} with |website= or |script-website= if not url_was_archive_today then -- is <URL> empty/missing because it was a deprecated archive.today url utilities.set_message ('err_cite_web_url'); -- no; emit an error message for an empty/ missing |url= end end -- do we have |accessdate= without either |url= or |chapter-url=? if utilities.is_set (AccessDate) and not utilities.is_set (ChapterURL) then -- ChapterURL may be set when URL is not set; utilities.set_message ('err_accessdate_missing_url'); AccessDate = ''; end end local UrlStatus = is_valid_parameter_value (A['UrlStatus'], A:ORIGIN('UrlStatus'), cfg.keywords_lists['url-status'], ''); local OriginalURL local OriginalURL_origin local OriginalFormat local OriginalAccess; UrlStatus = UrlStatus:lower(); -- used later when assembling archived text if utilities.is_set ( ArchiveURL ) then if utilities.is_set (ChapterURL) then -- if chapter-url= is set apply archive url to it OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text OriginalURL_origin = ChapterURL_origin; -- name of |chapter-url= parameter for error messages OriginalFormat = ChapterFormat; -- and original |chapter-format= if 'live' ~= UrlStatus then ChapterURL = ArchiveURL -- swap-in the archive's URL ChapterURL_origin = A:ORIGIN('ArchiveURL') -- name of |archive-url= parameter for error messages ChapterFormat = ArchiveFormat or ''; -- swap in archive's format ChapterUrlAccess = nil; -- restricted access levels do not make sense for archived URLs end elseif utilities.is_set (URL) then OriginalURL = URL; -- save copy of original source URL OriginalURL_origin = URL_origin; -- name of URL parameter for error messages OriginalFormat = Format; -- and original |format= OriginalAccess = UrlAccess; if 'live' ~= UrlStatus then -- if URL set then |archive-url= applies to it URL = ArchiveURL -- swap-in the archive's URL URL_origin = A:ORIGIN('ArchiveURL') -- name of archive URL parameter for error messages Format = ArchiveFormat or ''; -- swap in archive's format UrlAccess = nil; -- restricted access levels do not make sense for archived URLs end end elseif utilities.is_set (UrlStatus) then -- if |url-status= is set when |archive-url= is not set utilities.set_message ('maint_url_status'); -- add maint cat end if utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or -- if any of the 'periodical' cites except encyclopedia ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) then local chap_param; if utilities.is_set (Chapter) then -- get a parameter name from one of these chapter related meta-parameters chap_param = A:ORIGIN ('Chapter') elseif utilities.is_set (TransChapter) then chap_param = A:ORIGIN ('TransChapter') elseif utilities.is_set (ChapterURL) then chap_param = A:ORIGIN ('ChapterURL') elseif utilities.is_set (ScriptChapter) then chap_param = ScriptChapter_origin; else utilities.is_set (ChapterFormat) chap_param = A:ORIGIN ('ChapterFormat') end if utilities.is_set (chap_param) then -- if we found one utilities.set_message ('err_chapter_ignored', {chap_param}); -- add error message Chapter = ''; -- and set them to empty string to be safe with concatenation TransChapter = ''; -- for now, ignore linter warnings ChapterURL = ''; ScriptChapter = ''; ChapterFormat = ''; end else -- otherwise, format chapter / article title local no_quotes = false; -- default assume that we will be quoting the chapter parameter value if utilities.is_set (Contribution) and 0 < #c then -- if this is a contribution with contributor(s) if utilities.in_array (Contribution:lower(), cfg.keywords_lists.contribution) then -- and a generic contribution title no_quotes = true; -- then render it unquoted end end Chapter = format_chapter_title (ScriptChapter, ScriptChapter_origin, Chapter, TransChapter, TransChapter_origin, ChapterURL, ChapterURL_origin, no_quotes, ChapterUrlAccess); -- Contribution is also in Chapter if utilities.is_set (Chapter) then Chapter = Chapter .. ChapterFormat ; if 'map' == config.CitationClass and utilities.is_set (TitleType) then Chapter = Chapter .. ' ' .. TitleType; -- map annotation here; not after title end Chapter = Chapter .. sepc .. ' '; elseif utilities.is_set (ChapterFormat) then -- |chapter= not set but |chapter-format= is so ... Chapter = ChapterFormat .. sepc .. ' '; -- ... ChapterFormat has error message, we want to see it end end -- Format main title local plain_title = false; local accept_title; Title, accept_title = utilities.has_accept_as_written (Title, true); -- remove accept-this-as-written markup when it wraps all of <Title> if accept_title and ('' == Title) then -- only support forced empty for now "(())" Title = cfg.messages['notitle']; -- replace by predefined "No title" message -- TODO: utilities.set_message ( 'err_redundant_parameters', ...); -- issue proper error message instead of muting ScriptTitle = ''; -- just mute for now TransTitle = ''; -- just mute for now plain_title = true; -- suppress text decoration for descriptive title utilities.set_message ('maint_untitled'); -- add maint cat end if not accept_title then -- <Title> not wrapped in accept-as-written markup if '...' == Title:sub (-3) then -- if ellipsis is the last three characters of |title= Title = Title:gsub ('(%.%.%.)%.+$', '%1'); -- limit the number of dots to three elseif not mw.ustring.find (Title, '%.%s*%a%.$') and -- end of title is not a 'dot-(optional space-)letter-dot' initialism ... not mw.ustring.find (Title, '%s+%a%.$') then -- ...and not a 'space-letter-dot' initial (''Allium canadense'' L.) Title = mw.ustring.gsub(Title, '%' .. sepc .. '$', ''); -- remove any trailing separator character; sepc and ms.ustring() here for languages that use multibyte separator characters end if utilities.is_set (ArchiveURL) and is_archived_copy (Title) then utilities.set_message ('maint_archived_copy'); -- add maintenance category before we modify the content of Title end if is_generic ('generic_titles', Title) then utilities.set_message ('err_generic_title'); -- set an error message end end if (not plain_title) and (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'document', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) or ('map' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)))) then -- special case for cite map when the map is in a periodical treat as an article Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from module provided quote marks Title = utilities.wrap_style ('quoted-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); elseif plain_title or ('report' == config.CitationClass) then -- no styling for cite report and descriptive titles (otherwise same as above) Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); -- for cite report, use this form for trans-title else Title = utilities.wrap_style ('italic-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-italic-title', TransTitle); end if utilities.is_set (TransTitle) then if utilities.is_set (Title) then TransTitle = " " .. TransTitle; else utilities.set_message ('err_trans_missing_title', {'title'}); end end if utilities.is_set (Title) then -- TODO: is this the right place to be making Wikisource URLs? if utilities.is_set (TitleLink) and utilities.is_set (URL) then utilities.set_message ('err_wikilink_in_url'); -- set an error message because we can't have both TitleLink = ''; -- unset end if not utilities.is_set (TitleLink) and utilities.is_set (URL) then Title = external_link (URL, Title, URL_origin, UrlAccess) .. TransTitle .. Format; URL = ''; -- unset these because no longer needed Format = ''; -- for now, ignore linter warning elseif utilities.is_set (TitleLink) and not utilities.is_set (URL) then local ws_url; ws_url = wikisource_url_make (TitleLink); -- ignore ws_label return; not used here if ws_url then Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title-link'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], TitleLink, Title}); Title = Title .. TransTitle; else Title = utilities.make_wikilink (TitleLink, Title) .. TransTitle; end else local ws_url, ws_label, L; -- Title has italic or quote markup by the time we get here which causes is_wikilink() to return 0 (not a wikilink) ws_url, ws_label, L = wikisource_url_make (Title:gsub('^[\'"]*(.-)[\'"]*$', '%1')); -- make ws URL from |title= interwiki link (strip italic or quote markup); link portion L becomes tooltip label if ws_url then Title = Title:gsub ('%b[]', ws_label); -- replace interwiki link with ws_label to retain markup Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, Title}); Title = Title .. TransTitle; else Title = Title .. TransTitle; end end else Title = TransTitle; end if utilities.is_set (Place) then Place = " " .. wrap_msg ('written', Place, use_lowercase) .. sepc .. " "; end local ConferenceURL_origin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL if utilities.is_set (Conference) then if utilities.is_set (ConferenceURL) then Conference = external_link( ConferenceURL, Conference, ConferenceURL_origin, nil ); end Conference = sepc .. " " .. Conference .. ConferenceFormat; elseif utilities.is_set (ConferenceURL) then Conference = sepc .. " " .. external_link( ConferenceURL, nil, ConferenceURL_origin, nil ); end local Position = ''; if not utilities.is_set (Position) then local Minutes = A['Minutes']; local Time = A['Time']; if utilities.is_set (Minutes) then if utilities.is_set (Time) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'minutes') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'time')}); end Position = utilities.substitute (cfg.messages.minutes, Minutes); else if utilities.is_set (Time) then local TimeCaption = A['TimeCaption'] if not utilities.is_set (TimeCaption) then TimeCaption = cs2_lower(cfg.messages['event']); end Position = " " .. TimeCaption .. " " .. Time; end end else Position = " " .. Position; At = ''; end Page, Pages, Sheet, Sheets = format_pages_sheets (Page, Pages, Sheet, Sheets, config.CitationClass, Periodical_origin, sepc, NoPP, use_lowercase); At = utilities.is_set (At) and (sepc .. " " .. At) or ""; Position = utilities.is_set (Position) and (sepc .. " " .. Position) or ""; if config.CitationClass == 'map' then local Sections = A['Sections']; -- Section (singular) is an alias of Chapter so set earlier local Inset = A['Inset']; if utilities.is_set ( Inset ) then Inset = sepc .. " " .. wrap_msg ('inset', Inset, use_lowercase); end if utilities.is_set ( Sections ) then Section = sepc .. " " .. wrap_msg ('sections', Sections, use_lowercase); elseif utilities.is_set ( Section ) then Section = sepc .. " " .. wrap_msg ('section', Section, use_lowercase); end At = At .. Inset .. Section; end local Others = A['Others']; if utilities.is_set (Others) and 0 == #a and 0 == #e then -- add maint cat when |others= has value and used without |author=, |editor= if config.CitationClass == "AV-media-notes" or config.CitationClass == "audio-visual" then -- special maint for AV/M which has a lot of 'false' positives right now utilities.set_message ('maint_others_avm') else utilities.set_message ('maint_others'); end end Others = utilities.is_set (Others) and (sepc .. " " .. Others) or ""; if utilities.is_set (Translators) then Others = safe_join ({sepc .. ' ', wrap_msg ('translated', Translators, use_lowercase), Others}, sepc); end if utilities.is_set (Interviewers) then Others = safe_join ({sepc .. ' ', wrap_msg ('interview', Interviewers, use_lowercase), Others}, sepc); end local TitleNote = A['TitleNote']; TitleNote = utilities.is_set (TitleNote) and (sepc .. " " .. TitleNote) or ""; if utilities.is_set (Edition) then if Edition:match ('%f[%a][Ee]d%n?%.?$') or Edition:match ('%f[%a][Ee]dition$') then -- Ed, ed, Ed., ed., Edn, edn, Edn., edn. utilities.set_message ('err_extra_text_edition'); -- add error message end Edition = " " .. wrap_msg ('edition', Edition); else Edition = ''; end Series = utilities.is_set (Series) and wrap_msg ('series', {sepc, Series}) or ""; -- not the same as SeriesNum local Agency = A['Agency'] or ''; -- |agency= is supported by {{cite magazine}}, {{cite news}}, {{cite press release}}, {{cite web}}, and certain {{citation}} templates if utilities.is_set (Agency) then -- this testing done here because {{citation}} supports 'news' citations if utilities.in_array (config.CitationClass, {'magazine', 'news', 'pressrelease', 'web'}) or ('citation' == config.CitationClass and utilities.in_array (Periodical_origin, {"magazine", "newspaper", "work"})) then Agency = wrap_msg ('agency', {sepc, Agency}); -- format for rendering else Agency = ''; -- unset; not supported utilities.set_message ('err_parameter_ignored', {'agency'}); -- add error message end end Volume = format_volume_issue (Volume, Issue, ArticleNumber, config.CitationClass, Periodical_origin, sepc, use_lowercase); if utilities.is_set (AccessDate) then local retrv_text = " " .. cfg.messages['retrieved']; AccessDate = nowrap_date (AccessDate); -- wrap in nowrap span if date in appropriate format retrv_text = cs2_lower(retrv_text); -- if mode is cs2, lower case AccessDate = utilities.substitute (retrv_text, AccessDate); -- add retrieved text AccessDate = utilities.substitute (cfg.presentation['accessdate'], {sepc, AccessDate}); -- allow editors to hide accessdates end if utilities.is_set (ID) then ID = sepc .. " " .. ID; end local Docket = A['Docket']; if "thesis" == config.CitationClass and utilities.is_set (Docket) then ID = sepc .. " Docket " .. Docket .. ID; end if "report" == config.CitationClass and utilities.is_set (Docket) then -- for cite report when |docket= is set ID = sepc .. ' ' .. Docket; -- overwrite ID even if |id= is set end if utilities.is_set (URL) then URL = " " .. external_link( URL, nil, URL_origin, UrlAccess ); end -- We check length of PostScript here because it will have been nuked by -- the quote parameters. We'd otherwise emit a message even if there wasn't -- a displayed postscript. -- TODO: Should the max size (1) be configurable? -- TODO: Should we check a specific pattern? if utilities.is_set(PostScript) and mw.ustring.len(PostScript) > 1 then utilities.set_message ('maint_postscript') end local Archived; if utilities.is_set (ArchiveURL) then if not utilities.is_set (ArchiveDate) then -- ArchiveURL set but ArchiveDate not set utilities.set_message ('err_archive_missing_date'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end else if utilities.is_set (ArchiveDate) then -- ArchiveURL not set but ArchiveDate is set utilities.set_message ('err_archive_date_missing_url'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end end if utilities.is_set (ArchiveURL) then if "live" == UrlStatus then if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cfg.messages['archived-live'], { external_link( ArchiveURL, cs2_lower(cfg.messages['archived']), A:ORIGIN('ArchiveURL'), nil) .. ArchiveFormat, ArchiveDate } ); else Archived = ''; end if not utilities.is_set (OriginalURL) then utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (OriginalURL) then -- UrlStatus is empty, 'dead', 'unfit', 'usurped', 'bot: unknown' if utilities.in_array (UrlStatus, {'unfit', 'usurped', 'bot: unknown'}) then Archived = sepc .. ' ' .. utilities.substitute ( cs2_lower(cfg.messages['archived-unfit']), ArchiveDate); if 'bot: unknown' == UrlStatus then utilities.set_message ('maint_bot_unknown'); -- and add a category if not already added else utilities.add_prop_cat ('unfit'); -- and add a category if not already added end else -- UrlStatus is empty, 'dead' if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cs2_lower(cfg.messages['archived-dead']), { external_link( OriginalURL, cfg.messages['original'], OriginalURL_origin, OriginalAccess ) .. OriginalFormat, ArchiveDate } ); else Archived = ''; -- unset for concatenation end end else -- OriginalUrl not set utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (ArchiveFormat) then Archived = ArchiveFormat; -- if set and ArchiveURL not set ArchiveFormat has error message else Archived = ''; end local TranscriptURL = A['TranscriptURL'] local TranscriptFormat = A['TranscriptFormat']; TranscriptFormat = style_format (TranscriptFormat, TranscriptURL, 'transcript-format', 'transcripturl'); local Transcript = A['Transcript']; local TranscriptURL_origin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL if utilities.is_set (Transcript) then if utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, Transcript, TranscriptURL_origin, nil ); end Transcript = sepc .. ' ' .. Transcript .. TranscriptFormat; elseif utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, nil, TranscriptURL_origin, nil ); end local Publisher; if utilities.is_set (PublicationDate) then PublicationDate = wrap_msg ('published', PublicationDate); end if utilities.is_set (PublisherName) then if utilities.is_set (PublicationPlace) then Publisher = sepc .. " " .. PublicationPlace .. ": " .. PublisherName .. PublicationDate; else Publisher = sepc .. " " .. PublisherName .. PublicationDate; end elseif utilities.is_set (PublicationPlace) then Publisher= sepc .. " " .. PublicationPlace .. PublicationDate; else Publisher = PublicationDate; end -- Several of the above rely upon detecting this as nil, so do it last. if (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical)) then if utilities.is_set (Title) or utilities.is_set (TitleNote) then Periodical = sepc .. " " .. format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); else Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); end end local Language = A['Language']; if utilities.is_set (Language) then Language = language_parameter (Language); -- format, categories, name from ISO639-1, etc. else Language=''; -- language not specified so make sure this is an empty string; --[[ TODO: need to extract the wrap_msg from language_parameter so that we can solve parentheses bunching problem with Format/Language/TitleType ]] end --[[ Handle the oddity that is cite speech. This code overrides whatever may be the value assigned to TitleNote (through |department=) and forces it to be " (Speech)" so that the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided). ]] if "speech" == config.CitationClass then -- cite speech only TitleNote = TitleType; -- move TitleType to TitleNote so that it renders ahead of |event= TitleType = ''; -- and unset if utilities.is_set (Periodical) then -- if Periodical, perhaps because of an included |website= or |journal= parameter if utilities.is_set (Conference) then -- and if |event= is set Conference = Conference .. sepc .. " "; -- then add appropriate punctuation to the end of the Conference variable before rendering end end end -- Piece all bits together at last. Here, all should be non-nil. -- We build things this way because it is more efficient in LUA -- not to keep reassigning to the same string variable over and over. local tcommon; local tcommon2; -- used for book cite when |contributor= is set local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (Periodical) then -- special cases for book cites if utilities.is_set (Contributors) then -- when we are citing foreword, preface, introduction, etc. tcommon = safe_join ({Title, TitleNote}, sepc); -- author and other stuff will come after this and before tcommon2 tcommon2 = safe_join ({TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); else tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); end elseif 'map' == config.CitationClass then -- special cases for cite map if utilities.is_set (Chapter) then -- map in a book; TitleType is part of Chapter tcommon = safe_join ({Title, Edition, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); elseif utilities.is_set (Periodical) then -- map in a periodical tcommon = safe_join ({Title, TitleType, Periodical, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); else -- a sheet or stand-alone map tcommon = safe_join ({Title, TitleType, Edition, Scale, Series, Language, Cartography, Others, Publisher}, sepc); end elseif 'episode' == config.CitationClass then -- special case for cite episode tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Edition, Publisher}, sepc); else -- all other CS1 templates tcommon = safe_join ({Title, TitleNote, Conference, Periodical, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc); end if #ID_list_t > 0 then ID_list_t = safe_join( { sepc .. " ", table.concat( ID_list_t, sepc .. " " ), ID }, sepc ); else ID_list_t = ID; end local Via = A['Via']; Via = utilities.is_set (Via) and wrap_msg ('via', Via) or ''; local idcommon; if 'audio-visual' == config.CitationClass or 'episode' == config.CitationClass then -- special case for cite AV media & cite episode position transcript idcommon = safe_join( { ID_list_t, URL, Archived, Transcript, AccessDate, Via, Quote }, sepc ); else idcommon = safe_join( { ID_list_t, URL, Archived, AccessDate, Via, Quote }, sepc ); end local text; -- local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; local OrigDate = A['OrigDate']; OrigDate = utilities.is_set (OrigDate) and wrap_msg ('origdate', OrigDate) or ''; if utilities.is_set (Date) then if utilities.is_set (Authors) or utilities.is_set (Editors) then -- date follows authors or editors when authors not set Date = " (" .. Date .. ")" .. OrigDate .. sepc .. " "; -- in parentheses else -- neither of authors and editors set if (string.sub(tcommon, -1, -1) == sepc) then -- if the last character of tcommon is sepc Date = " " .. Date .. OrigDate; -- Date does not begin with sepc else Date = sepc .. " " .. Date .. OrigDate; -- Date begins with sepc end end end if utilities.is_set (Authors) then if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Authors termination Authors = terminate_name_list (Authors, sepc); -- when no date, terminate with 0 or 1 sepc and a space end if utilities.is_set (Editors) then local in_text = ''; local post_text; if utilities.is_set (Chapter) and 0 == #c then in_text = cfg.messages['in'] .. ' '; in_text = cs2_lower(in_text); -- lowercase for cs2 end if EditorCount <= 1 then post_text = ' (' .. cfg.messages['editor'] .. ')'; -- be consistent with no-author, no-date case else post_text = ' (' .. cfg.messages['editors'] .. ')'; end Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space end if utilities.is_set (Contributors) then -- book cite and we're citing the intro, preface, etc. local by_text = sepc .. ' ' .. cfg.messages['by'] .. ' '; by_text = cs2_lower(by_text); -- lowercase for cs2 Authors = by_text .. Authors; -- author follows title so tweak it here if utilities.is_set (Editors) and utilities.is_set (Date) then -- when Editors make sure that Authors gets terminated Authors = terminate_name_list (Authors, sepc); -- terminate with 0 or 1 sepc and a space end if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Contributors termination Contributors = terminate_name_list (Contributors, sepc); -- terminate with 0 or 1 sepc and a space end text = safe_join( {Contributors, Date, Chapter, tcommon, Authors, Place, Editors, tcommon2, pgtext, idcommon }, sepc ); else text = safe_join( {Authors, Date, Chapter, Place, Editors, tcommon, pgtext, idcommon }, sepc ); end elseif utilities.is_set (Editors) then if utilities.is_set (Date) then if EditorCount <= 1 then Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editor']; else Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editors']; end else if EditorCount <= 1 then Editors = Editors .. " (" .. cfg.messages['editor'] .. ")" .. sepc .. " " else Editors = Editors .. " (" .. cfg.messages['editors'] .. ")" .. sepc .. " " end end text = safe_join( {Editors, Date, Chapter, Place, tcommon, pgtext, idcommon}, sepc ); else if utilities.in_array (config.CitationClass, {"journal", "citation"}) and utilities.is_set (Periodical) then text = safe_join( {Chapter, Place, tcommon, pgtext, Date, idcommon}, sepc ); else text = safe_join( {Chapter, Place, tcommon, Date, pgtext, idcommon}, sepc ); end end if utilities.is_set (PostScript) and PostScript ~= sepc then text = safe_join( {text, sepc}, sepc ); -- Deals with italics, spaces, etc. if '.' == sepc then -- remove final seperator if present text = text:gsub ('%' .. sepc .. '$', ''); -- dot must be escaped here else text = mw.ustring.gsub (text, sepc .. '$', ''); -- using ustring for non-dot sepc (likely a non-Latin character) end end text = safe_join( {text, PostScript}, sepc ); -- Now enclose the whole thing in a <cite> element local options_t = {}; options_t.class = cite_class_attribute_make (config.CitationClass, Mode); local Ref = is_valid_parameter_value (A['Ref'], A:ORIGIN('Ref'), cfg.keywords_lists['ref'], nil, true); -- nil when |ref=harv; A['Ref'] else if 'none' ~= cfg.keywords_xlate[(Ref and Ref:lower()) or ''] then local namelist_t = {}; -- holds selected contributor, author, editor name list local year = first_set ({Year, anchor_year}, 2); -- Year first for legacy citations and for YMD dates that require disambiguation if #c > 0 then -- if there is a contributor list namelist_t = c; -- select it elseif #a > 0 then -- or an author list namelist_t = a; elseif #e > 0 then -- or an editor list namelist_t = e; end local citeref_id; if #namelist_t > 0 then -- if there are names in namelist_t citeref_id = make_citeref_id (namelist_t, year); -- go make the CITEREF anchor if mw.uri.anchorEncode (citeref_id) == ((Ref and mw.uri.anchorEncode (Ref)) or '') then -- Ref may already be encoded (by {{sfnref}}) so citeref_id must be encoded before comparison utilities.set_message ('maint_ref_duplicates_default'); end else citeref_id = ''; -- unset end options_t.id = Ref or citeref_id; end if string.len (text:gsub('%b<>', '')) <= 2 then -- remove html and html-like tags; then get length of what remains; z.error_cats_t = {}; -- blank the categories list z.error_msgs_t = {}; -- blank the error messages list OCinSoutput = nil; -- blank the metadata string text = ''; -- blank the the citation utilities.set_message ('err_empty_citation'); -- set empty citation message and category end local render_t = {}; -- here we collect the final bits for concatenation into the rendered citation if is_preview_mode and (0 ~= #z.error_msgs_t or 0 ~= #z.maint_cats_t) then -- when in preview mode if not utilities.is_set (options_t.id) then -- and when this template has not created an anchor ID math.randomseed (tonumber (mw.getLanguage ('en'):formatDate ('U')) * 10000 + os.clock() * 10000); options_t.id = 'CITEREF_temp_preview_id_' .. math.random (100000, 999999); -- create temporary anchor ID for preview mode end end if utilities.is_set (options_t.id) then -- here we wrap the rendered citation in <cite ...>...</cite> tags options_t.id = mw.uri.anchorEncode(options_t.id); -- do this here; also used when adding preview warning messages table.insert (render_t, utilities.substitute (cfg.presentation['cite-id'], {options_t.id, mw.text.nowiki(options_t.class), text})); -- when |ref= is set or when there is a namelist else table.insert (render_t, utilities.substitute (cfg.presentation['cite'], {mw.text.nowiki(options_t.class), text})); -- when |ref=none or when namelist_t empty and |ref= is missing or is empty end if OCinSoutput then -- blanked when citation is 'empty' so don't bother to add boilerplate metadata span table.insert (render_t, utilities.substitute (cfg.presentation['ocins'], OCinSoutput)); -- format and append metadata to the citation end local template_name = cfg.citation_class_map_t[config.CitationClass]; local template_link = '[[Template:' .. template_name .. '|' .. template_name .. ']]'; local msg_prefix = '<code class="cs1-code">{{' .. template_link .. '}}</code>: '; if 0 ~= #z.error_msgs_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_e, {template_link, options_t.id})); table.insert (render_t, ' '); -- insert a space between citation and its error messages table.sort (z.error_msgs_t); -- sort the error messages list; sorting includes wrapping <span> and <code> tags; hidden-error sorts ahead of visible-error local hidden = true; -- presume that the only error messages emited by this template are hidden for _, v in ipairs (z.error_msgs_t) do -- spin through the list of error messages if v:find ('cs1-visible-error', 1, true) then -- look for the visible error class name hidden = false; -- found one; so don't hide the error message prefix break; -- and done because no need to look further end end z.error_msgs_t[1] = table.concat ({utilities.error_comment (msg_prefix, hidden), z.error_msgs_t[1]}); -- add error message prefix to first error message to prevent extraneous punctuation table.insert (render_t, table.concat (z.error_msgs_t, '; ')); -- make a big string of error messages and add it to the rendering end if 0 ~= #z.maint_cats_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_m, {template_link, options_t.id})); table.sort (z.maint_cats_t); -- sort the maintenance messages list local maint_msgs_t = {}; -- here we collect all of the maint messages if 0 == #z.error_msgs_t then -- if no error messages table.insert (maint_msgs_t, msg_prefix); -- insert message prefix in maint message livery end for _, v in ipairs( z.maint_cats_t ) do -- append maintenance categories table.insert (maint_msgs_t, -- assemble new maint message and add it to the maint_msgs_t table table.concat ({v, ' (', utilities.substitute (cfg.messages[':cat wikilink'], v), ')'}) ); end table.insert (render_t, utilities.substitute (cfg.presentation['hidden-maint'], table.concat (maint_msgs_t, ' '))); -- wrap the group of maint messages with proper presentation and save end if not no_tracking_cats then local sort_key; local cat_wikilink = 'cat wikilink'; if cfg.enable_sort_keys then -- when namespace sort keys enabled local namespace_number = mw.title.getCurrentTitle().namespace; -- get namespace number for this wikitext sort_key = (0 ~= namespace_number and (cfg.name_space_sort_keys[namespace_number] or cfg.name_space_sort_keys.other)) or nil; -- get sort key character; nil for mainspace cat_wikilink = (not sort_key and 'cat wikilink') or 'cat wikilink sk'; -- make <cfg.messages> key end for _, v in ipairs (z.error_cats_t) do -- append error categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end if cfg.id_limits_data_load_fail then -- boolean true when load failed utilities.set_message ('maint_id_limit_load_fail'); -- done here because this maint cat emits no message end for _, v in ipairs (z.maint_cats_t) do -- append maintenance categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end for _, v in ipairs (z.prop_cats_t) do -- append properties categories table.insert (render_t, utilities.substitute (cfg.messages['cat wikilink'], v)); -- no sort keys end end return table.concat (render_t); -- make a big string and done end --[[--------------------------< V A L I D A T E >-------------------------------------------------------------- Looks for a parameter's name in one of several whitelists. Parameters in the whitelist can have three values: true - active, supported parameters false - deprecated, supported parameters nil - unsupported parameters ]] local function validate (name, cite_class, empty) local enum_name; -- parameter name with enumerator (if any) replaced with '#' local state; local function state_test () -- local function to do testing of state values; operates on the upvalues <state> and <name> if true == state then return true; end -- valid actively supported parameter if false == state then if empty then return nil; end -- empty deprecated parameters are treated as unknowns deprecated_parameter (name); -- parameter is deprecated but still supported return true; end if 'tracked' == state then local base_name = name:gsub ('%d', ''); -- strip enumerators from parameter names that have them to get the base name utilities.add_prop_cat ('tracked-param', {base_name}, base_name); -- add a properties category; <base_name> modifies <key> return true; end return nil; end if 'string' ~= type (name) or name:find ('#') then -- # is a cs1|2 reserved character so parameters with # not permitted; positional params are 'number' type; not supported return nil; end -- replace enumerator digit(s) with # (|last25= becomes |last#=) (mw.ustring because non-Western 'local' digits) enum_name = mw.ustring.gsub (name, '%d+$', '#'); -- where enumerator is last charaters in parameter name (these to protect |s2cid=) enum_name = mw.ustring.gsub (enum_name, '%d+([%-l])', '#%1'); -- where enumerator is in the middle of the parameter name; |author#link= is the oddity if 'document' == cite_class then -- special case for {{cite document}} state = whitelist.document_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test () then return true; end return false; end if utilities.in_array (cite_class, whitelist.preprint_template_list_t) then -- limited parameter sets allowed for these templates state = whitelist.limited_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test () then return true; end state = whitelist.preprint_arguments_t[cite_class][name]; -- look in the parameter-list for the template identified by cite_class if true == state_test () then return true; end return false; -- not supported because not found or name is set to nil end -- end limited parameter-set templates if utilities.in_array (cite_class, whitelist.unique_param_template_list_t) then -- template-specific parameters for templates that accept parameters from the basic argument list state = whitelist.unique_arguments_t[cite_class][name]; -- look in the template-specific parameter-lists for the template identified by cite_class if true == state_test () then return true; end end -- if here, fall into general validation state = whitelist.common_parameters_t[enum_name]; -- all other templates; all normal parameters allowed; this list holds enumerated and nonenumerated parameters if true == state_test () then return true; end return false; -- not supported because not found or name is set to nil end --[=[-------------------------< I N T E R _ W I K I _ C H E C K >---------------------------------------------- check <value> for inter-language interwiki-link markup. <prefix> must be a MediaWiki-recognized language code. when these values have the form (without leading colon): [[<prefix>:link|label]] return label as plain-text [[<prefix>:link]] return <prefix>:link as plain-text return value as is else ]=] local function inter_wiki_check (parameter, value) local prefix = value:match ('%[%[(%a+):'); -- get an interwiki prefix if one exists local _; if prefix and cfg.inter_wiki_map[prefix:lower()] then -- if prefix is in the map, needs preceding colon so utilities.set_message ('err_bad_paramlink', parameter); -- emit an error message _, value, _ = utilities.is_wikilink (value); -- extract label portion from wikilink end return value; end --[[--------------------------< M I S S I N G _ P I P E _ C H E C K >------------------------------------------ Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal sign, compare the alphanumeric string to the list of cs1|2 parameters. If found, then the string is possibly a parameter that is missing its pipe. There are two tests made: {{cite ... |title=Title access-date=2016-03-17}} -- the first parameter has a value and whitespace separates that value from the missing pipe parameter name {{cite ... |title=access-date=2016-03-17}} -- the first parameter has no value (whitespace after the first = is trimmed by MediaWiki) cs1|2 shares some parameter names with XML/HTML attributes: class=, title=, etc. To prevent false positives XML/HTML tags are removed before the search. If a missing pipe is detected, this function adds the missing pipe maintenance category. ]] local function missing_pipe_check (parameter, value) local capture; value = value:gsub ('%b<>', ''); -- remove XML/HTML tags because attributes: class=, title=, etc. capture = value:match ('%s+(%a[%w%-]+)%s*=') or value:match ('^(%a[%w%-]+)%s*='); -- find and categorize parameters with possible missing pipes if capture and validate (capture) then -- if the capture is a valid parameter name utilities.set_message ('err_missing_pipe', parameter); end end --[[--------------------------< H A S _ E X T R A N E O U S _ P U N C T >-------------------------------------- look for extraneous terminal punctuation in most parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_punc (param, value) if 'number' == type (param) then return; end param = param:gsub ('%d+', '#'); -- enumerated name-list mask params allow terminal punct; normalize if cfg.punct_skip[param] then return; -- parameter name found in the skip table so done end if value:match ('[,;:]$') then utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end if value:match ('^=') then -- sometimes an extraneous '=' character appears ... utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end end --[[--------------------------< H A S _ T W L _ U R L >-------------------------------------------------------- look for The Wikipedia Library urls in url-holding parameters. TWL urls are accessible only for readers who are active extended confirmed Wikipedia editors. This function sets an error message when such urls are discovered and when appropriate, sets the |<param>-url-access=subscription. returns nothing. looks for: '.wikipedialibrary.idm.oclc.org' ]] local function has_twl_url (url_params_t, cite_args_t) local url_error_t = {}; -- sequence of url-holding parameters that have a TWL url for param, value in pairs (url_params_t) do if value:find ('%.wikipedialibrary%.idm%.oclc%.org') then -- has the TWL base url? table.insert (url_error_t, param); -- add parameter name to the error list end end if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); -- sor for error messaging for i, param in ipairs (url_error_t) do if cfg.url_access_map_t[param] then -- if <param> has a matching -access parameter cite_args_t[cfg.url_access_map_t[param]] = cfg.keywords_xlate.subscription; -- set |<param>-url-access=subscription end url_error_t[i] = utilities.wrap_style ('parameter', param); -- make the parameter pretty for error message end utilities.set_message ('err_param_has_twl_url', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< M I S C _ U R L _ D E T E C T >------------------------------------------------ look for miscellaneous urls that might be converted to, or are duplicates of, identifiers. ]] local misc_url_patterns_t = { 'idm%.oclc%.org', -- but not wikipedialibrary.idm.oclc.org; has_twl_url() 'https?://citeseerx?%.ist%.psu%.edu/', -- simplified so we catch all citeseer and citeseerx urls except ~/document/... (the 'new' form) } local ignore_patterns_t = { 'wikipedialibrary.idm.oclc.org', -- handled by has_twl_url() 'https?://citeseerx?%.ist%.psu%.edu/document', -- 'new'-form citeseerx urls that mostly work; ignore for now } local function misc_url_detect (url_params_t) local ignore_flag = false; for _, value in pairs (url_params_t) do for _, ignore_pattern in ipairs (ignore_patterns_t) do if value:find (ignore_pattern) then -- matches this ignore_pattern? ignore_flag = true; -- found a pattern to ignore break; -- end end if not ignore_flag then -- if ignore_flag is set then don't bother to test this url <value> for _, misc_pattern in ipairs (misc_url_patterns_t) do if value:find (misc_pattern) then -- matches this misc_pattern? utilities.set_message ('maint_misc_url'); -- found one; set the message return; -- and done; no need to test other <value>s end end end ignore_flag = false; -- reset end end --[[--------------------------< H A S _ E X T R A N E O U S _ U R L >------------------------------------------ look for extraneous url parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_url (non_url_param_t) local url_error_t = {}; check_for_url (non_url_param_t, url_error_t); -- extraneous url check if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); utilities.set_message ('err_param_has_ext_link', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< _ C I T A T I O N >------------------------------------------------------------ Module entry point frame – from template call (citation()); may be nil when called from another module args_t – table of all cs1|2 parameters in the template (the parent frame) config_t – table of template-supplied parameter (the #invoke frame) ]] local function _citation (frame, args_t, config_t) -- save a copy in case we need to display an error message in preview mode if not frame then frame = mw.getCurrentFrame(); -- if called from another module, get a frame for frame-provided functions end -- i18n: set the name that your wiki uses to identify sandbox subpages from sandbox template invoke (or can be set here) local sandbox = ((config_t.SandboxPath and '' ~= config_t.SandboxPath) and config_t.SandboxPath) or '/sandbox'; -- sandbox path from {{#invoke:Citation/CS1/sandbox|citation|SandboxPath=/...}} is_sandbox = nil ~= string.find (frame:getTitle(), sandbox, 1, true); -- is this invoke the sandbox module? sandbox = is_sandbox and sandbox or ''; -- use i18n sandbox to load sandbox modules when this module is the sandox; live modules else cfg = mw.loadData ('Module:Citation/CS1/Configuration' .. sandbox); -- load sandbox versions of support modules when {{#invoke:Citation/CS1/sandbox|...}}; live modules else whitelist = mw.loadData ('Module:Citation/CS1/Whitelist' .. sandbox); utilities = require ('Module:Citation/CS1/Utilities' .. sandbox); validation = require ('Module:Citation/CS1/Date_validation' .. sandbox); identifiers = require ('Module:Citation/CS1/Identifiers' .. sandbox); metadata = require ('Module:Citation/CS1/COinS' .. sandbox); utilities.set_selected_modules (cfg); -- so that functions in Utilities can see the selected cfg tables identifiers.set_selected_modules (cfg, utilities); -- so that functions in Identifiers can see the selected cfg tables and selected Utilities module validation.set_selected_modules (cfg, utilities); -- so that functions in Date validataion can see selected cfg tables and the selected Utilities module metadata.set_selected_modules (cfg, utilities); -- so that functions in COinS can see the selected cfg tables and selected Utilities module z = utilities.z; -- table of error and category tables in Module:Citation/CS1/Utilities local cite_args_t = {}; -- because args_t is the parent (template) frame args (which cannot be modified); params and their values will be placed here is_preview_mode = not utilities.is_set (frame:preprocess ('{{REVISIONID}}')); local suggestions = {}; -- table where we store suggestions if we need to loadData them local error_text; -- used as a flag local capture; -- the single supported capture when matching unknown parameters using patterns local empty_unknowns = {}; -- sequence table to hold empty unknown params for error message listing for k, v in pairs (args_t) do -- get parameters from the parent (template) frame v = mw.ustring.gsub (v, '^%s*(.-)%s*$', '%1'); -- trim leading/trailing whitespace; when v is only whitespace, becomes empty string if v ~= '' then if cfg.enum_needs_xlation and 'string' == type (k) then -- for wikis that set date_names['local_digits'] to non-western digits k = mw.ustring.gsub (k, '%d', cfg.date_names.local_digits); -- translate 'local' digits enumerators to Western 0-9 end if not validate( k, config_t.CitationClass ) then if type (k) ~= 'string' then -- exclude empty numbered parameters if v:match("%S+") ~= nil then error_text = utilities.set_message ('err_text_ignored', {v}); end elseif validate (k:lower(), config_t.CitationClass) then error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, k:lower()}); -- suggest the lowercase version of the parameter else if nil == suggestions.suggestions then -- if this table is nil then we need to load it suggestions = mw.loadData ('Module:Citation/CS1/Suggestions' .. sandbox); --load sandbox version of suggestion module when {{#invoke:Citation/CS1/sandbox|...}}; live module else end for pattern, param in pairs (suggestions.patterns) do -- loop through the patterns to see if we can suggest a proper parameter capture = k:match (pattern); -- the whole match if no capture in pattern else the capture if a match if capture then -- if the pattern matches param = utilities.substitute (param, capture); -- add the capture to the suggested parameter (typically the enumerator) if validate (param, config_t.CitationClass) then -- validate the suggestion to make sure that the suggestion is supported by this template (necessary for limited parameter lists) error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, param}); -- set the suggestion error message else error_text = utilities.set_message ('err_parameter_ignored', {k}); -- suggested param not supported by this template v = ''; -- unset end end end if not utilities.is_set (error_text) then -- couldn't match with a pattern, is there an explicit suggestion? if (suggestions.suggestions[ k:lower() ] ~= nil) and validate (suggestions.suggestions[ k:lower() ], config_t.CitationClass) then utilities.set_message ('err_parameter_ignored_suggest', {k, suggestions.suggestions[ k:lower() ]}); else utilities.set_message ('err_parameter_ignored', {k}); v = ''; -- unset value assigned to unrecognized parameters (this for the limited parameter lists) end end end end cite_args_t[k] = v; -- save this parameter and its value elseif not utilities.is_set (v) then -- for empty parameters if not validate (k, config_t.CitationClass, true) then -- is this empty parameter a valid parameter k = ('' == k) and cfg.err_msg_supl.empty_str or k; -- when k is empty string (or was space(s) trimmed to empty string), replace with descriptive text table.insert (empty_unknowns, utilities.wrap_style ('parameter', k)); -- format for error message and add to the list end end end if 0 ~= #empty_unknowns then -- create empty unknown error message utilities.set_message ('err_param_unknown_empty', { 1 == #empty_unknowns and '' or 's', utilities.make_sep_list (#empty_unknowns, empty_unknowns) }); end local non_url_param_t = {}; -- table of parameters and values that are not url-holding parameters local url_param_t = {}; -- table of url-holding paramters and their values for k, v in pairs (cite_args_t) do if 'string' == type (k) then -- don't evaluate positional parameters has_invisible_chars (k, v); -- look for invisible characters end has_extraneous_punc (k, v); -- look for extraneous terminal punctuation in parameter values missing_pipe_check (k, v); -- do we think that there is a parameter that is missing a pipe? cite_args_t[k] = inter_wiki_check (k, v); -- when language interwiki-linked parameter missing leading colon replace with wiki-link label if 'string' == type (k) then -- when parameter k is not positional if not cfg.url_skip[k] then -- and not in url skip table non_url_param_t[k] = v; -- make a parameter/value list for extraneous url check else -- and is in url skip table (a url-holding parameter) url_param_t[k] = v; -- make a parameter/value list to check for values that are The Wikipedia Library url end end end if cfg.suppress_archive_today_urls then has_archive_today_url (cite_args_t); -- look for and suppress archive.today urls and dependent parameters for all templates end has_extraneous_url (non_url_param_t); -- look for url in parameter values where a url does not belong has_twl_url (url_param_t, cite_args_t); -- look for url-holding parameters that hold a The Wikipedia Library url misc_url_detect (url_param_t); -- look for url-holding parameters that hold certain miscellaneous urls return table.concat ({ frame:extensionTag ('templatestyles', '', {src='Module:Citation/CS1' .. sandbox .. '/styles.css'}), citation0 (config_t, cite_args_t) }); end --[[--------------------------< C I T A T I O N >-------------------------------------------------------------- Template entry point ]] local function citation (frame) local config_t = {}; -- table to store parameters from the module {{#invoke:}} local args_t = frame:getParent().args; -- get template's preset parameters for k, v in pairs (frame.args) do -- get parameters from the {{#invoke}} frame config_t[k] = v; -- args_t[k] = v; -- crude debug support that allows us to render a citation from module {{#invoke:}}; skips parameter validation; TODO: keep? end return _citation (frame, args_t, config_t) end --[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------ ]] return { citation = citation, -- template entry point _citation = _citation, -- module entry point } mzkfjlhyhvftcb93lj0ik7zu7t1myhw 736727 241990 2025-08-30T21:44:49Z en>Trappist the monk 0 synch from sandbox; 736727 Scribunto text/plain require ('strict'); --[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- each of these counts against the Lua upvalue limit ]] local validation; -- functions in Module:Citation/CS1/Date_validation local utilities; -- functions in Module:Citation/CS1/Utilities local z = {}; -- table of tables in Module:Citation/CS1/Utilities local identifiers; -- functions and tables in Module:Citation/CS1/Identifiers local metadata; -- functions in Module:Citation/CS1/COinS local cfg = {}; -- table of configuration tables that are defined in Module:Citation/CS1/Configuration local whitelist = {}; -- table of tables listing valid template parameter names; defined in Module:Citation/CS1/Whitelist --[[------------------< P A G E S C O P E V A R I A B L E S >--------------- declare variables here that have page-wide scope that are not brought in from other modules; that are created here and used here ]] local added_deprecated_cat; -- Boolean flag so that the category is added only once local added_vanc_errs; -- Boolean flag so we only emit one Vancouver error / category local added_generic_name_errs; -- Boolean flag so we only emit one generic name error / category and stop testing names once an error is encountered local added_numeric_name_errs; -- Boolean flag so we only emit one numeric name error / category and stop testing names once an error is encountered local added_numeric_name_maint; -- Boolean flag so we only emit one numeric name maint category and stop testing names once a category has been emitted local is_preview_mode; -- true when article is in preview mode; false when using 'Preview page with this template' (previewing the module) local is_sandbox; -- true when using sandbox modules to render citation --[[--------------------------< F I R S T _ S E T >------------------------------------------------------------ Locates and returns the first set value in a table of values where the order established in the table, left-to-right (or top-to-bottom), is the order in which the values are evaluated. Returns nil if none are set. This version replaces the original 'for _, val in pairs do' and a similar version that used ipairs. With the pairs version the order of evaluation could not be guaranteed. With the ipairs version, a nil value would terminate the for-loop before it reached the actual end of the list. ]] local function first_set (list, count) local i = 1; while i <= count do -- loop through all items in list if utilities.is_set( list[i] ) then return list[i]; -- return the first set list member end i = i + 1; -- point to next end end --[[--------------------------< A D D _ V A N C _ E R R O R >---------------------------------------------------- Adds a single Vancouver system error message to the template's output regardless of how many error actually exist. To prevent duplication, added_vanc_errs is nil until an error message is emitted. added_vanc_errs is a Boolean declared in page scope variables above ]] local function add_vanc_error (source, position) if added_vanc_errs then return end added_vanc_errs = true; -- note that we've added this category utilities.set_message ('err_vancouver', {source, position}); end --[[--------------------------< I S _ S C H E M E >------------------------------------------------------------ does this thing that purports to be a URI scheme seem to be a valid scheme? The scheme is checked to see if it is in agreement with http://tools.ietf.org/html/std66#section-3.1 which says: Scheme names consist of a sequence of characters beginning with a letter and followed by any combination of letters, digits, plus ("+"), period ("."), or hyphen ("-"). returns true if it does, else false ]] local function is_scheme (scheme) return scheme and scheme:match ('^%a[%a%d%+%.%-]*:'); -- true if scheme is set and matches the pattern end --[=[-------------------------< I S _ D O M A I N _ N A M E >-------------------------------------------------- Does this thing that purports to be a domain name seem to be a valid domain name? Syntax defined here: http://tools.ietf.org/html/rfc1034#section-3.5 BNF defined here: https://tools.ietf.org/html/rfc4234 Single character names are generally reserved; see https://tools.ietf.org/html/draft-ietf-dnsind-iana-dns-01#page-15; see also [[Single-letter second-level domain]] list of TLDs: https://www.iana.org/domains/root/db RFC 952 (modified by RFC 1123) requires the first and last character of a hostname to be a letter or a digit. Between the first and last characters the name may use letters, digits, and the hyphen. Also allowed are IPv4 addresses. IPv6 not supported domain is expected to be stripped of any path so that the last character in the last character of the TLD. tld is two or more alpha characters. Any preceding '//' (from splitting a URL with a scheme) will be stripped here. Perhaps not necessary but retained in case it is necessary for IPv4 dot decimal. There are several tests: the first character of the whole domain name including subdomains must be a letter or a digit internationalized domain name (ASCII characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the TLD) see https://tools.ietf.org/html/rfc3490 single-letter/digit second-level domains in the .org, .cash, and .today TLDs q, x, and z SL domains in the .com TLD i and q SL domains in the .net TLD single-letter SL domains in the ccTLDs (where the ccTLD is two letters) two-character SL domains in gTLDs (where the gTLD is two or more letters) three-plus-character SL domains in gTLDs (where the gTLD is two or more letters) IPv4 dot-decimal address format; TLD not allowed returns true if domain appears to be a proper name and TLD or IPv4 address, else false ]=] local function is_domain_name (domain) if not domain then return false; -- if not set, abandon end domain = domain:gsub ('^//', ''); -- strip '//' from domain name if present; done here so we only have to do it once if not domain:match ('^[%w]') then -- first character must be letter or digit return false; end if domain:match ('^%a+:') then -- hack to detect things that look like s:Page:Title where Page: is namespace at Wikisource return false; end local patterns = { -- patterns that look like URLs '%f[%w][%w][%w%-]+[%w]%.%a%a+$', -- three or more character hostname.hostname or hostname.tld '%f[%w][%w][%w%-]+[%w]%.xn%-%-[%w]+$', -- internationalized domain name with ACE prefix '%f[%a][qxz]%.com$', -- assigned one character .com hostname (x.com times out 2015-12-10) '%f[%a][iq]%.net$', -- assigned one character .net hostname (q.net registered but not active 2015-12-10) '%f[%w][%w]%.%a%a$', -- one character hostname and ccTLD (2 chars) '%f[%w][%w][%w]%.%a%a+$', -- two character hostname and TLD '^%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?', -- IPv4 address '[%a%d]+%:?' -- IPv6 address } for _, pattern in ipairs (patterns) do -- loop through the patterns list if domain:match (pattern) then return true; -- if a match then we think that this thing that purports to be a URL is a URL end end for _, d in ipairs (cfg.single_letter_2nd_lvl_domains_t) do -- look for single letter second level domain names for these top level domains if domain:match ('%f[%w][%w]%.' .. d) then return true end end return false; -- no matches, we don't know what this thing is end --[[--------------------------< I S _ U R L >------------------------------------------------------------------ returns true if the scheme and domain parts of a URL appear to be a valid URL; else false. This function is the last step in the validation process. This function is separate because there are cases that are not covered by split_url(), for example is_parameter_ext_wikilink() which is looking for bracketted external wikilinks. ]] local function is_url (scheme, domain) if utilities.is_set (scheme) then -- if scheme is set check it and domain return is_scheme (scheme) and is_domain_name (domain); else return is_domain_name (domain); -- scheme not set when URL is protocol-relative end end --[[--------------------------< S P L I T _ U R L >------------------------------------------------------------ Split a URL into a scheme, authority indicator, and domain. First remove Fully Qualified Domain Name terminator (a dot following TLD) (if any) and any path(/), query(?) or fragment(#). If protocol-relative URL, return nil scheme and domain else return nil for both scheme and domain. When not protocol-relative, get scheme, authority indicator, and domain. If there is an authority indicator (one or more '/' characters immediately following the scheme's colon), make sure that there are only 2. Any URL that does not have news: scheme must have authority indicator (//). TODO: are there other common schemes like news: that don't use authority indicator? Strip off any port and path; ]] local function split_url (url_str) local scheme, authority, domain; url_str = url_str:gsub ('([%a%d])%.?[/%?#].*$', '%1'); -- strip FQDN terminator and path(/), query(?), fragment (#) (the capture prevents false replacement of '//') if url_str:match ('^//%S*') then -- if there is what appears to be a protocol-relative URL domain = url_str:match ('^//(%S*)') elseif url_str:match ('%S-:/*%S+') then -- if there is what appears to be a scheme, optional authority indicator, and domain name scheme, authority, domain = url_str:match ('(%S-:)(/*)(%S+)'); -- extract the scheme, authority indicator, and domain portions if utilities.is_set (authority) then authority = authority:gsub ('//', '', 1); -- replace place 1 pair of '/' with nothing; if utilities.is_set(authority) then -- if anything left (1 or 3+ '/' where authority should be) then return scheme; -- return scheme only making domain nil which will cause an error message end else if not scheme:match ('^news:') then -- except for news:..., MediaWiki won't link URLs that do not have authority indicator; TODO: a better way to do this test? return scheme; -- return scheme only making domain nil which will cause an error message end end domain = domain:gsub ('(%a):%d+', '%1'); -- strip port number if present end return scheme, domain; end --[[--------------------------< L I N K _ P A R A M _ O K >--------------------------------------------------- checks the content of |title-link=, |series-link=, |author-link=, etc. for properly formatted content: no wikilinks, no URLs Link parameters are to hold the title of a Wikipedia article, so none of the WP:TITLESPECIALCHARACTERS are allowed: # < > [ ] | { } _ except the underscore which is used as a space in wiki URLs and # which is used for section links returns false when the value contains any of these characters. When there are no illegal characters, this function returns TRUE if value DOES NOT appear to be a valid URL (the |<param>-link= parameter is ok); else false when value appears to be a valid URL (the |<param>-link= parameter is NOT ok). ]] local function link_param_ok (value) local scheme, domain; if value:find ('[<>%[%]|{}]') then -- if any prohibited characters return false; end scheme, domain = split_url (value); -- get scheme or nil and domain or nil from URL; return not is_url (scheme, domain); -- return true if value DOES NOT appear to be a valid URL end --[[--------------------------< L I N K _ T I T L E _ O K >--------------------------------------------------- Use link_param_ok() to validate |<param>-link= value and its matching |<title>= value. |<title>= may be wiki-linked but not when |<param>-link= has a value. This function emits an error message when that condition exists check <link> for inter-language interwiki-link prefix. prefix must be a MediaWiki-recognized language code and must begin with a colon. ]] local function link_title_ok (link, lorig, title, torig) local orig; if utilities.is_set (link) then -- don't bother if <param>-link doesn't have a value if not link_param_ok (link) then -- check |<param>-link= markup orig = lorig; -- identify the failing link parameter elseif title:find ('%[%[') then -- check |title= for wikilink markup orig = torig; -- identify the failing |title= parameter elseif link:match ('^%a+:') then -- if the link is what looks like an interwiki local prefix = link:match ('^(%a+):'):lower(); -- get the interwiki prefix if cfg.inter_wiki_map[prefix] then -- if prefix is in the map, must have preceding colon orig = lorig; -- flag as error end end end if utilities.is_set (orig) then link = ''; -- unset utilities.set_message ('err_bad_paramlink', orig); -- URL or wikilink in |title= with |title-link=; end return link; -- link if ok, empty string else end --[[--------------------------< C H E C K _ U R L >------------------------------------------------------------ Determines whether a URL string appears to be valid. First we test for space characters. If any are found, return false. Then split the URL into scheme and domain portions, or for protocol-relative (//example.com) URLs, just the domain. Use is_url() to validate the two portions of the URL. If both are valid, or for protocol-relative if domain is valid, return true, else false. Because it is different from a standard URL, and because this module used external_link() to make external links that work for standard and news: links, we validate newsgroup names here. The specification for a newsgroup name is at https://tools.ietf.org/html/rfc5536#section-3.1.4 ]] local function check_url( url_str ) if nil == url_str:match ("^%S+$") then -- if there are any spaces in |url=value it can't be a proper URL return false; end local scheme, domain; scheme, domain = split_url (url_str); -- get scheme or nil and domain or nil from URL; if 'news:' == scheme then -- special case for newsgroups return domain:match('^[%a%d%+%-_]+%.[%a%d%+%-_%.]*[%a%d%+%-_]$'); end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[=[-------------------------< I S _ P A R A M E T E R _ E X T _ W I K I L I N K >---------------------------- Return true if a parameter value has a string that begins and ends with square brackets [ and ] and the first non-space characters following the opening bracket appear to be a URL. The test will also find external wikilinks that use protocol-relative URLs. Also finds bare URLs. The frontier pattern prevents a match on interwiki-links which are similar to scheme:path URLs. The tests that find bracketed URLs are required because the parameters that call this test (currently |title=, |chapter=, |work=, and |publisher=) may have wikilinks and there are articles or redirects like '//Hus' so, while uncommon, |title=[[//Hus]] is possible as might be [[en://Hus]]. ]=] local function is_parameter_ext_wikilink (value) local scheme, domain; if value:match ('%f[%[]%[%a%S*:%S+.*%]') then -- if ext. wikilink with scheme and domain: [xxxx://yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(%a%S*:%S+).*%]')); elseif value:match ('%f[%[]%[//%S+.*%]') then -- if protocol-relative ext. wikilink: [//yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(//%S+).*%]')); elseif value:match ('%a%S*:%S+') then -- if bare URL with scheme; may have leading or trailing plain text scheme, domain = split_url (value:match ('(%a%S*:%S+)')); elseif value:match ('^//%S+') or value:match ('%s//%S+') then -- if protocol-relative bare URL: //yyyyy.zzz; authority indicator (//) must be be preceded nothing or by whitespace scheme, domain = split_url (value:match ('(//%S+)')); -- what is left should be the domain else return false; -- didn't find anything that is obviously a URL end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[[-------------------------< C H E C K _ F O R _ U R L >----------------------------------------------------- loop through a list of parameters and their values. Look at the value and if it has an external link, emit an error message. ]] local function check_for_url (parameter_list, error_list) for k, v in pairs (parameter_list) do -- for each parameter in the list if is_parameter_ext_wikilink (v) then -- look at the value; if there is a URL add an error message table.insert (error_list, utilities.wrap_style ('parameter', k)); end end end --[[--------------------------< S A F E _ F O R _ U R L >------------------------------------------------------ Escape sequences for content that will be used for URL descriptions ]] local function safe_for_url( str ) if str:match( "%[%[.-%]%]" ) ~= nil then utilities.set_message ('err_wikilink_in_url', {}); end return str:gsub( '[%[%]\n]', { ['['] = '&#91;', [']'] = '&#93;', ['\n'] = ' ' } ); end --[[--------------------------< E X T E R N A L _ L I N K >---------------------------------------------------- Format an external link with error checking ]] local function external_link (URL, label, source, access) local err_msg = ''; local domain; local path; local base_url; if not utilities.is_set (label) then label = URL; if utilities.is_set (source) then utilities.set_message ('err_bare_url_missing_title', {utilities.wrap_style ('parameter', source)}); else error (cfg.messages["bare_url_no_origin"]); -- programmer error; valid parameter name does not have matching meta-parameter end end if not check_url (URL) then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); end domain, path = URL:match ('^([/%.%-%+:%a%d]+)([/%?#].*)$'); -- split the URL into scheme plus domain and path if path then -- if there is a path portion path = path:gsub ('[%[%]]', {['['] = '%5b', [']'] = '%5d'}); -- replace '[' and ']' with their percent-encoded values URL = table.concat ({domain, path}); -- and reassemble end base_url = table.concat ({ "[", URL, " ", safe_for_url (label), "]" }); -- assemble a wiki-markup URL if utilities.is_set (access) then -- access level (subscription, registration, limited) base_url = utilities.substitute (cfg.presentation['ext-link-access-signal'], {cfg.presentation[access].class, cfg.presentation[access].title, base_url}); -- add the appropriate icon end return base_url; end --[[--------------------------< D E P R E C A T E D _ P A R A M E T E R >-------------------------------------- Categorize and emit an error message when the citation contains one or more deprecated parameters. The function includes the offending parameter name to the error message. Only one error message is emitted regardless of the number of deprecated parameters in the citation. added_deprecated_cat is a Boolean declared in page scope variables above ]] local function deprecated_parameter(name) if not added_deprecated_cat then added_deprecated_cat = true; -- note that we've added this category utilities.set_message ('err_deprecated_params', {name}); -- add error message end end --[=[-------------------------< K E R N _ Q U O T E S >-------------------------------------------------------- Apply kerning to open the space between the quote mark provided by the module and a leading or trailing quote mark contained in a |title= or |chapter= parameter's value. This function will positive kern either single or double quotes: "'Unkerned title with leading and trailing single quote marks'" " 'Kerned title with leading and trailing single quote marks' " (in real life the kerning isn't as wide as this example) Double single quotes (italic or bold wiki-markup) are not kerned. Replaces Unicode quote marks in plain text or in the label portion of a [[L|D]] style wikilink with typewriter quote marks regardless of the need for kerning. Unicode quote marks are not replaced in simple [[D]] wikilinks. Call this function for chapter titles, for website titles, etc.; not for book titles. ]=] local function kern_quotes (str) local cap = ''; local wl_type, label, link; wl_type, label, link = utilities.is_wikilink (str); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] if 1 == wl_type then -- [[D]] simple wikilink with or without quote marks if mw.ustring.match (str, '%[%[[\"“”\'‘’].+[\"“”\'‘’]%]%]') then -- leading and trailing quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); str = utilities.substitute (cfg.presentation['kern-right'], str); elseif mw.ustring.match (str, '%[%[[\"“”\'‘’].+%]%]') then -- leading quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); elseif mw.ustring.match (str, '%[%[.+[\"“”\'‘’]%]%]') then -- trailing quote marks str = utilities.substitute (cfg.presentation['kern-right'], str); end else -- plain text or [[L|D]]; text in label variable label = mw.ustring.gsub (label, '[“”]', '\"'); -- replace “” (U+201C & U+201D) with " (typewriter double quote mark) label = mw.ustring.gsub (label, '[‘’]', '\''); -- replace ‘’ (U+2018 & U+2019) with ' (typewriter single quote mark) cap = mw.ustring.match (label, "^([\"\'][^\'].+)"); -- match leading double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-left'], cap); end cap = mw.ustring.match (label, "^(.+[^\'][\"\'])$") -- match trailing double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-right'], cap); end if 2 == wl_type then str = utilities.make_wikilink (link, label); -- reassemble the wikilink else str = label; end end return str; end --[[--------------------------< F O R M A T _ S C R I P T _ V A L U E >---------------------------------------- |script-title= holds title parameters that are not written in Latin-based scripts: Chinese, Japanese, Arabic, Hebrew, etc. These scripts should not be italicized and may be written right-to-left. The value supplied by |script-title= is concatenated onto Title after Title has been wrapped in italic markup. Regardless of language, all values provided by |script-title= are wrapped in <bdi>...</bdi> tags to isolate RTL languages from the English left to right. |script-title= provides a unique feature. The value in |script-title= may be prefixed with a two-character ISO 639-1 language code and a colon: |script-title=ja:*** *** (where * represents a Japanese character) Spaces between the two-character code and the colon and the colon and the first script character are allowed: |script-title=ja : *** *** |script-title=ja: *** *** |script-title=ja :*** *** Spaces preceding the prefix are allowed: |script-title = ja:*** *** The prefix is checked for validity. If it is a valid ISO 639-1 language code, the lang attribute (lang="ja") is added to the <bdi> tag so that browsers can know the language the tag contains. This may help the browser render the script more correctly. If the prefix is invalid, the lang attribute is not added. At this time there is no error message for this condition. Supports |script-title=, |script-chapter=, |script-<periodical>= ]] local function format_script_value (script_value, script_param) local lang=''; -- initialize to empty string local name; if script_value:match('^%l%l%l?%s*:') then -- if first 3 or 4 non-space characters are script language prefix lang = script_value:match('^(%l%l%l?)%s*:%s*%S.*'); -- get the language prefix or nil if there is no script if not utilities.is_set (lang) then utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing title part']}); -- prefix without 'title'; add error message return ''; -- script_value was just the prefix so return empty string end -- if we get this far we have prefix and script name = cfg.lang_tag_remap[lang] or mw.language.fetchLanguageName( lang, cfg.this_wiki_code ); -- get language name so that we can use it to categorize if utilities.is_set (name) then -- is prefix a proper ISO 639-1 language code? script_value = script_value:gsub ('^%l+%s*:%s*', ''); -- strip prefix from script -- is prefix one of these language codes? if utilities.in_array (lang, cfg.script_lang_codes) then utilities.add_prop_cat ('script', {name, lang}) else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['unknown language code']}); -- unknown script-language; add error message end lang = ' lang="' .. lang .. '" '; -- convert prefix into a lang attribute else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['invalid language code']}); -- invalid language code; add error message lang = ''; -- invalid so set lang to empty string end else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing prefix']}); -- no language code prefix; add error message end script_value = utilities.substitute (cfg.presentation['bdi'], {lang, script_value}); -- isolate in case script is RTL return script_value; end --[[--------------------------< S C R I P T _ C O N C A T E N A T E >------------------------------------------ Initially for |title= and |script-title=, this function concatenates those two parameter values after the script value has been wrapped in <bdi> tags. ]] local function script_concatenate (title, script, script_param) if utilities.is_set (script) then script = format_script_value (script, script_param); -- <bdi> tags, lang attribute, categorization, etc.; returns empty string on error if utilities.is_set (script) then title = title .. ' ' .. script; -- concatenate title and script title end end return title; end --[[--------------------------< W R A P _ M S G >-------------------------------------------------------------- Applies additional message text to various parameter values. Supplied string is wrapped using a message_list configuration taking one argument. Supports lower case text for {{citation}} templates. Additional text taken from citation_config.messages - the reason this function is similar to but separate from wrap_style(). ]] local function wrap_msg (key, str, lower) if not utilities.is_set ( str ) then return ""; end if true == lower then local msg; msg = cfg.messages[key]:lower(); -- set the message to lower case before return utilities.substitute ( msg, str ); -- including template text else return utilities.substitute ( cfg.messages[key], str ); end end --[[----------------< W I K I S O U R C E _ U R L _ M A K E >------------------- Makes a Wikisource URL from Wikisource interwiki-link. Returns the URL and appropriate label; nil else. str is the value assigned to |chapter= (or aliases) or |title= or |title-link= ]] local function wikisource_url_make (str) local wl_type, D, L; local ws_url, ws_label; local wikisource_prefix = table.concat ({'https://', cfg.this_wiki_code, '.wikisource.org/wiki/'}); wl_type, D, L = utilities.is_wikilink (str); -- wl_type is 0 (not a wikilink), 1 (simple wikilink), 2 (complex wikilink) if 0 == wl_type then -- not a wikilink; might be from |title-link= str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 1 == wl_type then -- simple wikilink: [[Wikisource:ws article]] str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 2 == wl_type then -- non-so-simple wikilink: [[Wikisource:ws article|displayed text]] ([[L|D]]) str = L:match ('^[Ww]ikisource:(.+)') or L:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_label = D; -- get ws article name from display portion of interwiki link ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title without namespace from link portion of wikilink }); end end if ws_url then ws_url = mw.uri.encode (ws_url, 'WIKI'); -- make a usable URL ws_url = ws_url:gsub ('%%23', '#'); -- undo percent-encoding of fragment marker end return ws_url, ws_label, L or D; -- return proper URL or nil and a label or nil end --[[----------------< F O R M A T _ P E R I O D I C A L >----------------------- Format the three periodical parameters: |script-<periodical>=, |<periodical>=, and |trans-<periodical>= into a single Periodical meta-parameter. ]] local function format_periodical (script_periodical, script_periodical_source, periodical, trans_periodical) if not utilities.is_set (periodical) then periodical = ''; -- to be safe for concatenation else periodical = utilities.wrap_style ('italic-title', periodical); -- style end periodical = script_concatenate (periodical, script_periodical, script_periodical_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (trans_periodical) then trans_periodical = utilities.wrap_style ('trans-italic-title', trans_periodical); if utilities.is_set (periodical) then periodical = periodical .. ' ' .. trans_periodical; else -- here when trans-periodical without periodical or script-periodical periodical = trans_periodical; utilities.set_message ('err_trans_missing_title', {'periodical'}); end end return periodical; end --[[------------------< F O R M A T _ C H A P T E R _ T I T L E >--------------- Format the four chapter parameters: |script-chapter=, |chapter=, |trans-chapter=, and |chapter-url= into a single chapter meta- parameter (chapter_url_source used for error messages). ]] local function format_chapter_title (script_chapter, script_chapter_source, chapter, chapter_source, trans_chapter, trans_chapter_source, chapter_url, chapter_url_source, no_quotes, access) local ws_url, ws_label, L = wikisource_url_make (chapter); -- make a wikisource URL and label from a wikisource interwiki link if ws_url then ws_label = ws_label:gsub ('_', ' '); -- replace underscore separators with space characters chapter = ws_label; end if not utilities.is_set (chapter) then chapter = ''; -- to be safe for concatenation else if false == no_quotes then chapter = kern_quotes (chapter); -- if necessary, separate chapter title's leading and trailing quote marks from module provided quote marks chapter = utilities.wrap_style ('quoted-title', chapter); end end chapter = script_concatenate (chapter, script_chapter, script_chapter_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (chapter_url) then chapter = external_link (chapter_url, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate elseif ws_url then chapter = external_link (ws_url, chapter .. '&nbsp;', 'ws link in chapter'); -- adds bare_url_missing_title error if appropriate; space char to move icon away from chap text; TODO: better way to do this? chapter = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, chapter}); end if utilities.is_set (trans_chapter) then trans_chapter = utilities.wrap_style ('trans-quoted-title', trans_chapter); if utilities.is_set (chapter) then chapter = chapter .. ' ' .. trans_chapter; else -- here when trans_chapter without chapter or script-chapter chapter = trans_chapter; chapter_source = trans_chapter_source:match ('trans%-?(.+)'); -- when no chapter, get matching name from trans-<param> utilities.set_message ('err_trans_missing_title', {chapter_source}); end end return chapter; end --[[----------------< H A S _ I N V I S I B L E _ C H A R S >------------------- This function searches a parameter's value for non-printable or invisible characters. The search stops at the first match. This function will detect the visible replacement character when it is part of the Wikisource. Detects but ignores nowiki and math stripmarkers. Also detects other named stripmarkers (gallery, math, pre, ref) and identifies them with a slightly different error message. See also coins_cleanup(). Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker that was detected along with its position (or, for multi-byte characters, the position of its first byte) in the parameter value. ]] local function has_invisible_chars (param, v) local position = ''; -- position of invisible char or starting position of stripmarker local capture; -- used by stripmarker detection to hold name of the stripmarker local stripmarker; -- boolean set true when a stripmarker is found capture = string.match (v, '[%w%p ]*'); -- test for values that are simple ASCII text and bypass other tests if true if capture == v then -- if same there are no Unicode characters return; end for _, invisible_char in ipairs (cfg.invisible_chars) do local char_name = invisible_char[1]; -- the character or group name local pattern = invisible_char[2]; -- the pattern used to find it position, _, capture = mw.ustring.find (v, pattern); -- see if the parameter value contains characters that match the pattern if position and (cfg.invisible_defs.zwj == capture) then -- if we found a zero-width joiner character if mw.ustring.find (v, cfg.indic_script) then -- it's ok if one of the Indic scripts position = nil; -- unset position elseif cfg.emoji_t[mw.ustring.codepoint (v, position+1)] then -- is zwj followed by a character listed in emoji{}? position = nil; -- unset position end end if position then if 'nowiki' == capture or 'math' == capture or -- nowiki and math stripmarkers (not an error condition) ('templatestyles' == capture and utilities.in_array (param, {'id', 'quote'})) then -- templatestyles stripmarker allowed in these parameters stripmarker = true; -- set a flag elseif true == stripmarker and cfg.invisible_defs.del == capture then -- because stripmakers begin and end with the delete char, assume that we've found one end of a stripmarker position = nil; -- unset else local err_msg; if capture and not (cfg.invisible_defs.del == capture or cfg.invisible_defs.zwj == capture) then err_msg = capture .. ' ' .. char_name; else err_msg = char_name .. ' ' .. 'character'; end utilities.set_message ('err_invisible_char', {err_msg, utilities.wrap_style ('parameter', param), position}); -- add error message return; -- and done with this parameter end end end end --[[-------------------< A R G U M E N T _ W R A P P E R >---------------------- Argument wrapper. This function provides support for argument mapping defined in the configuration file so that multiple names can be transparently aliased to single internal variable. ]] local function argument_wrapper ( args ) local origin = {}; return setmetatable({ ORIGIN = function ( self, k ) local dummy = self[k]; -- force the variable to be loaded. return origin[k]; end }, { __index = function ( tbl, k ) if origin[k] ~= nil then return nil; end local args, list, v = args, cfg.aliases[k]; if type( list ) == 'table' then v, origin[k] = utilities.select_one ( args, list, 'err_redundant_parameters' ); if origin[k] == nil then origin[k] = ''; -- Empty string, not nil end elseif list ~= nil then v, origin[k] = args[list], list; else -- maybe let through instead of raising an error? -- v, origin[k] = args[k], k; error( cfg.messages['unknown_argument_map'] .. ': ' .. k); end -- Empty strings, not nil; if v == nil then v = ''; origin[k] = ''; end tbl = rawset( tbl, k, v ); return v; end, }); end --[[--------------------------< N O W R A P _ D A T E >------------------------- When date is YYYY-MM-DD format wrap in nowrap span: <span ...>YYYY-MM-DD</span>. When date is DD MMMM YYYY or is MMMM DD, YYYY then wrap in nowrap span: <span ...>DD MMMM</span> YYYY or <span ...>MMMM DD,</span> YYYY DOES NOT yet support MMMM YYYY or any of the date ranges. ]] local function nowrap_date (date) local cap = ''; local cap2 = ''; if date:match("^%d%d%d%d%-%d%d%-%d%d$") then date = utilities.substitute (cfg.presentation['nowrap1'], date); elseif date:match("^%a+%s*%d%d?,%s+%d%d%d%d$") or date:match ("^%d%d?%s*%a+%s+%d%d%d%d$") then cap, cap2 = string.match (date, "^(.*)%s+(%d%d%d%d)$"); date = utilities.substitute (cfg.presentation['nowrap2'], {cap, cap2}); end return date; end --[[--------------------------< S E T _ T I T L E T Y P E >--------------------- This function sets default title types (equivalent to the citation including |type=<default value>) for those templates that have defaults. Also handles the special case where it is desirable to omit the title type from the rendered citation (|type=none). ]] local function set_titletype (cite_class, title_type) if utilities.is_set (title_type) then if 'none' == cfg.keywords_xlate[title_type] then title_type = ''; -- if |type=none then type parameter not displayed end return title_type; -- if |type= has been set to any other value use that value end return cfg.title_types [cite_class] or ''; -- set template's default title type; else empty string for concatenation end --[[--------------------------< S A F E _ J O I N >----------------------------- Joins a sequence of strings together while checking for duplicate separation characters. ]] local function safe_join( tbl, duplicate_char ) local f = {}; -- create a function table appropriate to type of 'duplicate character' if 1 == #duplicate_char then -- for single byte ASCII characters use the string library functions f.gsub = string.gsub f.match = string.match f.sub = string.sub else -- for multi-byte characters use the ustring library functions f.gsub = mw.ustring.gsub f.match = mw.ustring.match f.sub = mw.ustring.sub end local str = ''; -- the output string local comp = ''; -- what does 'comp' mean? local end_chr = ''; local trim; for _, value in ipairs( tbl ) do if value == nil then value = ''; end if str == '' then -- if output string is empty str = value; -- assign value to it (first time through the loop) elseif value ~= '' then if value:sub(1, 1) == '<' then -- special case of values enclosed in spans and other markup. comp = value:gsub( "%b<>", "" ); -- remove HTML markup (<span>string</span> -> string) else comp = value; end -- typically duplicate_char is sepc if f.sub(comp, 1, 1) == duplicate_char then -- is first character same as duplicate_char? why test first character? -- Because individual string segments often (always?) begin with terminal punct for the -- preceding segment: 'First element' .. 'sepc next element' .. etc.? trim = false; end_chr = f.sub(str, -1, -1); -- get the last character of the output string -- str = str .. "<HERE(enchr=" .. end_chr .. ")" -- debug stuff? if end_chr == duplicate_char then -- if same as separator str = f.sub(str, 1, -2); -- remove it elseif end_chr == "'" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "''" then -- if last three chars of str are sepc'' str = f.sub(str, 1, -4) .. "''"; -- remove them and add back '' elseif f.sub(str, -5, -1) == duplicate_char .. "]]''" then -- if last five chars of str are sepc]]'' trim = true; -- why? why do this and next differently from previous? elseif f.sub(str, -4, -1) == duplicate_char .. "]''" then -- if last four chars of str are sepc]'' trim = true; -- same question end elseif end_chr == "]" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "]]" then -- if last three chars of str are sepc]] wikilink trim = true; elseif f.sub(str, -3, -1) == duplicate_char .. '"]' then -- if last three chars of str are sepc"] quoted external link trim = true; elseif f.sub(str, -2, -1) == duplicate_char .. "]" then -- if last two chars of str are sepc] external link trim = true; elseif f.sub(str, -4, -1) == duplicate_char .. "'']" then -- normal case when |url=something & |title=Title. trim = true; end elseif end_chr == " " then -- if last char of output string is a space if f.sub(str, -2, -1) == duplicate_char .. " " then -- if last two chars of str are <sepc><space> str = f.sub(str, 1, -3); -- remove them both end end if trim then if value ~= comp then -- value does not equal comp when value contains HTML markup local dup2 = duplicate_char; if f.match(dup2, "%A" ) then dup2 = "%" .. dup2; end -- if duplicate_char not a letter then escape it value = f.gsub(value, "(%b<>)" .. dup2, "%1", 1 ) -- remove duplicate_char if it follows HTML markup else value = f.sub(value, 2, -1 ); -- remove duplicate_char when it is first character end end end str = str .. value; -- add it to the output string end end return str; end --[[--------------------------< I S _ S U F F I X >----------------------------- returns true if suffix is properly formed Jr, Sr, or ordinal in the range 1–9. Puncutation not allowed. ]] local function is_suffix (suffix) if utilities.in_array (suffix, {'Jr', 'Sr', 'Jnr', 'Snr', '1st', '2nd', '3rd'}) or suffix:match ('^%dth$') then return true; end return false; end --[[--------------------< I S _ G O O D _ V A N C _ N A M E >------------------- For Vancouver style, author/editor names are supposed to be rendered in Latin (read ASCII) characters. When a name uses characters that contain diacritical marks, those characters are to be converted to the corresponding Latin character. When a name is written using a non-Latin alphabet or logogram, that name is to be transliterated into Latin characters. The module doesn't do this so editors may/must. This test allows |first= and |last= names to contain any of the letters defined in the four Unicode Latin character sets [http://www.unicode.org/charts/PDF/U0000.pdf C0 Controls and Basic Latin] 0041–005A, 0061–007A [http://www.unicode.org/charts/PDF/U0080.pdf C1 Controls and Latin-1 Supplement] 00C0–00D6, 00D8–00F6, 00F8–00FF [http://www.unicode.org/charts/PDF/U0100.pdf Latin Extended-A] 0100–017F [http://www.unicode.org/charts/PDF/U0180.pdf Latin Extended-B] 0180–01BF, 01C4–024F |lastn= also allowed to contain hyphens, spaces, and apostrophes. (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) |firstn= also allowed to contain hyphens, spaces, apostrophes, and periods This original test: if nil == mw.ustring.find (last, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%'%.]+[2-6%a]*$") then was written outside of the code editor and pasted here because the code editor gets confused between character insertion point and cursor position. The test has been rewritten to use decimal character escape sequence for the individual bytes of the Unicode characters so that it is not necessary to use an external editor to maintain this code. \195\128-\195\150 – À-Ö (U+00C0–U+00D6 – C0 controls) \195\152-\195\182 – Ø-ö (U+00D8-U+00F6 – C0 controls) \195\184-\198\191 – ø-ƿ (U+00F8-U+01BF – C0 controls, Latin extended A & B) \199\132-\201\143 – DŽ-ɏ (U+01C4-U+024F – Latin extended B) ]] local function is_good_vanc_name (last, first, suffix, position) if not suffix then if first:find ('[,%s]') then -- when there is a space or comma, might be first name/initials + generational suffix first = first:match ('(.-)[,%s]+'); -- get name/initials suffix = first:match ('[,%s]+(.+)$'); -- get generational suffix end end if utilities.is_set (suffix) then if not is_suffix (suffix) then add_vanc_error (cfg.err_msg_supl.suffix, position); return false; -- not a name with an appropriate suffix end end if nil == mw.ustring.find (last, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%'%.]*$") then add_vanc_error (cfg.err_msg_supl['non-Latin char'], position); return false; -- not a string of Latin characters; Vancouver requires Romanization end; return true; end --[[--------------------------< R E D U C E _ T O _ I N I T I A L S >------------------------------------------ Attempts to convert names to initials in support of |name-list-style=vanc. Names in |firstn= may be separated by spaces or hyphens, or for initials, a period. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35062/. Vancouver style requires family rank designations (Jr, II, III, etc.) to be rendered as Jr, 2nd, 3rd, etc. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35085/. This code only accepts and understands generational suffix in the Vancouver format because Roman numerals look like, and can be mistaken for, initials. This function uses ustring functions because firstname initials may be any of the Unicode Latin characters accepted by is_good_vanc_name (). ]] local function reduce_to_initials (first, position) if first:find (',', 1, true) then return first; -- commas not allowed; abandon end local name, suffix = mw.ustring.match (first, "^(%u+) ([%dJS][%drndth]+)$"); if not name then -- if not initials and a suffix name = mw.ustring.match (first, "^(%u+)$"); -- is it just initials? end if name then -- if first is initials with or without suffix if 3 > mw.ustring.len (name) then -- if one or two initials if suffix then -- if there is a suffix if is_suffix (suffix) then -- is it legitimate? return first; -- one or two initials and a valid suffix so nothing to do else add_vanc_error (cfg.err_msg_supl.suffix, position); -- one or two initials with invalid suffix so error message return first; -- and return first unmolested end else return first; -- one or two initials without suffix; nothing to do end end end -- if here then name has 3 or more uppercase letters so treat them as a word local initials_t, names_t = {}, {}; -- tables to hold name parts and initials local i = 1; -- counter for number of initials names_t = mw.text.split (first, '[%s%-]+'); -- split into a sequence of names and possible suffix while names_t[i] do -- loop through the sequence if 1 < i and names_t[i]:match ('[%dJS][%drndth]+%.?$') then -- if not the first name, and looks like a suffix (may have trailing dot) names_t[i] = names_t[i]:gsub ('%.', ''); -- remove terminal dot if present if is_suffix (names_t[i]) then -- if a legitimate suffix table.insert (initials_t, ' ' .. names_t[i]); -- add a separator space, insert at end of initials sequence break; -- and done because suffix must fall at the end of a name end -- no error message if not a suffix; possibly because of Romanization end if 3 > i then table.insert (initials_t, mw.ustring.sub (names_t[i], 1, 1)); -- insert the initial at end of initials sequence end i = i + 1; -- bump the counter end return table.concat (initials_t); -- Vancouver format does not include spaces. end --[[--------------------------< I N T E R W I K I _ P R E F I X E N _ G E T >---------------------------------- extract interwiki prefixen from <value>. Returns two one or two values: false – no prefixen nil – prefix exists but not recognized project prefix, language prefix – when value has either of: :<project>:<language>:<article> :<language>:<project>:<article> project prefix, nil – when <value> has only a known single-letter prefix nil, language prefix – when <value> has only a known language prefix accepts single-letter project prefixen: 'd' (wikidata), 's' (wikisource), and 'w' (wikipedia) prefixes; at this writing, the other single-letter prefixen (b (wikibook), c (commons), m (meta), n (wikinews), q (wikiquote), and v (wikiversity)) are not supported. ]] local function interwiki_prefixen_get (value, is_link) if not value:find (':%l+:') then -- if no prefix return false; -- abandon; boolean here to distinguish from nil fail returns later end local prefix_patterns_linked_t = { -- sequence of valid interwiki and inter project prefixen '^%[%[:([dsw]):(%l%l+):', -- wikilinked; project and language prefixes '^%[%[:(%l%l+):([dsw]):', -- wikilinked; language and project prefixes '^%[%[:([dsw]):', -- wikilinked; project prefix '^%[%[:(%l%l+):', -- wikilinked; language prefix } local prefix_patterns_unlinked_t = { -- sequence of valid interwiki and inter project prefixen '^:([dsw]):(%l%l+):', -- project and language prefixes '^:(%l%l+):([dsw]):', -- language and project prefixes '^:([dsw]):', -- project prefix '^:(%l%l+):', -- language prefix } local cap1, cap2; for _, pattern in ipairs ((is_link and prefix_patterns_linked_t) or prefix_patterns_unlinked_t) do cap1, cap2 = value:match (pattern); if cap1 then break; -- found a match so stop looking end end if cap1 and cap2 then -- when both then :project:language: or :language:project: (both forms allowed) if 1 == #cap1 then -- length == 1 then :project:language: if cfg.inter_wiki_map[cap2] then -- is language prefix in the interwiki map? return cap1, cap2; -- return interwiki project and interwiki language end else -- here when :language:project: if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return cap2, cap1; -- return interwiki project and interwiki language end end return nil; -- unknown interwiki language elseif not (cap1 or cap2) then -- both are nil? return nil; -- we got something that looks like a project prefix but isn't; return fail elseif 1 == #cap1 then -- here when one capture return cap1, nil; -- length is 1 so return project, nil language else -- here when one capture and its length it more than 1 if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return nil, cap1; -- return nil project, language end end end --[[--------------------------< L I S T _ P E O P L E >-------------------------- Formats a list of people (authors, contributors, editors, interviewers, translators) names in the list will be linked when |<name>-link= has a value |<name>-mask- does NOT have a value; masked names are presumed to have been rendered previously so should have been linked there when |<name>-mask=0, the associated name is not rendered ]] local function list_people (control, people, etal) local sep; local namesep; local format = control.format; local maximum = control.maximum; local name_list = {}; if 'vanc' == format then -- Vancouver-like name styling? sep = cfg.presentation['sep_nl_vanc']; -- name-list separator between names is a comma namesep = cfg.presentation['sep_name_vanc']; -- last/first separator is a space else sep = cfg.presentation['sep_nl']; -- name-list separator between names is a semicolon namesep = cfg.presentation['sep_name']; -- last/first separator is <comma><space> end if sep:sub (-1, -1) ~= " " then sep = sep .. " " end if utilities.is_set (maximum) and maximum < 1 then return "", 0; end -- returned 0 is for EditorCount; not used for other names for i, person in ipairs (people) do if utilities.is_set (person.last) then local mask = person.mask; local one; local sep_one = sep; if utilities.is_set (maximum) and i > maximum then etal = true; break; end if mask then local n = tonumber (mask); -- convert to a number if it can be converted; nil else if n then one = 0 ~= n and string.rep("&mdash;", n) or nil; -- make a string of (n > 0) mdashes, nil else, to replace name person.link = nil; -- don't create link to name if name is replaces with mdash string or has been set nil else one = mask; -- replace name with mask text (must include name-list separator) sep_one = " "; -- modify name-list separator end else one = person.last; -- get surname local first = person.first -- get given name if utilities.is_set (first) then if ("vanc" == format) then -- if Vancouver format one = one:gsub ('%.', ''); -- remove periods from surnames (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) if not person.corporate and is_good_vanc_name (one, first, nil, i) then -- and name is all Latin characters; corporate authors not tested first = reduce_to_initials (first, i); -- attempt to convert first name(s) to initials end end one = one .. namesep .. first; end end if utilities.is_set (person.link) then one = utilities.make_wikilink (person.link, one); -- link author/editor end if one then -- if <one> has a value (name, mdash replacement, or mask text replacement) local proj, tag = interwiki_prefixen_get (one, true); -- get the interwiki prefixen if present if 'w' == proj and ('Wikipedia' == mw.site.namespaces.Project['name']) then proj = nil; -- for stuff like :w:de:<article>, :w is unnecessary TODO: maint cat? end if proj then local proj_name = ({['d'] = 'Wikidata', ['s'] = 'Wikisource', ['w'] = 'Wikipedia'})[proj]; -- :w (wikipedia) for linking from a non-wikipedia project if proj_name then one = one .. utilities.wrap_style ('interproj', proj_name); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interproj-linked-name', proj); -- categorize it; <proj> is sort key tag = nil; -- unset; don't do both project and language end end if tag == cfg.this_wiki_code then tag = nil; -- stuff like :en:<article> at en.wiki is pointless TODO: maint cat? end if tag then local lang = cfg.lang_tag_remap[tag] or cfg.mw_languages_by_tag_t[tag]; if lang then -- error messaging done in extract_names() where we know parameter names one = one .. utilities.wrap_style ('interwiki', lang); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interwiki-linked-name', tag); -- categorize it; <tag> is sort key end end table.insert (name_list, one); -- add it to the list of names table.insert (name_list, sep_one); -- add the proper name-list separator end end end local count = #name_list / 2; -- (number of names + number of separators) divided by 2 if 0 < count then if 1 < count and not etal then if 'amp' == format then name_list[#name_list-2] = " & "; -- replace last separator with ampersand text elseif 'and' == format then if 2 == count then name_list[#name_list-2] = cfg.presentation.sep_nl_and; -- replace last separator with 'and' text else name_list[#name_list-2] = cfg.presentation.sep_nl_end; -- replace last separator with '(sep) and' text end end end name_list[#name_list] = nil; -- erase the last separator end local result = table.concat (name_list); -- construct list if etal and utilities.is_set (result) then -- etal may be set by |display-authors=etal but we might not have a last-first list result = result .. sep .. cfg.messages['et al']; -- we've got a last-first list and etal so add et al. end return result, count; -- return name-list string and count of number of names (count used for editor names only) end --[[--------------------< M A K E _ C I T E R E F _ I D >----------------------- Generates a CITEREF anchor ID if we have at least one name or a date. Otherwise returns an empty string. namelist is one of the contributor-, author-, or editor-name lists chosen in that order. year is Year or anchor_year. ]] local function make_citeref_id (namelist, year) local names={}; -- a table for the one to four names and year for i,v in ipairs (namelist) do -- loop through the list and take up to the first four last names names[i] = v.last if i == 4 then break end -- if four then done end table.insert (names, year); -- add the year at the end local id = table.concat(names); -- concatenate names and year for CITEREF id if utilities.is_set (id) then -- if concatenation is not an empty string return "CITEREF" .. id; -- add the CITEREF portion else return ''; -- return an empty string; no reason to include CITEREF id in this citation end end --[[--------------------------< C I T E _ C L A S S _A T T R I B U T E _M A K E >------------------------------ construct <cite> tag class attribute for this citation. <cite_class> – config.CitationClass from calling template <mode> – value from |mode= parameter ]] local function cite_class_attribute_make (cite_class, mode) local class_t = {}; table.insert (class_t, 'citation'); -- required for blue highlight if 'citation' ~= cite_class then table.insert (class_t, cite_class); -- identify this template for user css table.insert (class_t, utilities.is_set (mode) and mode or 'cs1'); -- identify the citation style for user css or javascript else table.insert (class_t, utilities.is_set (mode) and mode or 'cs2'); -- identify the citation style for user css or javascript end for _, prop_key in ipairs (z.prop_keys_t) do table.insert (class_t, prop_key); -- identify various properties for user css or javascript end return table.concat (class_t, ' '); -- make a big string and done end --[[---------------------< N A M E _ H A S _ E T A L >-------------------------- Evaluates the content of name parameters (author, editor, etc.) for variations on the theme of et al. If found, the et al. is removed, a flag is set to true and the function returns the modified name and the flag. This function never sets the flag to false but returns its previous state because it may have been set by previous passes through this function or by the associated |display-<names>=etal parameter ]] local function name_has_etal (name, etal, nocat, param) if utilities.is_set (name) then -- name can be nil in which case just return local patterns = cfg.et_al_patterns; -- get patterns from configuration for _, pattern in ipairs (patterns) do -- loop through all of the patterns if name:match (pattern) then -- if this 'et al' pattern is found in name name = name:gsub (pattern, ''); -- remove the offending text etal = true; -- set flag (may have been set previously here or by |display-<names>=etal) if not nocat then -- no categorization for |vauthors= utilities.set_message ('err_etal', {param}); -- and set an error if not added end end end end return name, etal; end --[[---------------------< N A M E _ I S _ N U M E R I C >---------------------- Add an error message and category when <name> parameter value does not contain letters. Add a maintenance category when <name> parameter value has numeric characters mixed with characters that are not numeric characters; could be letters and/or punctuation characters. This function will only emit one error and one maint message for the current template. Does not emit both error and maint messages/categories for the same parameter value. returns nothing ]] local function name_is_numeric (name, name_alias, list_name) local patterns = { '^%D+%d', -- <name> must have digits preceded by other characters '^%D*%d+%D+', -- <name> must have digits followed by other characters } if not added_numeric_name_errs and mw.ustring.match (name, '^[%A]+$') then -- if we have not already set an error message and <name> does not have any alpha characters utilities.set_message ('err_numeric_names', name_alias); -- add an error message added_numeric_name_errs = true; -- set the flag so we emit only one error message return; -- when here no point in further testing; abandon end if not added_numeric_name_maint then -- if we have already set a maint message for _, pattern in ipairs (patterns) do -- spin through list of patterns if mw.ustring.match (name, pattern) then -- digits preceded or followed by anything but digits; %D+ includes punctuation utilities.set_message ('maint_numeric_names', cfg.special_case_translation [list_name]); -- add a maint cat for this template added_numeric_name_maint = true; -- set the flag so we emit only one maint message return; -- when here no point in further testing; abandon end end end end --[[-----------------< N A M E _ H A S _ M U L T _ N A M E S >------------------ Evaluates the content of last/surname (authors etc.) parameters for multiple names. Multiple names are indicated if there is more than one comma or any "unescaped" semicolons. Escaped semicolons are ones used as part of selected HTML entities. If the condition is met, the function adds the multiple name maintenance category. Same test for first except that commas should not appear in given names (MOS:JR says that the generational suffix does not take a separator character). Titles, degrees, postnominals, affiliations, all normally comma separated don't belong in a citation. <name> – name parameter value <list_name> – AuthorList, EditorList, etc <limit> – number of allowed commas; 1 (default) for surnames; 0 for given names returns nothing ]] local function name_has_mult_names (name, list_name, limit) local _, commas, semicolons, nbsps; limit = limit and limit or 1; if utilities.is_set (name) then _, commas = name:gsub (',', ''); -- count the number of commas _, semicolons = name:gsub (';', ''); -- count the number of semicolons -- nbsps probably should be its own separate count rather than merged in -- some way with semicolons because Lua patterns do not support the -- grouping operator that regex does, which means there is no way to add -- more entities to escape except by adding more counts with the new -- entities _, nbsps = name:gsub ('&nbsp;',''); -- count nbsps -- There is exactly 1 semicolon per &nbsp; entity, so subtract nbsps -- from semicolons to 'escape' them. If additional entities are added, -- they also can be subtracted. if limit < commas or 0 < (semicolons - nbsps) then utilities.set_message ('maint_mult_names', cfg.special_case_translation [list_name]); -- add a maint message end end end --[=[-------------------------< I S _ G E N E R I C >---------------------------------------------------------- Compares values assigned to various parameters according to the string provided as <item> in the function call. <item> can have on of two values: 'generic_names' – for name-holding parameters: |last=, |first=, |editor-last=, etc 'generic_titles' – for |title= There are two types of generic tests. The 'accept' tests look for a pattern that should not be rejected by the 'reject' test. For example, |author=[[John Smith (author)|Smith, John]] would be rejected by the 'author' reject test. But piped wikilinks with 'author' disambiguation should not be rejected so the 'accept' test prevents that from happening. Accept tests are always performed before reject tests. Each of the 'accept' and 'reject' sequence tables hold tables for en.wiki (['en']) and local.wiki (['local']) that each can hold a test sequence table The sequence table holds, at index [1], a test pattern, and, at index [2], a boolean control value. The control value tells string.find() or mw.ustring.find() to do plain-text search (true) or a pattern search (false). The intent of all this complexity is to make these searches as fast as possible so that we don't run out of processing time on very large articles. Returns true when a reject test finds the pattern or string false when an accept test finds the pattern or string nil else ]=] local function is_generic (item, value, wiki) local test_val; local str_lower = { -- use string.lower() for en.wiki (['en']) and use mw.ustring.lower() or local.wiki (['local']) ['en'] = string.lower, ['local'] = mw.ustring.lower, } local str_find = { -- use string.find() for en.wiki (['en']) and use mw.ustring.find() or local.wiki (['local']) ['en'] = string.find, ['local'] = mw.ustring.find, } local function test (val, test_t, wiki) -- local function to do the testing; <wiki> selects lower() and find() functions val = test_t[2] and str_lower[wiki](value) or val; -- when <test_t[2]> set to 'true', plaintext search using lowercase value return str_find[wiki] (val, test_t[1], 1, test_t[2]); -- return nil when not found or matched end local test_types_t = {'accept', 'reject'}; -- test accept patterns first, then reject patterns local wikis_t = {'en', 'local'}; -- do tests for each of these keys; en.wiki first, local.wiki second for _, test_type in ipairs (test_types_t) do -- for each test type for _, generic_value in pairs (cfg.special_case_translation[item][test_type]) do -- spin through the list of generic value fragments to accept or reject for _, wiki in ipairs (wikis_t) do if generic_value[wiki] then if test (value, generic_value[wiki], wiki) then -- go do the test return ('reject' == test_type); -- param value rejected, return true; false else end end end end end end --[[--------------------------< N A M E _ I S _ G E N E R I C >------------------------------------------------ calls is_generic() to determine if <name> is a 'generic name' listed in cfg.generic_names; <name_alias> is the parameter name used in error messaging ]] local function name_is_generic (name, name_alias) if not added_generic_name_errs and is_generic ('generic_names', name) then utilities.set_message ('err_generic_name', name_alias); -- set an error message added_generic_name_errs = true; end end --[[--------------------------< N A M E _ C H E C K S >-------------------------------------------------------- This function calls various name checking functions used to validate the content of the various name-holding parameters. ]] local function name_checks (last, first, list_name, last_alias, first_alias) local accept_name; if utilities.is_set (last) then last, accept_name = utilities.has_accept_as_written (last); -- remove accept-this-as-written markup when it wraps all of <last> if not accept_name then -- <last> not wrapped in accept-as-written markup name_has_mult_names (last, list_name); -- check for multiple names in the parameter name_is_numeric (last, last_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (last, last_alias); -- check for names found in the generic names list end end if utilities.is_set (first) then first, accept_name = utilities.has_accept_as_written (first); -- remove accept-this-as-written markup when it wraps all of <first> if not accept_name then -- <first> not wrapped in accept-as-written markup name_has_mult_names (first, list_name, 0); -- check for multiple names in the parameter; 0 is number of allowed commas in a given name name_is_numeric (first, first_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (first, first_alias); -- check for names found in the generic names list end local wl_type, D = utilities.is_wikilink (first); if 0 ~= wl_type then first = D; utilities.set_message ('err_bad_paramlink', first_alias); end end return last, first; -- done end --[[----------------------< E X T R A C T _ N A M E S >------------------------- Gets name list from the input arguments Searches through args in sequential order to find |lastn= and |firstn= parameters (or their aliases), and their matching link and mask parameters. Stops searching when both |lastn= and |firstn= are not found in args after two sequential attempts: found |last1=, |last2=, and |last3= but doesn't find |last4= and |last5= then the search is done. This function emits an error message when there is a |firstn= without a matching |lastn=. When there are 'holes' in the list of last names, |last1= and |last3= are present but |last2= is missing, an error message is emitted. |lastn= is not required to have a matching |firstn=. When an author or editor parameter contains some form of 'et al.', the 'et al.' is stripped from the parameter and a flag (etal) returned that will cause list_people() to add the static 'et al.' text from Module:Citation/CS1/Configuration. This keeps 'et al.' out of the template's metadata. When this occurs, an error is emitted. ]] local function extract_names(args, list_name) local names = {}; -- table of names local last; -- individual name components local first; local link; local mask; local i = 1; -- loop counter/indexer local n = 1; -- output table indexer local count = 0; -- used to count the number of times we haven't found a |last= (or alias for authors, |editor-last or alias for editors) local etal = false; -- return value set to true when we find some form of et al. in an author parameter local last_alias, first_alias, link_alias; -- selected parameter aliases used in error messaging while true do last, last_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'err_redundant_parameters', i ); -- search through args for name components beginning at 1 first, first_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'err_redundant_parameters', i ); link, link_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ); mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); if last then -- error check |lastn= alias for unknown interwiki link prefix; done here because this is where we have the parameter name local project, language = interwiki_prefixen_get (last, true); -- true because we expect interwiki links in |lastn= to be wikilinked if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', last_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? last = utilities.remove_wiki_link (last); -- remove wikilink markup; show display value only end end if link then -- error check |linkn= alias for unknown interwiki link prefix local project, language = interwiki_prefixen_get (link, false); -- false because wiki links in |author-linkn= is an error if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', link_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? link = nil; -- unset so we don't link link_alias = nil; end end last, etal = name_has_etal (last, etal, false, last_alias); -- find and remove variations on et al. first, etal = name_has_etal (first, etal, false, first_alias); -- find and remove variations on et al. last, first = name_checks (last, first, list_name, last_alias, first_alias); -- multiple names, extraneous annotation, etc. checks if first and not last then -- if there is a firstn without a matching lastn local alias = first_alias:find ('given', 1, true) and 'given' or 'first'; -- get first or given form of the alias utilities.set_message ('err_first_missing_last', { first_alias, -- param name of alias missing its mate first_alias:gsub (alias, {['first'] = 'last', ['given'] = 'surname'}), -- make param name appropriate to the alias form }); -- add this error message elseif not first and not last then -- if both firstn and lastn aren't found, are we done? count = count + 1; -- number of times we haven't found last and first if 2 <= count then -- two missing names and we give up break; -- normal exit or there is a two-name hole in the list; can't tell which end else -- we have last with or without a first local result; link = link_title_ok (link, link_alias, last, last_alias); -- check for improper wiki-markup if first then link = link_title_ok (link, link_alias, first, first_alias); -- check for improper wiki-markup end names[n] = {last = last, first = first, link = link, mask = mask, corporate = false}; -- add this name to our names list (corporate for |vauthors= only) n = n + 1; -- point to next location in the names table if 1 == count then -- if the previous name was missing utilities.set_message ('err_missing_name', {list_name:match ("(%w+)List"):lower(), i - 1}); -- add this error message end count = 0; -- reset the counter, we're looking for two consecutive missing names end i = i + 1; -- point to next args location end return names, etal; -- all done, return our list of names and the etal flag end --[[--------------------------< N A M E _ T A G _ G E T >------------------------------------------------------ attempt to decode |language=<lang_param> and return language name and matching tag; nil else. This function looks for: <lang_param> as a tag in cfg.lang_tag_remap{} <lang_param> as a name in cfg.lang_name_remap{} <lang_param> as a name in cfg.mw_languages_by_name_t <lang_param> as a tag in cfg.mw_languages_by_tag_t when those fail, presume that <lang_param> is an IETF-like tag that MediaWiki does not recognize. Strip all script, region, variant, whatever subtags from <lang_param> to leave just a two or three character language tag and look for the new <lang_param> in cfg.mw_languages_by_tag_t{} on success, returns name (in properly capitalized form) and matching tag (in lowercase); on failure returns nil ]] local function name_tag_get (lang_param) local lang_param_lc = mw.ustring.lower (lang_param); -- use lowercase as an index into the various tables local name; local tag; name = cfg.lang_tag_remap[lang_param_lc]; -- assume <lang_param_lc> is a tag; attempt to get remapped language name if name then -- when <name>, <lang_param> is a tag for a remapped language name if cfg.lang_name_remap[name:lower()][2] ~= lang_param_lc then utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added return name, cfg.lang_name_remap[name:lower()][2]; -- so return name and tag from lang_name_remap[name]; special case to xlate sr-ec and sr-el to sr-cyrl and sr-latn end return name, lang_param_lc; -- so return <name> from remap and <lang_param_lc> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- still assuming that <lang_param_lc> is a tag; strip script, region, variant subtags name = cfg.lang_tag_remap[tag]; -- attempt to get remapped language name with language subtag only if name then -- when <name>, <tag> is a tag for a remapped language name return name, tag; -- so return <name> from remap and <tag> end if cfg.lang_name_remap[lang_param_lc] then -- not a remapped tag, assume <lang_param_lc> is a name; attempt to get remapped language tag return cfg.lang_name_remap[lang_param_lc][1], cfg.lang_name_remap[lang_param_lc][2]; -- for this <lang_param_lc>, return a (possibly) new name and appropriate tag end name = cfg.mw_languages_by_tag_t[lang_param_lc]; -- assume that <lang_param_lc> is a tag; attempt to get its matching language name if name then return name, lang_param_lc; -- <lang_param_lc> is a tag so return it and <name> end tag = cfg.mw_languages_by_name_t[lang_param_lc]; -- assume that <lang_param_lc> is a language name; attempt to get its matching tag if tag then return cfg.mw_languages_by_tag_t[tag], tag; -- <lang_param_lc> is a name so return the name from the table and <tag> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- is <lang_param_lc> an IETF-like tag that MediaWiki doesn't recognize? <tag> gets the language subtag; nil else if tag then name = cfg.mw_languages_by_tag_t[tag]; -- attempt to get a language name using the shortened <tag> if name then return name, tag; -- <lang_param_lc> is an unrecognized IETF-like tag so return <name> and language subtag end end end --[[-------------------< L A N G U A G E _ P A R A M E T E R >------------------ Gets language name from a provided two- or three-character ISO 639 code. If a code is recognized by MediaWiki, use the returned name; if not, then use the value that was provided with the language parameter. When |language= contains a recognized language (either code or name), the page is assigned to the category for that code: Category:Norwegian-language sources (no). For valid three-character code languages, the page is assigned to the single category for '639-2' codes: Category:CS1 ISO 639-2 language sources. Languages that are the same as the local wiki are not categorized. MediaWiki does not recognize three-character equivalents of two-character codes: code 'ar' is recognized but code 'ara' is not. This function supports multiple languages in the form |language=nb, French, th where the language names or codes are separated from each other by commas with optional space characters. ]] local function language_parameter (lang) local tag; -- some form of IETF-like language tag; language subtag with optional region, sript, vatiant, etc subtags local lang_subtag; -- ve populates |language= with mostly unecessary region subtags the MediaWiki does not recognize; this is the base language subtag local name; -- the language name local language_list = {}; -- table of language names to be rendered local names_t = {}; -- table made from the value assigned to |language= local this_wiki_name = mw.language.fetchLanguageName (cfg.this_wiki_code, cfg.this_wiki_code); -- get this wiki's language name names_t = mw.text.split (lang, '%s*,%s*'); -- names should be a comma separated list for _, lang in ipairs (names_t) do -- reuse lang here because we don't yet know if lang is a language name or a language tag name, tag = name_tag_get (lang); -- attempt to get name/tag pair for <lang>; <name> has proper capitalization; <tag> is lowercase if utilities.is_set (tag) then lang_subtag = tag:gsub ('^(%a%a%a?)%-.*', '%1'); -- for categorization, strip any IETF-like tags from language tag if cfg.this_wiki_code ~= lang_subtag then -- when the language is not the same as this wiki's language if 2 == lang_subtag:len() then -- and is a two-character tag utilities.add_prop_cat ('foreign-lang-source', {name, tag}, lang_subtag); -- categorize it; tag appended to allow for multiple language categorization else -- or is a recognized language (but has a three-character tag) utilities.add_prop_cat ('foreign-lang-source-2', {lang_subtag}, lang_subtag); -- categorize it differently TODO: support multiple three-character tag categories per cs1|2 template? end elseif cfg.local_lang_cat_enable then -- when the language and this wiki's language are the same and categorization is enabled utilities.add_prop_cat ('local-lang-source', {name, lang_subtag}); -- categorize it end else name = lang; -- return whatever <lang> has so that we show something utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added end table.insert (language_list, name); name = ''; -- so we can reuse it end name = utilities.make_sep_list (#language_list, language_list); if (1 == #language_list) and (lang_subtag == cfg.this_wiki_code) then -- when only one language, find lang name in this wiki lang name; for |language=en-us, 'English' in 'American English' return ''; -- if one language and that language is this wiki's return an empty string (no annotation) end return (" " .. wrap_msg ('language', name)); -- otherwise wrap with '(in ...)' --[[ TODO: should only return blank or name rather than full list so we can clean up the bunched parenthetical elements Language, Type, Format ]] end --[[-----------------------< S E T _ C S _ S T Y L E >-------------------------- Gets the default CS style configuration for the given mode. Returns default separator and either postscript as passed in or the default. In CS1, the default postscript and separator are '.'. In CS2, the default postscript is the empty string and the default separator is ','. ]] local function set_cs_style (postscript, mode) if utilities.is_set(postscript) then -- emit a maintenance message if user postscript is the default cs1 postscript -- we catch the opposite case for cs2 in set_style if mode == 'cs1' and postscript == cfg.presentation['ps_' .. mode] then utilities.set_message ('maint_postscript'); end else postscript = cfg.presentation['ps_' .. mode]; end return cfg.presentation['sep_' .. mode], postscript; end --[[--------------------------< S E T _ S T Y L E >----------------------------- Sets the separator and postscript styles. Checks the |mode= first and the #invoke CitationClass second. Removes the postscript if postscript == none. ]] local function set_style (mode, postscript, cite_class) local sep; if 'cs2' == mode then sep, postscript = set_cs_style (postscript, 'cs2'); elseif 'cs1' == mode then sep, postscript = set_cs_style (postscript, 'cs1'); elseif 'citation' == cite_class then sep, postscript = set_cs_style (postscript, 'cs2'); else sep, postscript = set_cs_style (postscript, 'cs1'); end if cfg.keywords_xlate[postscript:lower()] == 'none' then -- emit a maintenance message if user postscript is the default cs2 postscript -- we catch the opposite case for cs1 in set_cs_style if 'cs2' == mode or ('cs1' ~= mode and 'citation' == cite_class) then -- {{citation |title=Title |mode=cs1 |postscript=none}} should not emit maint message utilities.set_message ('maint_postscript'); end postscript = ''; end return sep, postscript end --[=[-------------------------< I S _ P D F >----------------------------------- Determines if a URL has the file extension that is one of the PDF file extensions used by [[MediaWiki:Common.css]] when applying the PDF icon to external links. returns true if file extension is one of the recognized extensions, else false ]=] local function is_pdf (url) return url:match ('%.pdf$') or url:match ('%.PDF$') or url:match ('%.pdf[%?#]') or url:match ('%.PDF[%?#]') or url:match ('%.PDF&#035') or url:match ('%.pdf&#035'); end --[[--------------------------< S T Y L E _ F O R M A T >----------------------- Applies CSS style to |format=, |chapter-format=, etc. Also emits an error message if the format parameter does not have a matching URL parameter. If the format parameter is not set and the URL contains a file extension that is recognized as a PDF document by MediaWiki's commons.css, this code will set the format parameter to (PDF) with the appropriate styling. ]] local function style_format (format, url, fmt_param, url_param) if utilities.is_set (format) then format = utilities.wrap_style ('format', format); -- add leading space, parentheses, resize if not utilities.is_set (url) then utilities.set_message ('err_format_missing_url', {fmt_param, url_param}); -- add an error message end elseif is_pdf (url) then -- format is not set so if URL is a PDF file then format = utilities.wrap_style ('format', 'PDF'); -- set format to PDF else format = ''; -- empty string for concatenation end return format; end --[[---------------------< G E T _ D I S P L A Y _ N A M E S >------------------ Returns a number that defines the number of names displayed for author and editor name lists and a Boolean flag to indicate when et al. should be appended to the name list. When the value assigned to |display-xxxxors= is a number greater than or equal to zero, return the number and the previous state of the 'etal' flag (false by default but may have been set to true if the name list contains some variant of the text 'et al.'). When the value assigned to |display-xxxxors= is the keyword 'etal', return a number that is one greater than the number of authors in the list and set the 'etal' flag true. This will cause the list_people() to display all of the names in the name list followed by 'et al.' In all other cases, returns nil and the previous state of the 'etal' flag. inputs: max: A['DisplayAuthors'] or A['DisplayEditors'], etc; a number or some flavor of etal count: #a or #e list_name: 'authors' or 'editors' etal: author_etal or editor_etal This function sets an error message when |display-xxxxors= value greater than or equal to number of names but not when <max> comes from {{cs1 config}} global settings. When using global settings, <param> is set to the keyword 'cs1 config' which is used to supress the normal error. Error is suppressed because it is to be expected that some citations in an article will have the same or fewer names that the limit specified in {{cs1 config}}. ]] local function get_display_names (max, count, list_name, etal, param) if utilities.is_set (max) then if 'etal' == max:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings max = count + 1; -- number of authors + 1 so display all author name plus et al. etal = true; -- overrides value set by extract_names() elseif max:match ('^%d+$') then -- if is a string of numbers max = tonumber (max); -- make it a number if (max >= count) and ('cs1 config' ~= param) then -- error when local |display-xxxxors= value greater than or equal to number of names; not an error when using global setting utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; end else -- not a valid keyword or number utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; -- unset; as if |display-xxxxors= had not been set end end return max, etal; end --[[----------< E X T R A _ T E X T _ I N _ P A G E _ C H E C K >--------------- Adds error if |page=, |pages=, |quote-page=, |quote-pages= has what appears to be some form of p. or pp. abbreviation in the first characters of the parameter content. check page for extraneous p, p., pp, pp., pg, pg. at start of parameter value: good pattern: '^P[^%.P%l]' matches when page begins PX or P# but not Px where x and X are letters and # is a digit bad pattern: '^[Pp][PpGg]' matches when page begins pp, pP, Pp, PP, pg, pG, Pg, PG ]] local function extra_text_in_page_check (val, name) if not val:match (cfg.vol_iss_pg_patterns.good_ppattern) then for _, pattern in ipairs (cfg.vol_iss_pg_patterns.bad_ppatterns) do -- spin through the selected sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message ('err_extra_text_pages', name); -- add error message return; -- and done end end end end --[[--------------------------< E X T R A _ T E X T _ I N _ V O L _ I S S _ C H E C K >------------------------ Adds error if |volume= or |issue= has what appears to be some form of redundant 'type' indicator. Applies to both; this function looks for issue text in both |issue= and |volume= and looks for volume-like text in |voluem= and |issue=. For |volume=: 'V.', or 'Vol.' (with or without the dot) abbreviations or 'Volume' in the first characters of the parameter content (all case insensitive). 'V' and 'v' (without the dot) are presumed to be roman numerals so are allowed. For |issue=: 'No.', 'I.', 'Iss.' (with or without the dot) abbreviations, or 'Issue' in the first characters of the parameter content (all case insensitive); numero styling: 'n°' with degree sign U+00B0, and № precomposed numero sign U+2116. Single character values ('v', 'i', 'n') allowed when not followed by separator character ('.', ':', '=', or whitespace character) – param values are trimmed of whitespace by MediaWiki before delivered to the module. <val> is |volume= or |issue= parameter value <name> is |volume= or |issue= parameter name for error message <selector> is 'v' for |volume=, 'i' for |issue= sets error message on failure; returns nothing ]] local function extra_text_in_vol_iss_check (val, name, selector) if not utilities.is_set (val) then return; end local handler = 'v' == selector and 'err_extra_text_volume' or 'err_extra_text_issue'; val = val:lower(); -- force parameter value to lower case for _, pattern in ipairs (cfg.vol_iss_pg_patterns.vi_patterns_t) do -- spin through the sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message (handler, name); -- add error message return; -- and done end end end --[=[-------------------------< G E T _ V _ N A M E _ T A B L E >---------------------------------------------- split apart a |vauthors= or |veditors= parameter. This function allows for corporate names, wrapped in doubled parentheses to also have commas; in the old version of the code, the doubled parentheses were included in the rendered citation and in the metadata. Individual author names may be wikilinked |vauthors=Jones AB, [[E. B. White|White EB]], ((Black, Brown, and Co.)) ]=] local function get_v_name_table (vparam, output_table, output_link_table) local _, accept = utilities.has_accept_as_written (vparam); if accept then utilities.add_prop_cat ('vanc-accept'); -- add properties category end local name_table = mw.text.split(vparam, "%s*,%s*"); -- names are separated by commas local wl_type, label, link; -- wl_type not used here; just a placeholder local i = 1; while name_table[i] do if name_table[i]:match ('^%(%(.*[^%)][^%)]$') then -- first segment of corporate with one or more commas; this segment has the opening doubled parentheses local name = name_table[i]; i = i + 1; -- bump indexer to next segment while name_table[i] do name = name .. ', ' .. name_table[i]; -- concatenate with previous segments if name_table[i]:match ('^.*%)%)$') then -- if this table member has the closing doubled parentheses break; -- and done reassembling so end i = i + 1; -- bump indexer end table.insert (output_table, name); -- and add corporate name to the output table table.insert (output_link_table, ''); -- no wikilink else wl_type, label, link = utilities.is_wikilink (name_table[i]); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] table.insert (output_table, label); -- add this name if 1 == wl_type then table.insert (output_link_table, label); -- simple wikilink [[D]] else table.insert (output_link_table, link); -- no wikilink or [[L|D]]; add this link if there is one, else empty string end end i = i + 1; end return output_table; end --[[--------------------------< P A R S E _ V A U T H O R S _ V E D I T O R S >-------------------------------- This function extracts author / editor names from |vauthors= or |veditors= and finds matching |xxxxor-maskn= and |xxxxor-linkn= in args. It then returns a table of assembled names just as extract_names() does. Author / editor names in |vauthors= or |veditors= must be in Vancouver system style. Corporate or institutional names may sometimes be required and because such names will often fail the is_good_vanc_name() and other format compliance tests, are wrapped in doubled parentheses ((corporate name)) to suppress the format tests. Supports generational suffixes Jr, 2nd, 3rd, 4th–6th. This function sets the Vancouver error when a required comma is missing and when there is a space between an author's initials. ]] local function parse_vauthors_veditors (args, vparam, list_name) local names = {}; -- table of names assembled from |vauthors=, |author-maskn=, |author-linkn= local v_name_table = {}; local v_link_table = {}; -- when name is wikilinked, targets go in this table local etal = false; -- return value set to true when we find some form of et al. vauthors parameter local last, first, link, mask, suffix; local corporate = false; vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period) v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); -- names are separated by commas for i, v_name in ipairs(v_name_table) do first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor local accept_name; v_name, accept_name = utilities.has_accept_as_written (v_name); -- remove accept-this-as-written markup when it wraps all of <v_name> if accept_name then last = v_name; corporate = true; -- flag used in list_people() elseif string.find(v_name, "%s") then if v_name:find('[;%.]') then -- look for commonly occurring punctuation characters; add_vanc_error (cfg.err_msg_supl.punctuation, i); end local lastfirstTable = {} lastfirstTable = mw.text.split(v_name, "%s+") first = table.remove(lastfirstTable); -- removes and returns value of last element in table which should be initials or generational suffix if not mw.ustring.match (first, '^%u+$') then -- mw.ustring here so that later we will catch non-Latin characters suffix = first; -- not initials so assume that whatever we got is a generational suffix first = table.remove(lastfirstTable); -- get what should be the initials from the table end last = table.concat(lastfirstTable, ' ') -- returns a string that is the concatenation of all other names that are not initials and generational suffix if not utilities.is_set (last) then first = ''; -- unset last = v_name; -- last empty because something wrong with first add_vanc_error (cfg.err_msg_supl.name, i); end if mw.ustring.match (last, '%a+%s+%u+%s+%a+') then add_vanc_error (cfg.err_msg_supl['missing comma'], i); -- matches last II last; the case when a comma is missing end if mw.ustring.match (v_name, ' %u %u$') then -- this test is in the wrong place TODO: move or replace with a more appropriate test add_vanc_error (cfg.err_msg_supl.initials, i); -- matches a space between two initials end else last = v_name; -- last name or single corporate name? Doesn't support multiword corporate names? do we need this? end if utilities.is_set (first) then if not mw.ustring.match (first, "^%u?%u$") then -- first shall contain one or two upper-case letters, nothing else add_vanc_error (cfg.err_msg_supl.initials, i); -- too many initials; mixed case initials (which may be ok Romanization); hyphenated initials end is_good_vanc_name (last, first, suffix, i); -- check first and last before restoring the suffix which may have a non-Latin digit if utilities.is_set (suffix) then first = first .. ' ' .. suffix; -- if there was a suffix concatenate with the initials suffix = ''; -- unset so we don't add this suffix to all subsequent names end else if not corporate then is_good_vanc_name (last, '', nil, i); end end link = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ) or v_link_table[i]; mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); names[i] = {last = last, first = first, link = link, mask = mask, corporate = corporate}; -- add this assembled name to our names list end return names, etal; -- all done, return our list of names end --[[--------------------------< S E L E C T _ A U T H O R _ E D I T O R _ S O U R C E >------------------------ Select one of |authors=, |authorn= / |lastn / firstn=, or |vauthors= as the source of the author name list or select one of |editorn= / editor-lastn= / |editor-firstn= or |veditors= as the source of the editor name list. Only one of these appropriate three will be used. The hierarchy is: |authorn= (and aliases) highest and |authors= lowest; |editorn= (and aliases) highest and |veditors= lowest (support for |editors= withdrawn) When looking for |authorn= / |editorn= parameters, test |xxxxor1= and |xxxxor2= (and all of their aliases); stops after the second test which mimicks the test used in extract_names() when looking for a hole in the author name list. There may be a better way to do this, I just haven't discovered what that way is. Emits an error message when more than one xxxxor name source is provided. In this function, vxxxxors = vauthors or veditors; xxxxors = authors as appropriate. ]] local function select_author_editor_source (vxxxxors, xxxxors, args, list_name) local lastfirst = false; if utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 1 ) or -- do this twice in case we have a |first1= without a |last1=; this ... utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 1 ) or -- ... also catches the case where |first= is used with |vauthors= utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 2 ) or utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 2 ) then lastfirst = true; end if (utilities.is_set (vxxxxors) and true == lastfirst) or -- these are the three error conditions (utilities.is_set (vxxxxors) and utilities.is_set (xxxxors)) or (true == lastfirst and utilities.is_set (xxxxors)) then local err_name; if 'AuthorList' == list_name then -- figure out which name should be used in error message err_name = 'author'; else err_name = 'editor'; end utilities.set_message ('err_redundant_parameters', err_name .. '-name-list parameters'); -- add error message end if true == lastfirst then return 1 end; -- return a number indicating which author name source to use if utilities.is_set (vxxxxors) then return 2 end; if utilities.is_set (xxxxors) then return 3 end; return 1; -- no authors so return 1; this allows missing author name test to run in case there is a first without last end --[[--------------------------< I S _ V A L I D _ P A R A M E T E R _ V A L U E >------------------------------ This function is used to validate a parameter's assigned value for those parameters that have only a limited number of allowable values (yes, y, true, live, dead, etc.). When the parameter value has not been assigned a value (missing or empty in the source template) the function returns the value specified by ret_val. If the parameter value is one of the list of allowed values returns the translated value; else, emits an error message and returns the value specified by ret_val. TODO: explain <invert> ]] local function is_valid_parameter_value (value, name, possible, ret_val, invert) if not utilities.is_set (value) then return ret_val; -- an empty parameter is ok end if (not invert and utilities.in_array (value, possible)) then -- normal; <value> is in <possible> table return cfg.keywords_xlate[value]; -- return translation of parameter keyword elseif invert and not utilities.in_array (value, possible) then -- invert; <value> is not in <possible> table return value; -- return <value> as it is else utilities.set_message ('err_invalid_param_val', {name, value}); -- not an allowed value so add error message return ret_val; end end --[[--------------------------< T E R M I N A T E _ N A M E _ L I S T >---------------------------------------- This function terminates a name list (author, contributor, editor) with a separator character (sepc) and a space when the last character is not a sepc character or when the last three characters are not sepc followed by two closing square brackets (close of a wikilink). When either of these is true, the name_list is terminated with a single space character. ]] local function terminate_name_list (name_list, sepc) if (string.sub (name_list, -3, -1) == sepc .. '. ') then -- if already properly terminated return name_list; -- just return the name list elseif (string.sub (name_list, -1, -1) == sepc) or (string.sub (name_list, -3, -1) == sepc .. ']]') then -- if last name in list ends with sepc char return name_list .. " "; -- don't add another else return name_list .. sepc .. ' '; -- otherwise terminate the name list end end --[[-------------------------< F O R M A T _ V O L U M E _ I S S U E >----------------------------------------- returns the concatenation of the formatted volume and issue (or journal article number) parameters as a single string; or formatted volume or formatted issue, or an empty string if neither are set. ]] local function format_volume_issue (volume, issue, article, cite_class, origin, sepc, lower) if not utilities.is_set (volume) and not utilities.is_set (issue) and not utilities.is_set (article) then return ''; end -- same condition as in format_pages_sheets() local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); local is_numeric_vol = volume and (volume:match ('^[MDCLXVI]+$') or volume:match ('^%d+$')); -- is only uppercase roman numerals or only digits? local is_long_vol = volume and (4 < mw.ustring.len(volume)); -- is |volume= value longer than 4 characters? if volume and (not is_numeric_vol and is_long_vol) then -- when not all digits or Roman numerals, is |volume= longer than 4 characters? utilities.add_prop_cat ('long-vol'); -- yes, add properties cat end if is_journal then -- journal-style formatting local vol = ''; if utilities.is_set (volume) then if is_numeric_vol then -- |volume= value all digits or all uppercase Roman numerals? vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, volume}); -- render in bold face elseif is_long_vol then -- not all digits or Roman numerals; longer than 4 characters? vol = utilities.substitute (cfg.messages['j-vol'], {sepc, utilities.hyphen_to_dash (volume)}); -- not bold else -- four or fewer characters vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, utilities.hyphen_to_dash (volume)}); -- bold end end vol = vol .. (utilities.is_set (issue) and utilities.substitute (cfg.messages['j-issue'], issue) or '') vol = vol .. (utilities.is_set (article) and utilities.substitute (cfg.messages['j-article-num'], article) or '') return vol; end if 'podcast' == cite_class and utilities.is_set (issue) then return wrap_msg ('issue', {sepc, issue}, lower); end if 'conference' == cite_class and utilities.is_set (article) then -- |article-number= supported only in journal and conference cites if utilities.is_set (volume) and utilities.is_set (article) then -- both volume and article number return wrap_msg ('vol-art', {sepc, utilities.hyphen_to_dash (volume), article}, lower); elseif utilities.is_set (article) then -- article number alone; when volume alone, handled below return wrap_msg ('art', {sepc, article}, lower); end end -- all other types of citation if utilities.is_set (volume) and utilities.is_set (issue) then return wrap_msg ('vol-no', {sepc, utilities.hyphen_to_dash (volume), issue}, lower); elseif utilities.is_set (volume) then return wrap_msg ('vol', {sepc, utilities.hyphen_to_dash (volume)}, lower); else return wrap_msg ('issue', {sepc, issue}, lower); end end --[[-------------------------< F O R M A T _ P A G E S _ S H E E T S >----------------------------------------- adds static text to one of |page(s)= or |sheet(s)= values and returns it with all of the others set to empty strings. The return order is: page, pages, sheet, sheets Singular has priority over plural when both are provided. ]] local function format_pages_sheets (page, pages, sheet, sheets, cite_class, origin, sepc, nopp, lower) if 'map' == cite_class then -- only cite map supports sheet(s) as in-source locators if utilities.is_set (sheet) then if 'journal' == origin then return '', '', wrap_msg ('j-sheet', sheet, lower), ''; else return '', '', wrap_msg ('sheet', {sepc, sheet}, lower), ''; end elseif utilities.is_set (sheets) then if 'journal' == origin then return '', '', '', wrap_msg ('j-sheets', sheets, lower); else return '', '', '', wrap_msg ('sheets', {sepc, sheets}, lower); end end end local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); if utilities.is_set (page) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], page), '', '', ''; elseif not nopp then return utilities.substitute (cfg.messages['p-prefix'], {sepc, page}), '', '', ''; else return utilities.substitute (cfg.messages['nopp'], {sepc, page}), '', '', ''; end elseif utilities.is_set (pages) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], pages), '', '', ''; elseif tonumber(pages) ~= nil and not nopp then -- if pages is only digits, assume a single page number return '', utilities.substitute (cfg.messages['p-prefix'], {sepc, pages}), '', ''; elseif not nopp then return '', utilities.substitute (cfg.messages['pp-prefix'], {sepc, pages}), '', ''; else return '', utilities.substitute (cfg.messages['nopp'], {sepc, pages}), '', ''; end end return '', '', '', ''; -- return empty strings end --[[--------------------------< I N S O U R C E _ L O C _ G E T >---------------------------------------------- returns one of the in-source locators: page, pages, or at. If any of these are interwiki links to Wikisource, returns the label portion of the interwiki-link as plain text for use in COinS. This COinS thing is done because here we convert an interwiki-link to an external link and add an icon span around that; get_coins_pages() doesn't know about the span. TODO: should it? TODO: add support for sheet and sheets?; streamline; TODO: make it so that this function returns only one of the three as the single in-source (the return value assigned to a new name)? ]] local function insource_loc_get (page, page_orig, pages, pages_orig, at) local ws_url, ws_label, coins_pages, L; -- for Wikisource interwiki-links; TODO: this corrupts page metadata (span remains in place after cleanup; fix there?) if utilities.is_set (page) then if utilities.is_set (pages) or utilities.is_set (at) then pages = ''; -- unset the others at = ''; end extra_text_in_page_check (page, page_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (page); -- make ws URL from |page= interwiki link; link portion L becomes tooltip label if ws_url then page = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in page'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? page = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, page}); coins_pages = ws_label; end elseif utilities.is_set (pages) then if utilities.is_set (at) then at = ''; -- unset end extra_text_in_page_check (pages, pages_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (pages); -- make ws URL from |pages= interwiki link; link portion L becomes tooltip label if ws_url then pages = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in pages'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? pages = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, pages}); coins_pages = ws_label; end elseif utilities.is_set (at) then ws_url, ws_label, L = wikisource_url_make (at); -- make ws URL from |at= interwiki link; link portion L becomes tooltip label if ws_url then at = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in at'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? at = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, at}); coins_pages = ws_label; end end return page, pages, at, coins_pages; end --[[--------------------------< I S _ U N I Q U E _ A R C H I V E _ U R L >------------------------------------ add error message when |archive-url= value is same as |url= or chapter-url= (or alias...) value ]] local function is_unique_archive_url (archive, url, c_url, source, date) if utilities.is_set (archive) then if archive == url or archive == c_url then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); -- add error message return '', ''; -- unset |archive-url= and |archive-date= because same as |url= or |chapter-url= end end return archive, date; end --[=[-------------------------< A R C H I V E _ U R L _ C H E C K >-------------------------------------------- Check archive.org URLs to make sure they at least look like they are pointing at valid archives and not to the save snapshot URL or to calendar pages. When the archive URL is 'https://web.archive.org/save/' (or http://...) archive.org saves a snapshot of the target page in the URL. That is something that Wikipedia should not allow unwitting readers to do. When the archive.org URL does not have a complete timestamp, archive.org chooses a snapshot according to its own algorithm or provides a calendar 'search' result. [[WP:ELNO]] discourages links to search results. This function looks at the value assigned to |archive-url= and returns empty strings for |archive-url= and |archive-date= and an error message when: |archive-url= holds an archive.org save command URL |archive-url= is an archive.org URL that does not have a complete timestamp (YYYYMMDDhhmmss 14 digits) in the correct place otherwise returns |archive-url= and |archive-date= There are two mostly compatible archive.org URLs: //web.archive.org/<timestamp>... -- the old form //web.archive.org/web/<timestamp>... -- the new form The old form does not support or map to the new form when it contains a display flag. There are four identified flags ('id_', 'js_', 'cs_', 'im_') but since archive.org ignores others following the same form (two letters and an underscore) we don't check for these specific flags but we do check the form. This function supports a preview mode. When the article is rendered in preview mode, this function may return a modified archive URL: for save command errors, return undated wildcard (/*/) for timestamp errors when the timestamp has a wildcard, return the URL unmodified for timestamp errors when the timestamp does not have a wildcard, return with timestamp limited to six digits plus wildcard (/yyyymm*/) A secondary function is to return an archive-url timestamp from those urls that have them (archive.org and archive.today). The timestamp is used by validation.archive_date_check() to see if the value in |archive-date= matches the timestamp in the archive url. ]=] local function archive_url_check (url, date) local err_msg = ''; -- start with the error message empty local path, timestamp, flag; -- portions of the archive.org URL timestamp = url:match ('//archive.today/(%d%d%d%d%d%d%d%d%d%d%d%d%d%d)/') or -- get timestamp from archive.today urls url:match ('//archive.today/(%d%d%d%d%.%d%d%.%d%d%-%d%d%d%d%d%d)/'); -- this timestamp needs cleanup if timestamp then -- if this was an archive.today url ... return url, date, timestamp:gsub ('[%.%-]', ''); -- return ArchiveURL, ArchiveDate, and timestamp (dots and dashes removed) from |archive-url=, and done end -- here for archive.org urls if (not url:match('//web%.archive%.org/')) and (not url:match('//liveweb%.archive%.org/')) then -- also deprecated liveweb Wayback machine URL return url, date; -- not an archive.org archive, return ArchiveURL and ArchiveDate end if url:match('//web%.archive%.org/save/') then -- if a save command URL, we don't want to allow saving of the target page err_msg = cfg.err_msg_supl.save; url = url:gsub ('(//web%.archive%.org)/save/', '%1/*/', 1); -- for preview mode: modify ArchiveURL elseif url:match('//liveweb%.archive%.org/') then err_msg = cfg.err_msg_supl.liveweb; else path, timestamp, flag = url:match('//web%.archive%.org/([^%d]*)(%d+)([^/]*)/'); -- split out some of the URL parts for evaluation if not path then -- malformed in some way; pattern did not match err_msg = cfg.err_msg_supl.timestamp; elseif 14 ~= timestamp:len() then -- path and flag optional, must have 14-digit timestamp here err_msg = cfg.err_msg_supl.timestamp; if '*' ~= flag then local replacement = timestamp:match ('^%d%d%d%d%d%d') or timestamp:match ('^%d%d%d%d'); -- get the first 6 (YYYYMM) or first 4 digits (YYYY) if replacement then -- nil if there aren't at least 4 digits (year) replacement = replacement .. string.rep ('0', 14 - replacement:len()); -- year or yearmo (4 or 6 digits) zero-fill to make 14-digit timestamp url=url:gsub ('(//web%.archive%.org/[^%d]*)%d[^/]*', '%1' .. replacement .. '*', 1) -- for preview, modify ts to 14 digits plus splat for calendar display end end elseif utilities.is_set (path) and 'web/' ~= path then -- older archive URLs do not have the extra 'web/' path element err_msg = cfg.err_msg_supl.path; elseif utilities.is_set (flag) and not utilities.is_set (path) then -- flag not allowed with the old form URL (without the 'web/' path element) err_msg = cfg.err_msg_supl.flag; elseif utilities.is_set (flag) and not flag:match ('%a%a_') then -- flag if present must be two alpha characters and underscore (requires 'web/' path element) err_msg = cfg.err_msg_supl.flag; else return url, date, timestamp; -- return ArchiveURL, ArchiveDate, and timestamp from |archive-url= end end -- if here, something not right so utilities.set_message ('err_archive_url', {err_msg}); -- add error message and if is_preview_mode then return url, date, timestamp; -- preview mode so return ArchiveURL, ArchiveDate, and timestamp from |archive-url= else return '', ''; -- return empty strings for ArchiveURL and ArchiveDate end end --[[--------------------------< P L A C E _ C H E C K >-------------------------------------------------------- check |place=, |publication-place=, |location= to see if these params include digits. This function added because many editors misuse location to specify the in-source location (|page(s)= and |at= are supposed to do that) returns the original parameter value without modification; added maint cat when parameter value contains digits ]] local function place_check (param_val) if not utilities.is_set (param_val) then -- parameter empty or omitted return param_val; -- return that empty state end if mw.ustring.find (param_val, '%d') then -- not empty, are there digits in the parameter value utilities.set_message ('maint_location'); -- yep, add maint cat end return param_val; -- and done end --[[--------------------------< I S _ A R C H I V E D _ C O P Y >---------------------------------------------- compares |title= to 'Archived copy' (placeholder added by bots that can't find proper title); if matches, return true; nil else ]] local function is_archived_copy (title) title = mw.ustring.lower(title); -- switch title to lower case if title:find (cfg.special_case_translation.archived_copy.en) then -- if title is 'Archived copy' return true; elseif cfg.special_case_translation.archived_copy['local'] then if mw.ustring.find (title, cfg.special_case_translation.archived_copy['local']) then -- mw.ustring() because might not be Latin script return true; end end end --[[--------------------------< D I S P L A Y _ N A M E S _ S E L E C T >-------------------------------------- for any of the |display-authors=, |display-editors=, etc parameters, select either the local or global setting. When both are present, look at <local_display_names> value. When the value is some sort of 'et al.'string, special handling is required. When {{cs1 config}} has |display-<namelist>= AND this template has |display-<namelist>=etal AND: the number of names specified by <number_of_names> is: greater than the number specified in the global |display-<namelist>= parameter (<global_display_names>) use global |display-<namelist>= parameter value set overridden maint category less than or equal to the number specified in the global |display-<namelist>= parameter use local |display-<namelist>= parameter value The purpose of this function is to prevent categorizing a template that has fewer names than the global setting to keep the etal annotation specified by <local_display_names>. ]] local function display_names_select (global_display_names, local_display_names, param_name, number_of_names, test) if global_display_names and utilities.is_set (local_display_names) then -- when both if 'etal' == local_display_names:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings number_of_names = tonumber (number_of_names); -- convert these to numbers for comparison local global_display_names_num = tonumber (global_display_names); -- <global_display_names> not set when parameter value is not digits if number_of_names > global_display_names_num then -- template has more names than global config allows to be displayed? utilities.set_message ('maint_overridden_setting'); -- set a maint message because global is overriding local |display-<namelist>=etal return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local because fewer names so let <local_display_names> control end end -- here when <global_display_names> and <local_display_names> both numbers; <global_display_names> controls utilities.set_message ('maint_overridden_setting'); -- set a maint message return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) end -- here when only one of <global_display_names> or <local_display_names> set if global_display_names then return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local end end --[[--------------------------< M O D E _ S E T >-------------------------------------------------------------- fetch global mode setting from {{cs1 config}} (if present) or from |mode= (if present); global setting overrides local |mode= parameter value. When both are present, emit maintenance message ]] local function mode_set (Mode, Mode_origin) local mode; if cfg.global_cs1_config_t['Mode'] then -- global setting in {{cs1 config}}; nil when empty or assigned value invalid mode = is_valid_parameter_value (cfg.global_cs1_config_t['Mode'], 'cs1 config: mode', cfg.keywords_lists['mode'], ''); -- error messaging 'param' here is a hoax else mode = is_valid_parameter_value (Mode, Mode_origin, cfg.keywords_lists['mode'], ''); end if cfg.global_cs1_config_t['Mode'] and utilities.is_set (Mode) then -- when template has |mode=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end return mode; end --[[--------------------------< Q U O T E _ M A K E >---------------------------------------------------------- create quotation from |quote=, |trans-quote=, and/or script-quote= with or without |quote-page= or |quote-pages= when any of those three quote parameters are set, this function unsets <PostScript>. When none of those parameters are set, |quote-page= and |quote-pages= are unset to nil so that they are not included in the template's metadata ]] local function quote_make (quote, trans_quote, script_quote, quote_page, quote_pages, nopp, sepc, postscript) if utilities.is_set (quote) or utilities.is_set (trans_quote) or utilities.is_set (script_quote) then if utilities.is_set (quote) then if quote:sub(1, 1) == '"' and quote:sub(-1, -1) == '"' then -- if first and last characters of quote are quote marks quote = quote:sub(2, -2); -- strip them off end end quote = kern_quotes (quote); -- kern if needed quote = utilities.wrap_style ('quoted-text', quote ); -- wrap in <q>...</q> tags if utilities.is_set (script_quote) then quote = script_concatenate (quote, script_quote, 'script-quote'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after quote is wrapped end if utilities.is_set (trans_quote) then if trans_quote:sub(1, 1) == '"' and trans_quote:sub(-1, -1) == '"' then -- if first and last characters of |trans-quote are quote marks trans_quote = trans_quote:sub(2, -2); -- strip them off end quote = quote .. " " .. utilities.wrap_style ('trans-quoted-title', trans_quote ); end if utilities.is_set (quote_page) or utilities.is_set (quote_pages) then -- add page prefix local quote_prefix = ''; if utilities.is_set (quote_page) then extra_text_in_page_check (quote_page, 'quote-page'); -- add to maint cat if |quote-page= value begins with what looks like p., pp., etc. if not nopp then quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_page}), '', '', ''; else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_page}), '', '', ''; end elseif utilities.is_set (quote_pages) then extra_text_in_page_check (quote_pages, 'quote-pages'); -- add to maint cat if |quote-pages= value begins with what looks like p., pp., etc. if tonumber(quote_pages) ~= nil and not nopp then -- if only digits, assume single page quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_pages}), '', ''; elseif not nopp then quote_prefix = utilities.substitute (cfg.messages['pp-prefix'], {sepc, quote_pages}), '', ''; else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_pages}), '', ''; end end quote = quote_prefix .. ": " .. quote; else quote = sepc .. " " .. quote; end postscript = ""; -- cs1|2 does not supply terminal punctuation when |quote= is set elseif utilities.is_set (quote_page) or utilities.is_set (quote_pages) then quote_page = nil; -- unset; these require |quote=; TODO: error message? quote_pages = nil; end return quote, quote_page, quote_pages, postscript; end --[[--------------------------< C H E C K _ P U B L I S H E R _ N A M E >-------------------------------------- look for variations of '<text>: <text>' that might be '<location>: <publisher>' in |publisher= parameter value. when found, emit a maintenance message; return nil else <publisher> is the value assigned to |publisher= or |institution= ]] local function check_publisher_name (publisher) local patterns_t = { '^[%w%s]+%s*:%s*[%w%s]+$', -- plain text <location>: <publisher> '^%[+[%w%s:|]+%]+%s*:%s*[%w%s]+$', -- partially wikilinked [[<location>]]: <publisher> '^[%w%s]+%s*:%s*%[+[%w%s:|]+%]+$', -- partially wikilinked <location>: [[<publisher>]] '^%[+[%w%s:|]+%]+%s*:%s*%[+[%w%s:|]+%]+$', -- wikilinked [[<location>]]: [[<publisher>]] } for _, pattern in ipairs (patterns_t) do -- spin through the patterns_t sequence if mw.ustring.match (publisher, pattern) then -- does this pattern match? utilities.set_message ('maint_publisher_location'); -- set a maint message return; -- and done end end end --[[--------------------------< I S _ P A G E _ A R T _ N U M >------------------------------------------------ compare the trailing (rightmost) characters of the |doi= value against the whole value assigned to |page(s)=. return boolean true when: |page(s)= has exactly 8 digits and a dot between the fourth and fifth digits matches the trailing 9 characters of the |doi= value: |page=12345678 → |page=1234.5678 matches |doi=10.xxxx/yyyy1234.5678 |page(s)= is 5 or more characters and matches |doi= values's trailing characters |page(s)= begins with a lowercase 'e' and |page(s)= without the 'e' matches |doi= values's trailing characters: |page=e12345 → |page=12345 matches |doi=10.xxxx/yyyy12345 |page(s)= begins with a uppercase 'CD' followed by (typically) six digits matches |doi= values that ends with 'CDxxxxxx.pubx' (where 'x' is any single digit) return nil when |page(s)= values: are ranges separated by underscore, hyphen, emdash, endash, figure dash, or minus character are comma- or semicolon-separated lists of pages have external urls (has text 'http') are digit-only values less than 10000 do not match |doi= values's trailing characters ]] local function is_page_art_num (page, doi) if not (utilities.is_set (page) and utilities.is_set (doi)) then -- both required return; -- abandon; nothing to do end if page:match ('[,;_−–—‒%-]') then -- when |page(s)= might be a page range or a separated list of pages return; -- abandon end page = page:lower(); -- because doi names are case insensitive doi = doi:lower(); -- force these to lowercase for testing if page:match ('http') then -- when |page(s)= appears to hold a url return; -- abandon end if tonumber (page) then -- is |page(s)= digits only if 10000 > tonumber (page) then -- when |page(s)= less than 10000 return; -- abandon end if doi:match (page .. '$') then -- digits only page number match the last digits in |doi=? return true; end if 8 == page:len() then -- special case when |page(s)= is exactly 8 digits local dot_page = page:gsub ('(%d%d%d%d)(%d%d%d%d)', '%1.%2'); -- make a |page=xxxx.yyyy version commonly used in |doi= if doi:match (dot_page .. '$') then -- 8-digit dotted page number match the last characters in |doi=? return true; end end else -- here when |page(s)= is alpha-numeric if 4 < page:len() then -- when |page(s)= is five or more characters if doi:match (page .. '$') then -- alpha-numeric page match the last characters in |doi=? return true; end local epage = page:match ('^e([%w]+)$'); -- if first character of |page= is 'e', remove it if epage and doi:match (epage .. '$') then -- page number match the last characters in |doi=? return true; end local cdpage = page:match ('^cd%d+$'); -- if first characters of |page= are 'CD' and last characters are digits (typically 6 digits) if cdpage and doi:match (cdpage .. '%.pub%d$') then -- page number matches doi 'CDxxxxxx.pubx' where 'x' is a digit return true; end end end end --[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------ This is the main function doing the majority of the citation formatting. ]] local function citation0( config, args ) --[[ Load Input Parameters The argument_wrapper facilitates the mapping of multiple aliases to single internal variable. ]] local A = argument_wrapper ( args ); local i -- Pick out the relevant fields from the arguments. Different citation templates -- define different field names for the same underlying things. local author_etal; local a = {}; -- authors list from |lastn= / |firstn= pairs or |vauthors= local Authors; local NameListStyle; if cfg.global_cs1_config_t['NameListStyle'] then -- global setting in {{cs1 config}} overrides local |name-list-style= parameter value; nil when empty or assigned value invalid NameListStyle = is_valid_parameter_value (cfg.global_cs1_config_t['NameListStyle'], 'cs1 config: name-list-style', cfg.keywords_lists['name-list-style'], ''); -- error messaging 'param' here is a hoax else NameListStyle = is_valid_parameter_value (A['NameListStyle'], A:ORIGIN('NameListStyle'), cfg.keywords_lists['name-list-style'], ''); end if cfg.global_cs1_config_t['NameListStyle'] and utilities.is_set (A['NameListStyle']) then -- when template has |name-list-style=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end local Collaboration = A['Collaboration']; do -- to limit scope of selected local selected = select_author_editor_source (A['Vauthors'], A['Authors'], args, 'AuthorList'); if 1 == selected then a, author_etal = extract_names (args, 'AuthorList'); -- fetch author list from |authorn= / |lastn= / |firstn=, |author-linkn=, and |author-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be a, author_etal = parse_vauthors_veditors (args, A['Vauthors'], 'AuthorList'); -- fetch author list from |vauthors=, |author-linkn=, and |author-maskn= elseif 3 == selected then Authors = A['Authors']; -- use content of |people= or |credits=; |authors= is deprecated; TODO: constrain |people= and |credits= to cite av media, episode, serial? end if utilities.is_set (Collaboration) then author_etal = true; -- so that |display-authors=etal not required end end local editor_etal; local e = {}; -- editors list from |editor-lastn= / |editor-firstn= pairs or |veditors= do -- to limit scope of selected local selected = select_author_editor_source (A['Veditors'], nil, args, 'EditorList'); -- support for |editors= withdrawn if 1 == selected then e, editor_etal = extract_names (args, 'EditorList'); -- fetch editor list from |editorn= / |editor-lastn= / |editor-firstn=, |editor-linkn=, and |editor-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be e, editor_etal = parse_vauthors_veditors (args, args.veditors, 'EditorList'); -- fetch editor list from |veditors=, |editor-linkn=, and |editor-maskn= end end local Chapter = A['Chapter']; -- done here so that we have access to |contribution= from |chapter= aliases local Chapter_origin = A:ORIGIN ('Chapter'); local Contribution; -- because contribution is required for contributor(s) if 'contribution' == Chapter_origin then Contribution = Chapter; -- get the name of the contribution end local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (A['Periodical']) then -- |contributor= and |contribution= only supported in book cites c = extract_names (args, 'ContributorList'); -- fetch contributor list from |contributorn= / |contributor-lastn=, -firstn=, -linkn=, -maskn= if 0 < #c then if not utilities.is_set (Contribution) then -- |contributor= requires |contribution= utilities.set_message ('err_contributor_missing_required_param', 'contribution'); -- add missing contribution error message c = {}; -- blank the contributors' table; it is used as a flag later end if 0 == #a then -- |contributor= requires |author= utilities.set_message ('err_contributor_missing_required_param', 'author'); -- add missing author error message c = {}; -- blank the contributors' table; it is used as a flag later end end else -- if not a book cite if utilities.select_one (args, cfg.aliases['ContributorList-Last'], 'err_redundant_parameters', 1 ) then -- are there contributor name list parameters? utilities.set_message ('err_contributor_ignored'); -- add contributor ignored error message end Contribution = nil; -- unset end local Title = A['Title']; local TitleLink = A['TitleLink']; local auto_select = ''; -- default is auto local accept_link; TitleLink, accept_link = utilities.has_accept_as_written (TitleLink, true); -- test for accept-this-as-written markup if (not accept_link) and utilities.in_array (TitleLink, {'none', 'pmc', 'doi'}) then -- check for special keywords auto_select = TitleLink; -- remember selection for later TitleLink = ''; -- treat as if |title-link= would have been empty end TitleLink = link_title_ok (TitleLink, A:ORIGIN ('TitleLink'), Title, 'title'); -- check for wiki-markup in |title-link= or wiki-markup in |title= when |title-link= is set local Section = ''; -- {{cite map}} only; preset to empty string for concatenation if not used if 'map' == config.CitationClass and 'section' == Chapter_origin then Section = A['Chapter']; -- get |section= from |chapter= alias list; |chapter= and the other aliases not supported in {{cite map}} Chapter = ''; -- unset for now; will be reset later from |map= if present end local Periodical = A['Periodical']; local Periodical_origin = A:ORIGIN('Periodical'); local ScriptPeriodical = A['ScriptPeriodical']; local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical'); local TransPeriodical = A['TransPeriodical']; local TransPeriodical_origin = A:ORIGIN ('TransPeriodical'); if (utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical))) then local param; if utilities.is_set (Periodical) then -- get a parameter name from one of these periodical related meta-parameters Periodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = Periodical_origin -- get parameter name for error messaging elseif utilities.is_set (TransPeriodical) then TransPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = TransPeriodical_origin; -- get parameter name for error messaging elseif utilities.is_set (ScriptPeriodical) then ScriptPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = ScriptPeriodical_origin; -- get parameter name for error messaging end if utilities.is_set (param) then -- if we found one utilities.set_message ('err_periodical_ignored', {param}); -- emit an error message end end if utilities.is_set (Periodical) then local i; Periodical, i = utilities.strip_apostrophe_markup (Periodical); -- strip apostrophe markup so that metadata isn't contaminated if i then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {Periodical_origin}); end end if 'mailinglist' == config.CitationClass then -- special case for {{cite mailing list}} if utilities.is_set (Periodical) and utilities.is_set (A ['MailingList']) then -- both set emit an error TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', Periodical_origin) .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'mailinglist')}); end Periodical = A ['MailingList']; -- error or no, set Periodical to |mailinglist= value because this template is {{cite mailing list}} Periodical_origin = A:ORIGIN('MailingList'); end -- web and news not tested for now because of -- Wikipedia:Administrators%27_noticeboard#Is_there_a_semi-automated_tool_that_could_fix_these_annoying_"Cite_Web"_errors? if not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) then -- 'periodical' templates require periodical parameter -- local p = {['journal'] = 'journal', ['magazine'] = 'magazine', ['news'] = 'newspaper', ['web'] = 'website'}; -- for error message local p = {['journal'] = 'journal', ['magazine'] = 'magazine'}; -- for error message if p[config.CitationClass] then utilities.set_message ('err_missing_periodical', {config.CitationClass, p[config.CitationClass]}); end end local Volume; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) then if not utilities.in_array (Periodical_origin, cfg.citation_no_volume_t) then -- {{citation}} does not render |volume= when these parameters are used Volume = A['Volume']; -- but does for all other 'periodicals' end elseif utilities.is_set (ScriptPeriodical) then if 'script-website' ~= ScriptPeriodical_origin then -- {{citation}} does not render volume for |script-website= Volume = A['Volume']; -- but does for all other 'periodicals' end else Volume = A['Volume']; -- and does for non-'periodical' cites end elseif utilities.in_array (config.CitationClass, cfg.templates_using_volume) then -- render |volume= for cs1 according to the configuration settings Volume = A['Volume']; end extra_text_in_vol_iss_check (Volume, A:ORIGIN ('Volume'), 'v'); local Issue; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) and utilities.in_array (Periodical_origin, cfg.citation_issue_t) then -- {{citation}} may render |issue= when these parameters are used Issue = utilities.hyphen_to_dash (A['Issue']); end elseif utilities.in_array (config.CitationClass, cfg.templates_using_issue) then -- conference & map books do not support issue; {{citation}} listed here because included in settings table if not (utilities.in_array (config.CitationClass, {'conference', 'map', 'citation'}) and not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical))) then Issue = utilities.hyphen_to_dash (A['Issue']); end end local ArticleNumber; if utilities.in_array (config.CitationClass, {'journal', 'conference'}) or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then ArticleNumber = A['ArticleNumber']; end extra_text_in_vol_iss_check (Issue, A:ORIGIN ('Issue'), 'i'); local Page; local Pages; local At; local QuotePage; local QuotePages; if not utilities.in_array (config.CitationClass, cfg.templates_not_using_page) then -- TODO: rewrite to emit ignored parameter error message? Page = A['Page']; Pages = utilities.hyphen_to_dash (A['Pages']); At = A['At']; QuotePage = A['QuotePage']; QuotePages = utilities.hyphen_to_dash (A['QuotePages']); end local NoPP = is_valid_parameter_value (A['NoPP'], A:ORIGIN('NoPP'), cfg.keywords_lists['yes_true_y'], nil); local Mode = mode_set (A['Mode'], A:ORIGIN('Mode')); -- separator character and postscript local sepc, PostScript = set_style (Mode:lower(), A['PostScript'], config.CitationClass); local Quote; Quote, QuotePage, QuotePages, PostScript = quote_make (A['Quote'], A['TransQuote'], A['ScriptQuote'], QuotePage, QuotePages, NoPP, sepc, PostScript); local Edition = A['Edition']; local PublicationPlace = place_check (A['PublicationPlace'], A:ORIGIN('PublicationPlace')); local Place = place_check (A['Place'], A:ORIGIN('Place')); local PublisherName = A['PublisherName']; local PublisherName_origin = A:ORIGIN('PublisherName'); if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then local i = 0; PublisherName, i = utilities.strip_apostrophe_markup (PublisherName); -- strip apostrophe markup so that metadata isn't contaminated; publisher is never italicized if i and (0 < i) then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {PublisherName_origin}); end end if ('document' == config.CitationClass) and not utilities.is_set (PublisherName) then utilities.set_message ('err_missing_publisher', {config.CitationClass, 'publisher'}); end local Newsgroup = A['Newsgroup']; -- TODO: strip apostrophe markup? local Newsgroup_origin = A:ORIGIN('Newsgroup'); if 'newsgroup' == config.CitationClass then if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then -- general use parameter |publisher= not allowed in cite newsgroup utilities.set_message ('err_parameter_ignored', {PublisherName_origin}); end PublisherName = nil; -- ensure that this parameter is unset for the time being; will be used again after COinS end if 'book' == config.CitationClass or 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then local accept; PublisherName, accept = utilities.has_accept_as_written (PublisherName); -- check for and remove accept-as-written markup from |publisher= wrapped if not accept then -- when no accept-as-written markup check_publisher_name (PublisherName); -- emit maint message when |publisher= might be prefixed with publisher's location end end local URL = A['URL']; -- TODO: better way to do this for URL, ChapterURL, and MapURL? local UrlAccess = is_valid_parameter_value (A['UrlAccess'], A:ORIGIN('UrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (URL) and utilities.is_set (UrlAccess) then UrlAccess = nil; utilities.set_message ('err_param_access_requires_param', 'url'); end local ChapterURL = A['ChapterURL']; local ChapterUrlAccess = is_valid_parameter_value (A['ChapterUrlAccess'], A:ORIGIN('ChapterUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (ChapterURL) and utilities.is_set (ChapterUrlAccess) then ChapterUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {A:ORIGIN('ChapterUrlAccess'):gsub ('%-access', '')}); end local MapUrlAccess = is_valid_parameter_value (A['MapUrlAccess'], A:ORIGIN('MapUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (A['MapURL']) and utilities.is_set (MapUrlAccess) then MapUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {'map-url'}); end local this_page = mw.title.getCurrentTitle(); -- also used for COinS and for language local no_tracking_cats = is_valid_parameter_value (A['NoTracking'], A:ORIGIN('NoTracking'), cfg.keywords_lists['yes_true_y'], nil); -- check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories if not utilities.is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page if cfg.uncategorized_namespaces[this_page.namespace] then -- is this page's namespace id one of the uncategorized namespace ids? no_tracking_cats = "true"; -- set no_tracking_cats end for _, v in ipairs (cfg.uncategorized_subpages) do -- cycle through page name patterns if this_page.text:match (v) then -- test page name against each pattern no_tracking_cats = "true"; -- set no_tracking_cats break; -- bail out if one is found end end end -- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it) utilities.select_one (args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'err_redundant_parameters'); -- this is a dummy call simply to get the error message and category local coins_pages; Page, Pages, At, coins_pages = insource_loc_get (Page, A:ORIGIN('Page'), Pages, A:ORIGIN('Pages'), At); if utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- both |publication-place= and |place= (|location=) allowed if different utilities.add_prop_cat ('location-test'); -- add property cat to evaluate how often PublicationPlace and Place are used together if PublicationPlace == Place then Place = ''; -- unset; don't need both if they are the same end elseif not utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- when only |place= (|location=) is set ... PublicationPlace = Place; -- promote |place= (|location=) to |publication-place end if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same local URL_origin = A:ORIGIN('URL'); -- get name of parameter that holds URL local ChapterURL_origin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL local ScriptChapter = A['ScriptChapter']; local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); local Format = A['Format']; local ChapterFormat = A['ChapterFormat']; local TransChapter = A['TransChapter']; local TransChapter_origin = A:ORIGIN ('TransChapter'); local TransTitle = A['TransTitle']; local ScriptTitle = A['ScriptTitle']; --[[ Parameter remapping for cite encyclopedia: When the citation has these parameters: |encyclopedia= and |title= then map |title= to |article= and |encyclopedia= to |title= for rendering |encyclopedia= and |article= then map |encyclopedia= to |title= for rendering |trans-title= maps to |trans-chapter= when |title= is re-mapped |url= maps to |chapter-url= when |title= is remapped All other combinations of |encyclopedia=, |title=, and |article= are not modified ]] local Encyclopedia = A['Encyclopedia']; -- used as a flag by this module and by ~/COinS local ScriptEncyclopedia = A['ScriptEncyclopedia']; local TransEncyclopedia = A['TransEncyclopedia']; if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then -- emit error message when Encyclopedia set but template is other than {{cite encyclopedia}} or {{citation}} if 'encyclopaedia' ~= config.CitationClass and 'citation' ~= config.CitationClass then if utilities.is_set (Encyclopedia) then utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('Encyclopedia')}); else utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('ScriptEncyclopedia')}); end Encyclopedia = nil; -- unset these because not supported by this template ScriptEncyclopedia = nil; TransEncyclopedia = nil; end elseif utilities.is_set (TransEncyclopedia) then utilities.set_message ('err_trans_missing_title', {'encyclopedia'}); end if ('encyclopaedia' == config.CitationClass) or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Periodical) and utilities.is_set (Encyclopedia) then -- when both parameters set emit an error message; {{citation}} only; Periodical not allowed in {{cite encyclopedia}} utilities.set_message ('err_periodical_ignored', {Periodical_origin}); end if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then Periodical = Encyclopedia; -- error or no, set Periodical to Encyclopedia for rendering; {{citation}} could (not legitimately) have both; use Encyclopedia Periodical_origin = A:ORIGIN ('Encyclopedia'); ScriptPeriodical = ScriptEncyclopedia; ScriptPeriodical_origin = A:ORIGIN ('ScriptEncyclopedia'); if utilities.is_set (Title) or utilities.is_set (ScriptTitle) then if not utilities.is_set (Chapter) then Chapter = Title; -- |encyclopedia= and |title= are set so map |title= params to |article= params for rendering ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle') TransChapter = TransTitle; ChapterURL = URL; ChapterURL_origin = URL_origin; ChapterUrlAccess = UrlAccess; ChapterFormat = Format; if not utilities.is_set (ChapterURL) and utilities.is_set (TitleLink) then Chapter = utilities.make_wikilink (TitleLink, Chapter); end Title = Periodical; -- now map |encyclopedia= params to |title= params for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; URL = ''; Format = ''; TitleLink = ''; end elseif utilities.is_set (Chapter) or utilities.is_set (ScriptChapter) then -- |title= not set Title = Periodical; -- |encyclopedia= set and |article= set so map |encyclopedia= to |title= for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; end end end -- special case for cite techreport. local ID = A['ID']; if (config.CitationClass == "techreport") then -- special case for cite techreport if utilities.is_set (A['Number']) then -- cite techreport uses 'number', which other citations alias to 'issue' if not utilities.is_set (ID) then -- can we use ID for the "number"? ID = A['Number']; -- yes, use it else -- ID has a value so emit error message utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'id') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'number')}); end end end -- Account for the oddity that is {{cite conference}}, before generation of COinS data. local ChapterLink -- = A['ChapterLink']; -- deprecated as a parameter but still used internally by cite episode local Conference = A['Conference']; local BookTitle = A['BookTitle']; local TransTitle_origin = A:ORIGIN ('TransTitle'); if 'conference' == config.CitationClass then if utilities.is_set (BookTitle) then Chapter = Title; Chapter_origin = 'title'; -- ChapterLink = TitleLink; -- |chapter-link= is deprecated ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; URL_origin = ''; ChapterFormat = Format; TransChapter = TransTitle; TransChapter_origin = TransTitle_origin; Title = BookTitle; Format = ''; -- TitleLink = ''; TransTitle = ''; URL = ''; end elseif 'speech' ~= config.CitationClass then Conference = ''; -- not cite conference or cite speech so make sure this is empty string end local use_lowercase = ( sepc == ',' ); -- controls capitalization of certain static text -- cite map oddities local Cartography = ""; local Scale = ""; local Sheet = A['Sheet'] or ''; local Sheets = A['Sheets'] or ''; if config.CitationClass == "map" then if utilities.is_set (Chapter) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'map') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', Chapter_origin)}); -- add error message end Chapter = A['Map']; Chapter_origin = A:ORIGIN('Map'); ChapterURL = A['MapURL']; ChapterURL_origin = A:ORIGIN('MapURL'); TransChapter = A['TransMap']; ScriptChapter = A['ScriptMap'] ScriptChapter_origin = A:ORIGIN('ScriptMap') ChapterUrlAccess = MapUrlAccess; ChapterFormat = A['MapFormat']; Cartography = A['Cartography']; if utilities.is_set ( Cartography ) then Cartography = sepc .. " " .. wrap_msg ('cartography', Cartography, use_lowercase); end Scale = A['Scale']; if utilities.is_set ( Scale ) then Scale = sepc .. " " .. Scale; end end -- Account for the oddities that are {{cite episode}} and {{cite serial}}, before generation of COinS data. local Series = A['Series']; if 'episode' == config.CitationClass or 'serial' == config.CitationClass then local SeriesLink = A['SeriesLink']; SeriesLink = link_title_ok (SeriesLink, A:ORIGIN ('SeriesLink'), Series, 'series'); -- check for wiki-markup in |series-link= or wiki-markup in |series= when |series-link= is set local Network = A['Network']; local Station = A['Station']; local s, n = {}, {}; -- do common parameters first if utilities.is_set (Network) then table.insert(n, Network); end if utilities.is_set (Station) then table.insert(n, Station); end ID = table.concat(n, sepc .. ' '); if 'episode' == config.CitationClass then -- handle the oddities that are strictly {{cite episode}} local Season = A['Season']; local SeriesNumber = A['SeriesNumber']; if utilities.is_set (Season) and utilities.is_set (SeriesNumber) then -- these are mutually exclusive so if both are set TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'season') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'seriesno')}); -- add error message SeriesNumber = ''; -- unset; prefer |season= over |seriesno= end -- assemble a table of parts concatenated later into Series if utilities.is_set (Season) then table.insert(s, wrap_msg ('season', Season, use_lowercase)); end if utilities.is_set (SeriesNumber) then table.insert(s, wrap_msg ('seriesnum', SeriesNumber, use_lowercase)); end if utilities.is_set (Issue) then table.insert(s, wrap_msg ('episode', Issue, use_lowercase)); end Issue = ''; -- unset because this is not a unique parameter Chapter = Title; -- promote title parameters to chapter ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle'); ChapterLink = TitleLink; -- alias |episode-link= TransChapter = TransTitle; ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; ChapterFormat = Format; Title = Series; -- promote series to title TitleLink = SeriesLink; Series = table.concat(s, sepc .. ' '); -- this is concatenation of season, seriesno, episode number if utilities.is_set (ChapterLink) and not utilities.is_set (ChapterURL) then -- link but not URL Chapter = utilities.make_wikilink (ChapterLink, Chapter); elseif utilities.is_set (ChapterLink) and utilities.is_set (ChapterURL) then -- if both are set, URL links episode; Series = utilities.make_wikilink (ChapterLink, Series); end URL = ''; -- unset TransTitle = ''; ScriptTitle = ''; Format = ''; else -- now oddities that are cite serial Issue = ''; -- unset because this parameter no longer supported by the citation/core version of cite serial Chapter = A['Episode']; -- TODO: make |episode= available to cite episode someday? if utilities.is_set (Series) and utilities.is_set (SeriesLink) then Series = utilities.make_wikilink (SeriesLink, Series); end Series = utilities.wrap_style ('italic-title', Series); -- series is italicized end end -- end of {{cite episode}} stuff -- handle type parameter for those CS1 citations that have default values local TitleType = A['TitleType']; local Degree = A['Degree']; if utilities.in_array (config.CitationClass, {'AV-media-notes', 'document', 'interview', 'mailinglist', 'map', 'podcast', 'pressrelease', 'report', 'speech', 'techreport', 'thesis'}) then TitleType = set_titletype (config.CitationClass, TitleType); if utilities.is_set (Degree) and "Thesis" == TitleType then -- special case for cite thesis TitleType = Degree .. ' ' .. cfg.title_types ['thesis']:lower(); end end if utilities.is_set (TitleType) then -- if type parameter is specified TitleType = utilities.substitute ( cfg.messages['type'], TitleType); -- display it in parentheses -- TODO: Hack on TitleType to fix bunched parentheses problem end -- legacy: promote PublicationDate to Date if neither Date nor Year are set. local Date = A['Date']; local Date_origin; -- to hold the name of parameter promoted to Date; required for date error messaging local PublicationDate = A['PublicationDate']; local Year = A['Year']; if utilities.is_set (Year) then validation.year_check (Year); -- returns nothing; emits maint message when |year= doesn't hold a 'year' value end if not utilities.is_set (Date) then Date = Year; -- promote Year to Date Year = nil; -- make nil so Year as empty string isn't used for CITEREF if not utilities.is_set (Date) and utilities.is_set (PublicationDate) then -- use PublicationDate when |date= and |year= are not set Date = PublicationDate; -- promote PublicationDate to Date PublicationDate = ''; -- unset, no longer needed Date_origin = A:ORIGIN('PublicationDate'); -- save the name of the promoted parameter else Date_origin = A:ORIGIN('Year'); -- save the name of the promoted parameter end else Date_origin = A:ORIGIN('Date'); -- not a promotion; name required for error messaging end if PublicationDate == Date then PublicationDate = ''; end -- if PublicationDate is same as Date, don't display in rendered citation --[[ Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates. This must be done before we do COinS because here is where we get the date used in the metadata. Date validation supporting code is in Module:Citation/CS1/Date_validation ]] local DF = is_valid_parameter_value (A['DF'], A:ORIGIN('DF'), cfg.keywords_lists['df'], ''); if not utilities.is_set (DF) then DF = cfg.global_df; -- local |df= if present overrides global df set by {{use xxx date}} template end local ArchiveURL; local ArchiveDate; local ArchiveFormat = A['ArchiveFormat']; local archive_url_timestamp; -- timestamp from wayback machine url ArchiveURL, ArchiveDate, archive_url_timestamp = archive_url_check (A['ArchiveURL'], A['ArchiveDate']) ArchiveFormat = style_format (ArchiveFormat, ArchiveURL, 'archive-format', 'archive-url'); ArchiveURL, ArchiveDate = is_unique_archive_url (ArchiveURL, URL, ChapterURL, A:ORIGIN('ArchiveURL'), ArchiveDate); -- add error message when URL or ChapterURL == ArchiveURL local AccessDate = A['AccessDate']; local COinS_date = {}; -- holds date info extracted from |date= for the COinS metadata by Module:Date verification local DoiBroken = A['DoiBroken']; local Embargo = A['Embargo']; local anchor_year; -- used in the CITEREF identifier do -- create defined block to contain local variables error_message, date_parameters_list, mismatch local error_message = ''; -- AirDate has been promoted to Date so not necessary to check it local date_parameters_list = { ['access-date'] = {val = AccessDate, name = A:ORIGIN ('AccessDate')}, ['archive-date'] = {val = ArchiveDate, name = A:ORIGIN ('ArchiveDate')}, ['date'] = {val = Date, name = Date_origin}, ['doi-broken-date'] = {val = DoiBroken, name = A:ORIGIN ('DoiBroken')}, ['pmc-embargo-date'] = {val = Embargo, name = A:ORIGIN ('Embargo')}, ['publication-date'] = {val = PublicationDate, name = A:ORIGIN ('PublicationDate')}, ['year'] = {val = Year, name = A:ORIGIN ('Year')}, }; local error_list = {}; anchor_year, Embargo = validation.dates(date_parameters_list, COinS_date, error_list); if utilities.is_set (Year) and utilities.is_set (Date) then -- both |date= and |year= not normally needed; validation.year_date_check (Year, A:ORIGIN ('Year'), Date, A:ORIGIN ('Date'), error_list); end if 0 == #error_list then -- error free dates only; 0 when error_list is empty local modified = false; -- flag if utilities.is_set (DF) then -- if we need to reformat dates modified = validation.reformat_dates (date_parameters_list, DF); -- reformat to DF format, use long month names if appropriate end if true == validation.date_hyphen_to_dash (date_parameters_list) then -- convert hyphens to dashes where appropriate modified = true; utilities.set_message ('maint_date_format'); -- hyphens were converted so add maint category end -- for those wikis that can and want to have English date names translated to the local language; not supported at en.wiki if cfg.date_name_auto_xlate_enable and validation.date_name_xlate (date_parameters_list, cfg.date_digit_auto_xlate_enable ) then utilities.set_message ('maint_date_auto_xlated'); -- add maint cat modified = true; end if modified then -- if the date_parameters_list values were modified AccessDate = date_parameters_list['access-date'].val; -- overwrite date holding parameters with modified values ArchiveDate = date_parameters_list['archive-date'].val; Date = date_parameters_list['date'].val; DoiBroken = date_parameters_list['doi-broken-date'].val; PublicationDate = date_parameters_list['publication-date'].val; end if archive_url_timestamp and utilities.is_set (ArchiveDate) then validation.archive_date_check (ArchiveDate, archive_url_timestamp, DF); -- does YYYYMMDD in archive_url_timestamp match date in ArchiveDate end else utilities.set_message ('err_bad_date', {utilities.make_sep_list (#error_list, error_list)}); -- add this error message end end -- end of do if utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) or -- {{cite book}}, {{cite encyclopedia}}; TODO: {{cite conference}} and others? ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) or -- {{citation}} as an encylopedia citation ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then -- {{citation}} as a book citation if utilities.is_set (PublicationPlace) then if not utilities.is_set (PublisherName) then local date = COinS_date.rftdate and tonumber (COinS_date.rftdate:match ('%d%d%d%d')); -- get year portion of COinS date (because in Arabic numerals); convert string to number if date and (1850 <= date) then -- location has no publisher; if date is 1850 or later utilities.set_message ('maint_location_no_publisher'); -- add maint cat end else -- PublisherName has a value if cfg.keywords_xlate['none'] == PublisherName then -- if that value is 'none' (only for book and encyclopedia citations) PublisherName = ''; -- unset end end end end local ID_list = {}; -- sequence table of rendered identifiers local ID_list_coins = {}; -- table of identifiers and their values from args; key is same as cfg.id_handlers's key local Class = A['Class']; -- arxiv class identifier local ID_support = { {A['ASINTLD'], 'ASIN', 'err_asintld_missing_asin', A:ORIGIN ('ASINTLD')}, {DoiBroken, 'DOI', 'err_doibroken_missing_doi', A:ORIGIN ('DoiBroken')}, {Embargo, 'PMC', 'err_embargo_missing_pmc', A:ORIGIN ('Embargo')}, } ID_list, ID_list_coins = identifiers.identifier_lists_get (args, { DoiBroken = DoiBroken, -- for |doi= ASINTLD = A['ASINTLD'], -- for |asin= Embargo = Embargo, -- for |pmc= Class = Class, -- for |arxiv= CitationClass = config.CitationClass, -- for |arxiv= Year=anchor_year, -- for |isbn= }, ID_support); -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, {{cite ssrn}}, before generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv=, |citeseerx=, |medrxiv=, |ssrn= required for their templates if not (args[cfg.id_handlers[config.CitationClass:upper()].parameters[1]] or -- can't use ID_list_coins k/v table here because invalid parameters omitted args[cfg.id_handlers[config.CitationClass:upper()].parameters[2]]) then -- which causes unexpected parameter missing error message utilities.set_message ('err_' .. config.CitationClass .. '_missing'); -- add error message end Periodical = ({['arxiv'] = 'arXiv', ['biorxiv'] = 'bioRxiv', ['citeseerx'] = 'CiteSeerX', ['medrxiv'] = 'medRxiv', ['ssrn'] = 'Social Science Research Network'})[config.CitationClass]; end -- Link the title of the work if no |url= was provided, but we have a |pmc= or a |doi= with |doi-access=free if config.CitationClass == "journal" and not utilities.is_set (URL) and not utilities.is_set (TitleLink) and not utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) then -- TODO: remove 'none' once existing citations have been switched to 'off', so 'none' can be used as token for "no title" instead if 'none' ~= cfg.keywords_xlate[auto_select] then -- if auto-linking not disabled if identifiers.auto_link_urls[auto_select] then -- manual selection URL = identifiers.auto_link_urls[auto_select]; -- set URL to be the same as identifier's external link URL_origin = cfg.id_handlers[auto_select:upper()].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['pmc'] then -- auto-select PMC URL = identifiers.auto_link_urls['pmc']; -- set URL to be the same as the PMC external link if not embargoed URL_origin = cfg.id_handlers['PMC'].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['doi'] then -- auto-select DOI URL = identifiers.auto_link_urls['doi']; URL_origin = cfg.id_handlers['DOI'].parameters[1]; end end if utilities.is_set (URL) then -- set when using an identifier-created URL if utilities.is_set (AccessDate) then -- |access-date= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_accessdate_missing_url'); -- add an error message AccessDate = ''; -- unset end if utilities.is_set (ArchiveURL) then -- |archive-url= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_archive_missing_url'); -- add an error message ArchiveURL = ''; -- unset end end end -- At this point fields may be nil if they weren't specified in the template use. We can use that fact. -- Test if citation has no title if not utilities.is_set (Title) and not utilities.is_set (TransTitle) and not utilities.is_set (ScriptTitle) then -- has special case for cite episode utilities.set_message ('err_citation_missing_title', {'episode' == config.CitationClass and 'series' or 'title'}); end if utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) and utilities.in_array (config.CitationClass, {'journal', 'citation'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and ('journal' == Periodical_origin or 'script-journal' == ScriptPeriodical_origin) then -- special case for journal cites Title = ''; -- set title to empty string utilities.set_message ('maint_untitled'); -- add maint cat end if 'journal' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then if is_page_art_num (Page or Pages, ID_list_coins['DOI']) then -- does |page(s)= look like it holds an article number utilities.set_message ('maint_page_art_num'); -- add maint cat end end -- COinS metadata (see <http://ocoins.info/>) for automated parsing of citation information. -- handle the oddity that is cite encyclopedia and {{citation |encyclopedia=something}}. Here we presume that -- when Periodical, Title, and Chapter are all set, then Periodical is the book (encyclopedia) title, Title -- is the article title, and Chapter is a section within the article. So, we remap local coins_chapter = Chapter; -- default assuming that remapping not required local coins_title = Title; -- et tu if 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Chapter) and utilities.is_set (Title) and utilities.is_set (Periodical) then -- if all are used then coins_chapter = Title; -- remap coins_title = Periodical; end end local coins_author = a; -- default for coins rft.au if 0 < #c then -- but if contributor list coins_author = c; -- use that instead end -- this is the function call to COinS() local OCinSoutput = metadata.COinS({ ['Periodical'] = utilities.strip_apostrophe_markup (Periodical), -- no markup in the metadata ['Encyclopedia'] = Encyclopedia, -- just a flag; content ignored by ~/COinS ['Chapter'] = metadata.make_coins_title (coins_chapter, ScriptChapter), -- Chapter and ScriptChapter stripped of bold / italic / accept-as-written markup ['Degree'] = Degree; -- cite thesis only ['Title'] = metadata.make_coins_title (coins_title, ScriptTitle), -- Title and ScriptTitle stripped of bold / italic / accept-as-written markup ['PublicationPlace'] = PublicationPlace, ['Date'] = COinS_date.rftdate, -- COinS_date.* has correctly formatted date values if Date is valid; ['Season'] = COinS_date.rftssn, ['Quarter'] = COinS_date.rftquarter, ['Chron'] = COinS_date.rftchron, ['Series'] = Series, ['Volume'] = Volume, ['Issue'] = Issue, ['ArticleNumber'] = ArticleNumber, ['Pages'] = coins_pages or metadata.get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At, QuotePage, QuotePages}, 7)), -- pages stripped of external links ['Edition'] = Edition, ['PublisherName'] = PublisherName or Newsgroup, -- any apostrophe markup already removed from PublisherName ['URL'] = first_set ({ChapterURL, URL}, 2), ['Authors'] = coins_author, ['ID_list'] = ID_list_coins, ['RawPage'] = this_page.prefixedText, }, config.CitationClass); -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, and {{cite ssrn}} AFTER generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- we have set rft.jtitle in COinS to arXiv, bioRxiv, CiteSeerX, medRxiv, or ssrn now unset so it isn't displayed Periodical = ''; -- periodical not allowed in these templates; if article has been published, use cite journal end -- special case for cite newsgroup. Do this after COinS because we are modifying Publishername to include some static text if 'newsgroup' == config.CitationClass and utilities.is_set (Newsgroup) then PublisherName = utilities.substitute (cfg.messages['newsgroup'], external_link( 'news:' .. Newsgroup, Newsgroup, Newsgroup_origin, nil )); end local Editors; local EditorCount; -- used only for choosing {ed.) or (eds.) annotation at end of editor name-list local Contributors; -- assembled contributors name list local contributor_etal; local Translators; -- assembled translators name list local translator_etal; local t = {}; -- translators list from |translator-lastn= / translator-firstn= pairs t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= local Interviewers; local interviewers_list = {}; interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters local interviewer_etal; -- Now perform various field substitutions. -- We also add leading spaces and surrounding markup and punctuation to the -- various parts of the citation, but only when they are non-nil. do local last_first_list; local control = { format = NameListStyle, -- empty string, '&', 'amp', 'and', or 'vanc' maximum = nil, -- as if display-authors or display-editors not set mode = Mode }; do -- do editor name list first because the now unsupported coauthors used to modify control table local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayEditors'], A['DisplayEditors'], A:ORIGIN ('DisplayEditors'), #e); control.maximum, editor_etal = get_display_names (display_names, #e, 'editors', editor_etal, param); Editors, EditorCount = list_people (control, e, editor_etal); if 1 == EditorCount and (true == editor_etal or 1 < #e) then -- only one editor displayed but includes etal then EditorCount = 2; -- spoof to display (eds.) annotation end end do -- now do interviewers local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayInterviewers'], A['DisplayInterviewers'], A:ORIGIN ('DisplayInterviewers'), #interviewers_list); control.maximum, interviewer_etal = get_display_names (display_names, #interviewers_list, 'interviewers', interviewer_etal, param); Interviewers = list_people (control, interviewers_list, interviewer_etal); end do -- now do translators local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayTranslators'], A['DisplayTranslators'], A:ORIGIN ('DisplayTranslators'), #t); control.maximum, translator_etal = get_display_names (display_names, #t, 'translators', translator_etal, param); Translators = list_people (control, t, translator_etal); end do -- now do contributors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayContributors'], A['DisplayContributors'], A:ORIGIN ('DisplayContributors'), #c); control.maximum, contributor_etal = get_display_names (display_names, #c, 'contributors', contributor_etal, param); Contributors = list_people (control, c, contributor_etal); end do -- now do authors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayAuthors'], A['DisplayAuthors'], A:ORIGIN ('DisplayAuthors'), #a, author_etal); control.maximum, author_etal = get_display_names (display_names, #a, 'authors', author_etal, param); last_first_list = list_people (control, a, author_etal); if utilities.is_set (Authors) then Authors, author_etal = name_has_etal (Authors, author_etal, false, 'authors'); -- find and remove variations on et al. if author_etal then Authors = Authors .. ' ' .. cfg.messages['et al']; -- add et al. to authors parameter end else Authors = last_first_list; -- either an author name list or an empty string end end -- end of do if utilities.is_set (Authors) and utilities.is_set (Collaboration) then Authors = Authors .. ' (' .. Collaboration .. ')'; -- add collaboration after et al. end end local ConferenceFormat = A['ConferenceFormat']; local ConferenceURL = A['ConferenceURL']; ConferenceFormat = style_format (ConferenceFormat, ConferenceURL, 'conference-format', 'conference-url'); Format = style_format (Format, URL, 'format', 'url'); -- special case for chapter format so no error message or cat when chapter not supported if not (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia))) then ChapterFormat = style_format (ChapterFormat, ChapterURL, 'chapter-format', 'chapter-url'); end if not utilities.is_set (URL) then if utilities.in_array (config.CitationClass, {"web", "podcast", "mailinglist"}) or -- |url= required for cite web, cite podcast, and cite mailinglist ('citation' == config.CitationClass and ('website' == Periodical_origin or 'script-website' == ScriptPeriodical_origin)) then -- and required for {{citation}} with |website= or |script-website= utilities.set_message ('err_cite_web_url'); end -- do we have |accessdate= without either |url= or |chapter-url=? if utilities.is_set (AccessDate) and not utilities.is_set (ChapterURL) then -- ChapterURL may be set when URL is not set; utilities.set_message ('err_accessdate_missing_url'); AccessDate = ''; end end local UrlStatus = is_valid_parameter_value (A['UrlStatus'], A:ORIGIN('UrlStatus'), cfg.keywords_lists['url-status'], ''); local OriginalURL local OriginalURL_origin local OriginalFormat local OriginalAccess; UrlStatus = UrlStatus:lower(); -- used later when assembling archived text if utilities.is_set ( ArchiveURL ) then if utilities.is_set (ChapterURL) then -- if chapter-url= is set apply archive url to it OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text OriginalURL_origin = ChapterURL_origin; -- name of |chapter-url= parameter for error messages OriginalFormat = ChapterFormat; -- and original |chapter-format= if 'live' ~= UrlStatus then ChapterURL = ArchiveURL -- swap-in the archive's URL ChapterURL_origin = A:ORIGIN('ArchiveURL') -- name of |archive-url= parameter for error messages ChapterFormat = ArchiveFormat or ''; -- swap in archive's format ChapterUrlAccess = nil; -- restricted access levels do not make sense for archived URLs end elseif utilities.is_set (URL) then OriginalURL = URL; -- save copy of original source URL OriginalURL_origin = URL_origin; -- name of URL parameter for error messages OriginalFormat = Format; -- and original |format= OriginalAccess = UrlAccess; if 'live' ~= UrlStatus then -- if URL set then |archive-url= applies to it URL = ArchiveURL -- swap-in the archive's URL URL_origin = A:ORIGIN('ArchiveURL') -- name of archive URL parameter for error messages Format = ArchiveFormat or ''; -- swap in archive's format UrlAccess = nil; -- restricted access levels do not make sense for archived URLs end end elseif utilities.is_set (UrlStatus) then -- if |url-status= is set when |archive-url= is not set utilities.set_message ('maint_url_status'); -- add maint cat end if utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or -- if any of the 'periodical' cites except encyclopedia ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) then local chap_param; if utilities.is_set (Chapter) then -- get a parameter name from one of these chapter related meta-parameters chap_param = A:ORIGIN ('Chapter') elseif utilities.is_set (TransChapter) then chap_param = A:ORIGIN ('TransChapter') elseif utilities.is_set (ChapterURL) then chap_param = A:ORIGIN ('ChapterURL') elseif utilities.is_set (ScriptChapter) then chap_param = ScriptChapter_origin; else utilities.is_set (ChapterFormat) chap_param = A:ORIGIN ('ChapterFormat') end if utilities.is_set (chap_param) then -- if we found one utilities.set_message ('err_chapter_ignored', {chap_param}); -- add error message Chapter = ''; -- and set them to empty string to be safe with concatenation TransChapter = ''; ChapterURL = ''; ScriptChapter = ''; ChapterFormat = ''; end else -- otherwise, format chapter / article title local no_quotes = false; -- default assume that we will be quoting the chapter parameter value if utilities.is_set (Contribution) and 0 < #c then -- if this is a contribution with contributor(s) if utilities.in_array (Contribution:lower(), cfg.keywords_lists.contribution) then -- and a generic contribution title no_quotes = true; -- then render it unquoted end end Chapter = format_chapter_title (ScriptChapter, ScriptChapter_origin, Chapter, Chapter_origin, TransChapter, TransChapter_origin, ChapterURL, ChapterURL_origin, no_quotes, ChapterUrlAccess); -- Contribution is also in Chapter if utilities.is_set (Chapter) then Chapter = Chapter .. ChapterFormat ; if 'map' == config.CitationClass and utilities.is_set (TitleType) then Chapter = Chapter .. ' ' .. TitleType; -- map annotation here; not after title end Chapter = Chapter .. sepc .. ' '; elseif utilities.is_set (ChapterFormat) then -- |chapter= not set but |chapter-format= is so ... Chapter = ChapterFormat .. sepc .. ' '; -- ... ChapterFormat has error message, we want to see it end end -- Format main title local plain_title = false; local accept_title; Title, accept_title = utilities.has_accept_as_written (Title, true); -- remove accept-this-as-written markup when it wraps all of <Title> if accept_title and ('' == Title) then -- only support forced empty for now "(())" Title = cfg.messages['notitle']; -- replace by predefined "No title" message -- TODO: utilities.set_message ( 'err_redundant_parameters', ...); -- issue proper error message instead of muting ScriptTitle = ''; -- just mute for now TransTitle = ''; -- just mute for now plain_title = true; -- suppress text decoration for descriptive title utilities.set_message ('maint_untitled'); -- add maint cat end if not accept_title then -- <Title> not wrapped in accept-as-written markup if '...' == Title:sub (-3) then -- if ellipsis is the last three characters of |title= Title = Title:gsub ('(%.%.%.)%.+$', '%1'); -- limit the number of dots to three elseif not mw.ustring.find (Title, '%.%s*%a%.$') and -- end of title is not a 'dot-(optional space-)letter-dot' initialism ... not mw.ustring.find (Title, '%s+%a%.$') then -- ...and not a 'space-letter-dot' initial (''Allium canadense'' L.) Title = mw.ustring.gsub(Title, '%' .. sepc .. '$', ''); -- remove any trailing separator character; sepc and ms.ustring() here for languages that use multibyte separator characters end if utilities.is_set (ArchiveURL) and is_archived_copy (Title) then utilities.set_message ('maint_archived_copy'); -- add maintenance category before we modify the content of Title end if is_generic ('generic_titles', Title) then utilities.set_message ('err_generic_title'); -- set an error message end end if (not plain_title) and (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'document', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) or ('map' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)))) then -- special case for cite map when the map is in a periodical treat as an article Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from module provided quote marks Title = utilities.wrap_style ('quoted-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); elseif plain_title or ('report' == config.CitationClass) then -- no styling for cite report and descriptive titles (otherwise same as above) Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); -- for cite report, use this form for trans-title else Title = utilities.wrap_style ('italic-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-italic-title', TransTitle); end if utilities.is_set (TransTitle) then if utilities.is_set (Title) then TransTitle = " " .. TransTitle; else utilities.set_message ('err_trans_missing_title', {'title'}); end end if utilities.is_set (Title) then -- TODO: is this the right place to be making Wikisource URLs? if utilities.is_set (TitleLink) and utilities.is_set (URL) then utilities.set_message ('err_wikilink_in_url'); -- set an error message because we can't have both TitleLink = ''; -- unset end if not utilities.is_set (TitleLink) and utilities.is_set (URL) then Title = external_link (URL, Title, URL_origin, UrlAccess) .. TransTitle .. Format; URL = ''; -- unset these because no longer needed Format = ""; elseif utilities.is_set (TitleLink) and not utilities.is_set (URL) then local ws_url; ws_url = wikisource_url_make (TitleLink); -- ignore ws_label return; not used here if ws_url then Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title-link'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], TitleLink, Title}); Title = Title .. TransTitle; else Title = utilities.make_wikilink (TitleLink, Title) .. TransTitle; end else local ws_url, ws_label, L; -- Title has italic or quote markup by the time we get here which causes is_wikilink() to return 0 (not a wikilink) ws_url, ws_label, L = wikisource_url_make (Title:gsub('^[\'"]*(.-)[\'"]*$', '%1')); -- make ws URL from |title= interwiki link (strip italic or quote markup); link portion L becomes tooltip label if ws_url then Title = Title:gsub ('%b[]', ws_label); -- replace interwiki link with ws_label to retain markup Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, Title}); Title = Title .. TransTitle; else Title = Title .. TransTitle; end end else Title = TransTitle; end if utilities.is_set (Place) then Place = " " .. wrap_msg ('written', Place, use_lowercase) .. sepc .. " "; end local ConferenceURL_origin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL if utilities.is_set (Conference) then if utilities.is_set (ConferenceURL) then Conference = external_link( ConferenceURL, Conference, ConferenceURL_origin, nil ); end Conference = sepc .. " " .. Conference .. ConferenceFormat; elseif utilities.is_set (ConferenceURL) then Conference = sepc .. " " .. external_link( ConferenceURL, nil, ConferenceURL_origin, nil ); end local Position = ''; if not utilities.is_set (Position) then local Minutes = A['Minutes']; local Time = A['Time']; if utilities.is_set (Minutes) then if utilities.is_set (Time) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'minutes') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'time')}); end Position = " " .. Minutes .. " " .. cfg.messages['minutes']; else if utilities.is_set (Time) then local TimeCaption = A['TimeCaption'] if not utilities.is_set (TimeCaption) then TimeCaption = cfg.messages['event']; if sepc ~= '.' then TimeCaption = TimeCaption:lower(); end end Position = " " .. TimeCaption .. " " .. Time; end end else Position = " " .. Position; At = ''; end Page, Pages, Sheet, Sheets = format_pages_sheets (Page, Pages, Sheet, Sheets, config.CitationClass, Periodical_origin, sepc, NoPP, use_lowercase); At = utilities.is_set (At) and (sepc .. " " .. At) or ""; Position = utilities.is_set (Position) and (sepc .. " " .. Position) or ""; if config.CitationClass == 'map' then local Sections = A['Sections']; -- Section (singular) is an alias of Chapter so set earlier local Inset = A['Inset']; if utilities.is_set ( Inset ) then Inset = sepc .. " " .. wrap_msg ('inset', Inset, use_lowercase); end if utilities.is_set ( Sections ) then Section = sepc .. " " .. wrap_msg ('sections', Sections, use_lowercase); elseif utilities.is_set ( Section ) then Section = sepc .. " " .. wrap_msg ('section', Section, use_lowercase); end At = At .. Inset .. Section; end local Others = A['Others']; if utilities.is_set (Others) and 0 == #a and 0 == #e then -- add maint cat when |others= has value and used without |author=, |editor= if config.CitationClass == "AV-media-notes" or config.CitationClass == "audio-visual" then -- special maint for AV/M which has a lot of 'false' positives right now utilities.set_message ('maint_others_avm') else utilities.set_message ('maint_others'); end end Others = utilities.is_set (Others) and (sepc .. " " .. Others) or ""; if utilities.is_set (Translators) then Others = safe_join ({sepc .. ' ', wrap_msg ('translated', Translators, use_lowercase), Others}, sepc); end if utilities.is_set (Interviewers) then Others = safe_join ({sepc .. ' ', wrap_msg ('interview', Interviewers, use_lowercase), Others}, sepc); end local TitleNote = A['TitleNote']; TitleNote = utilities.is_set (TitleNote) and (sepc .. " " .. TitleNote) or ""; if utilities.is_set (Edition) then if Edition:match ('%f[%a][Ee]d%n?%.?$') or Edition:match ('%f[%a][Ee]dition$') then -- Ed, ed, Ed., ed., Edn, edn, Edn., edn. utilities.set_message ('err_extra_text_edition'); -- add error message end Edition = " " .. wrap_msg ('edition', Edition); else Edition = ''; end Series = utilities.is_set (Series) and wrap_msg ('series', {sepc, Series}) or ""; -- not the same as SeriesNum local Agency = A['Agency'] or ''; -- |agency= is supported by {{cite magazine}}, {{cite news}}, {{cite press release}}, {{cite web}}, and certain {{citation}} templates if utilities.is_set (Agency) then -- this testing done here because {{citation}} supports 'news' citations if utilities.in_array (config.CitationClass, {'magazine', 'news', 'pressrelease', 'web'}) or ('citation' == config.CitationClass and utilities.in_array (Periodical_origin, {"magazine", "newspaper", "work"})) then Agency = wrap_msg ('agency', {sepc, Agency}); -- format for rendering else Agency = ''; -- unset; not supported utilities.set_message ('err_parameter_ignored', {'agency'}); -- add error message end end Volume = format_volume_issue (Volume, Issue, ArticleNumber, config.CitationClass, Periodical_origin, sepc, use_lowercase); if utilities.is_set (AccessDate) then local retrv_text = " " .. cfg.messages['retrieved'] AccessDate = nowrap_date (AccessDate); -- wrap in nowrap span if date in appropriate format if (sepc ~= ".") then retrv_text = retrv_text:lower() end -- if mode is cs2, lower case AccessDate = utilities.substitute (retrv_text, AccessDate); -- add retrieved text AccessDate = utilities.substitute (cfg.presentation['accessdate'], {sepc, AccessDate}); -- allow editors to hide accessdates end if utilities.is_set (ID) then ID = sepc .. " " .. ID; end local Docket = A['Docket']; if "thesis" == config.CitationClass and utilities.is_set (Docket) then ID = sepc .. " Docket " .. Docket .. ID; end if "report" == config.CitationClass and utilities.is_set (Docket) then -- for cite report when |docket= is set ID = sepc .. ' ' .. Docket; -- overwrite ID even if |id= is set end if utilities.is_set (URL) then URL = " " .. external_link( URL, nil, URL_origin, UrlAccess ); end -- We check length of PostScript here because it will have been nuked by -- the quote parameters. We'd otherwise emit a message even if there wasn't -- a displayed postscript. -- TODO: Should the max size (1) be configurable? -- TODO: Should we check a specific pattern? if utilities.is_set(PostScript) and mw.ustring.len(PostScript) > 1 then utilities.set_message ('maint_postscript') end local Archived; if utilities.is_set (ArchiveURL) then if not utilities.is_set (ArchiveDate) then -- ArchiveURL set but ArchiveDate not set utilities.set_message ('err_archive_missing_date'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end else if utilities.is_set (ArchiveDate) then -- ArchiveURL not set but ArchiveDate is set utilities.set_message ('err_archive_date_missing_url'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end end if utilities.is_set (ArchiveURL) then local arch_text; if "live" == UrlStatus then arch_text = cfg.messages['archived']; if sepc ~= "." then arch_text = arch_text:lower() end if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cfg.messages['archived-live'], {external_link( ArchiveURL, arch_text, A:ORIGIN('ArchiveURL'), nil) .. ArchiveFormat, ArchiveDate } ); else Archived = ''; end if not utilities.is_set (OriginalURL) then utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (OriginalURL) then -- UrlStatus is empty, 'dead', 'unfit', 'usurped', 'bot: unknown' if utilities.in_array (UrlStatus, {'unfit', 'usurped', 'bot: unknown'}) then arch_text = cfg.messages['archived-unfit']; if sepc ~= "." then arch_text = arch_text:lower() end Archived = sepc .. ' ' .. arch_text .. ArchiveDate; -- format already styled if 'bot: unknown' == UrlStatus then utilities.set_message ('maint_bot_unknown'); -- and add a category if not already added else utilities.add_prop_cat ('unfit'); -- and add a category if not already added end else -- UrlStatus is empty, 'dead' arch_text = cfg.messages['archived-dead']; if sepc ~= "." then arch_text = arch_text:lower() end if utilities.is_set (ArchiveDate) then Archived = sepc .. " " .. utilities.substitute ( arch_text, { external_link( OriginalURL, cfg.messages['original'], OriginalURL_origin, OriginalAccess ) .. OriginalFormat, ArchiveDate } ); -- format already styled else Archived = ''; -- unset for concatenation end end else -- OriginalUrl not set utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (ArchiveFormat) then Archived = ArchiveFormat; -- if set and ArchiveURL not set ArchiveFormat has error message else Archived = ''; end local TranscriptURL = A['TranscriptURL'] local TranscriptFormat = A['TranscriptFormat']; TranscriptFormat = style_format (TranscriptFormat, TranscriptURL, 'transcript-format', 'transcripturl'); local Transcript = A['Transcript']; local TranscriptURL_origin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL if utilities.is_set (Transcript) then if utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, Transcript, TranscriptURL_origin, nil ); end Transcript = sepc .. ' ' .. Transcript .. TranscriptFormat; elseif utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, nil, TranscriptURL_origin, nil ); end local Publisher; if utilities.is_set (PublicationDate) then PublicationDate = wrap_msg ('published', PublicationDate); end if utilities.is_set (PublisherName) then if utilities.is_set (PublicationPlace) then Publisher = sepc .. " " .. PublicationPlace .. ": " .. PublisherName .. PublicationDate; else Publisher = sepc .. " " .. PublisherName .. PublicationDate; end elseif utilities.is_set (PublicationPlace) then Publisher= sepc .. " " .. PublicationPlace .. PublicationDate; else Publisher = PublicationDate; end -- Several of the above rely upon detecting this as nil, so do it last. if (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical)) then if utilities.is_set (Title) or utilities.is_set (TitleNote) then Periodical = sepc .. " " .. format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); else Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); end end local Language = A['Language']; if utilities.is_set (Language) then Language = language_parameter (Language); -- format, categories, name from ISO639-1, etc. else Language=''; -- language not specified so make sure this is an empty string; --[[ TODO: need to extract the wrap_msg from language_parameter so that we can solve parentheses bunching problem with Format/Language/TitleType ]] end --[[ Handle the oddity that is cite speech. This code overrides whatever may be the value assigned to TitleNote (through |department=) and forces it to be " (Speech)" so that the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided). ]] if "speech" == config.CitationClass then -- cite speech only TitleNote = TitleType; -- move TitleType to TitleNote so that it renders ahead of |event= TitleType = ''; -- and unset if utilities.is_set (Periodical) then -- if Periodical, perhaps because of an included |website= or |journal= parameter if utilities.is_set (Conference) then -- and if |event= is set Conference = Conference .. sepc .. " "; -- then add appropriate punctuation to the end of the Conference variable before rendering end end end -- Piece all bits together at last. Here, all should be non-nil. -- We build things this way because it is more efficient in LUA -- not to keep reassigning to the same string variable over and over. local tcommon; local tcommon2; -- used for book cite when |contributor= is set if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (Periodical) then -- special cases for book cites if utilities.is_set (Contributors) then -- when we are citing foreword, preface, introduction, etc. tcommon = safe_join ({Title, TitleNote}, sepc); -- author and other stuff will come after this and before tcommon2 tcommon2 = safe_join ({TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); else tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); end elseif 'map' == config.CitationClass then -- special cases for cite map if utilities.is_set (Chapter) then -- map in a book; TitleType is part of Chapter tcommon = safe_join ({Title, Edition, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); elseif utilities.is_set (Periodical) then -- map in a periodical tcommon = safe_join ({Title, TitleType, Periodical, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); else -- a sheet or stand-alone map tcommon = safe_join ({Title, TitleType, Edition, Scale, Series, Language, Cartography, Others, Publisher}, sepc); end elseif 'episode' == config.CitationClass then -- special case for cite episode tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Edition, Publisher}, sepc); else -- all other CS1 templates tcommon = safe_join ({Title, TitleNote, Conference, Periodical, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc); end if #ID_list > 0 then ID_list = safe_join( { sepc .. " ", table.concat( ID_list, sepc .. " " ), ID }, sepc ); else ID_list = ID; end local Via = A['Via']; Via = utilities.is_set (Via) and wrap_msg ('via', Via) or ''; local idcommon; if 'audio-visual' == config.CitationClass or 'episode' == config.CitationClass then -- special case for cite AV media & cite episode position transcript idcommon = safe_join( { ID_list, URL, Archived, Transcript, AccessDate, Via, Quote }, sepc ); else idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, Quote }, sepc ); end local text; local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; local OrigDate = A['OrigDate']; OrigDate = utilities.is_set (OrigDate) and wrap_msg ('origdate', OrigDate) or ''; if utilities.is_set (Date) then if utilities.is_set (Authors) or utilities.is_set (Editors) then -- date follows authors or editors when authors not set Date = " (" .. Date .. ")" .. OrigDate .. sepc .. " "; -- in parentheses else -- neither of authors and editors set if (string.sub(tcommon, -1, -1) == sepc) then -- if the last character of tcommon is sepc Date = " " .. Date .. OrigDate; -- Date does not begin with sepc else Date = sepc .. " " .. Date .. OrigDate; -- Date begins with sepc end end end if utilities.is_set (Authors) then if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Authors termination Authors = terminate_name_list (Authors, sepc); -- when no date, terminate with 0 or 1 sepc and a space end if utilities.is_set (Editors) then local in_text = ''; local post_text = ''; if utilities.is_set (Chapter) and 0 == #c then in_text = cfg.messages['in'] .. ' '; if (sepc ~= '.') then in_text = in_text:lower(); -- lowercase for cs2 end end if EditorCount <= 1 then post_text = ' (' .. cfg.messages['editor'] .. ')'; -- be consistent with no-author, no-date case else post_text = ' (' .. cfg.messages['editors'] .. ')'; end Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space end if utilities.is_set (Contributors) then -- book cite and we're citing the intro, preface, etc. local by_text = sepc .. ' ' .. cfg.messages['by'] .. ' '; if (sepc ~= '.') then by_text = by_text:lower() end -- lowercase for cs2 Authors = by_text .. Authors; -- author follows title so tweak it here if utilities.is_set (Editors) and utilities.is_set (Date) then -- when Editors make sure that Authors gets terminated Authors = terminate_name_list (Authors, sepc); -- terminate with 0 or 1 sepc and a space end if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Contributors termination Contributors = terminate_name_list (Contributors, sepc); -- terminate with 0 or 1 sepc and a space end text = safe_join( {Contributors, Date, Chapter, tcommon, Authors, Place, Editors, tcommon2, pgtext, idcommon }, sepc ); else text = safe_join( {Authors, Date, Chapter, Place, Editors, tcommon, pgtext, idcommon }, sepc ); end elseif utilities.is_set (Editors) then if utilities.is_set (Date) then if EditorCount <= 1 then Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editor']; else Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editors']; end else if EditorCount <= 1 then Editors = Editors .. " (" .. cfg.messages['editor'] .. ")" .. sepc .. " " else Editors = Editors .. " (" .. cfg.messages['editors'] .. ")" .. sepc .. " " end end text = safe_join( {Editors, Date, Chapter, Place, tcommon, pgtext, idcommon}, sepc ); else if utilities.in_array (config.CitationClass, {"journal", "citation"}) and utilities.is_set (Periodical) then text = safe_join( {Chapter, Place, tcommon, pgtext, Date, idcommon}, sepc ); else text = safe_join( {Chapter, Place, tcommon, Date, pgtext, idcommon}, sepc ); end end if utilities.is_set (PostScript) and PostScript ~= sepc then text = safe_join( {text, sepc}, sepc ); -- Deals with italics, spaces, etc. if '.' == sepc then -- remove final seperator if present text = text:gsub ('%' .. sepc .. '$', ''); -- dot must be escaped here else text = mw.ustring.gsub (text, sepc .. '$', ''); -- using ustring for non-dot sepc (likely a non-Latin character) end end text = safe_join( {text, PostScript}, sepc ); -- Now enclose the whole thing in a <cite> element local options_t = {}; options_t.class = cite_class_attribute_make (config.CitationClass, Mode); local Ref = is_valid_parameter_value (A['Ref'], A:ORIGIN('Ref'), cfg.keywords_lists['ref'], nil, true); -- nil when |ref=harv; A['Ref'] else if 'none' ~= cfg.keywords_xlate[(Ref and Ref:lower()) or ''] then local namelist_t = {}; -- holds selected contributor, author, editor name list local year = first_set ({Year, anchor_year}, 2); -- Year first for legacy citations and for YMD dates that require disambiguation if #c > 0 then -- if there is a contributor list namelist_t = c; -- select it elseif #a > 0 then -- or an author list namelist_t = a; elseif #e > 0 then -- or an editor list namelist_t = e; end local citeref_id; if #namelist_t > 0 then -- if there are names in namelist_t citeref_id = make_citeref_id (namelist_t, year); -- go make the CITEREF anchor if mw.uri.anchorEncode (citeref_id) == ((Ref and mw.uri.anchorEncode (Ref)) or '') then -- Ref may already be encoded (by {{sfnref}}) so citeref_id must be encoded before comparison utilities.set_message ('maint_ref_duplicates_default'); end else citeref_id = ''; -- unset end options_t.id = Ref or citeref_id; end if string.len (text:gsub('%b<>', '')) <= 2 then -- remove html and html-like tags; then get length of what remains; z.error_cats_t = {}; -- blank the categories list z.error_msgs_t = {}; -- blank the error messages list OCinSoutput = nil; -- blank the metadata string text = ''; -- blank the the citation utilities.set_message ('err_empty_citation'); -- set empty citation message and category end local render_t = {}; -- here we collect the final bits for concatenation into the rendered citation if utilities.is_set (options_t.id) then -- here we wrap the rendered citation in <cite ...>...</cite> tags table.insert (render_t, utilities.substitute (cfg.presentation['cite-id'], {mw.uri.anchorEncode(options_t.id), mw.text.nowiki(options_t.class), text})); -- when |ref= is set or when there is a namelist else table.insert (render_t, utilities.substitute (cfg.presentation['cite'], {mw.text.nowiki(options_t.class), text})); -- when |ref=none or when namelist_t empty and |ref= is missing or is empty end if OCinSoutput then -- blanked when citation is 'empty' so don't bother to add boilerplate metadata span table.insert (render_t, utilities.substitute (cfg.presentation['ocins'], OCinSoutput)); -- format and append metadata to the citation end local template_name = ('citation' == config.CitationClass) and 'citation' or 'cite ' .. (cfg.citation_class_map_t[config.CitationClass] or config.CitationClass); local template_link = '[[Template:' .. template_name .. '|' .. template_name .. ']]'; local msg_prefix = '<code class="cs1-code">{{' .. template_link .. '}}</code>: '; if 0 ~= #z.error_msgs_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_e, template_link)); table.insert (render_t, ' '); -- insert a space between citation and its error messages table.sort (z.error_msgs_t); -- sort the error messages list; sorting includes wrapping <span> and <code> tags; hidden-error sorts ahead of visible-error local hidden = true; -- presume that the only error messages emited by this template are hidden for _, v in ipairs (z.error_msgs_t) do -- spin through the list of error messages if v:find ('cs1-visible-error', 1, true) then -- look for the visible error class name hidden = false; -- found one; so don't hide the error message prefix break; -- and done because no need to look further end end z.error_msgs_t[1] = table.concat ({utilities.error_comment (msg_prefix, hidden), z.error_msgs_t[1]}); -- add error message prefix to first error message to prevent extraneous punctuation table.insert (render_t, table.concat (z.error_msgs_t, '; ')); -- make a big string of error messages and add it to the rendering end if 0 ~= #z.maint_cats_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_m, template_link)); table.sort (z.maint_cats_t); -- sort the maintenance messages list local maint_msgs_t = {}; -- here we collect all of the maint messages if 0 == #z.error_msgs_t then -- if no error messages table.insert (maint_msgs_t, msg_prefix); -- insert message prefix in maint message livery end for _, v in ipairs( z.maint_cats_t ) do -- append maintenance categories table.insert (maint_msgs_t, -- assemble new maint message and add it to the maint_msgs_t table table.concat ({v, ' (', utilities.substitute (cfg.messages[':cat wikilink'], v), ')'}) ); end table.insert (render_t, utilities.substitute (cfg.presentation['hidden-maint'], table.concat (maint_msgs_t, ' '))); -- wrap the group of maint messages with proper presentation and save end if not no_tracking_cats then local sort_key; local cat_wikilink = 'cat wikilink'; if cfg.enable_sort_keys then -- when namespace sort keys enabled local namespace_number = mw.title.getCurrentTitle().namespace; -- get namespace number for this wikitext sort_key = (0 ~= namespace_number and (cfg.name_space_sort_keys[namespace_number] or cfg.name_space_sort_keys.other)) or nil; -- get sort key character; nil for mainspace cat_wikilink = (not sort_key and 'cat wikilink') or 'cat wikilink sk'; -- make <cfg.messages> key end for _, v in ipairs (z.error_cats_t) do -- append error categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end if cfg.id_limits_data_load_fail then -- boolean true when load failed utilities.set_message ('maint_id_limit_load_fail'); -- done here because this maint cat emits no message end for _, v in ipairs (z.maint_cats_t) do -- append maintenance categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end for _, v in ipairs (z.prop_cats_t) do -- append properties categories table.insert (render_t, utilities.substitute (cfg.messages['cat wikilink'], v)); -- no sort keys end end return table.concat (render_t); -- make a big string and done end --[[--------------------------< V A L I D A T E >-------------------------------------------------------------- Looks for a parameter's name in one of several whitelists. Parameters in the whitelist can have three values: true - active, supported parameters false - deprecated, supported parameters nil - unsupported parameters ]] local function validate (name, cite_class, empty) local name = tostring (name); local enum_name; -- parameter name with enumerator (if any) replaced with '#' local state; local function state_test (state, name) -- local function to do testing of state values if true == state then return true; end -- valid actively supported parameter if false == state then if empty then return nil; end -- empty deprecated parameters are treated as unknowns deprecated_parameter (name); -- parameter is deprecated but still supported return true; end if 'tracked' == state then local base_name = name:gsub ('%d', ''); -- strip enumerators from parameter names that have them to get the base name utilities.add_prop_cat ('tracked-param', {base_name}, base_name); -- add a properties category; <base_name> modifies <key> return true; end return nil; end if name:find ('#') then -- # is a cs1|2 reserved character so parameters with # not permitted return nil; end -- replace enumerator digit(s) with # (|last25= becomes |last#=) (mw.ustring because non-Western 'local' digits) enum_name = mw.ustring.gsub (name, '%d+$', '#'); -- where enumerator is last charaters in parameter name (these to protect |s2cid=) enum_name = mw.ustring.gsub (enum_name, '%d+([%-l])', '#%1'); -- where enumerator is in the middle of the parameter name; |author#link= is the oddity if 'document' == cite_class then -- special case for {{cite document}} state = whitelist.document_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end return false; end if utilities.in_array (cite_class, whitelist.preprint_template_list_t) then -- limited parameter sets allowed for these templates state = whitelist.limited_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end state = whitelist.preprint_arguments_t[cite_class][name]; -- look in the parameter-list for the template identified by cite_class if true == state_test (state, name) then return true; end return false; -- not supported because not found or name is set to nil end -- end limited parameter-set templates if utilities.in_array (cite_class, whitelist.unique_param_template_list_t) then -- template-specific parameters for templates that accept parameters from the basic argument list state = whitelist.unique_arguments_t[cite_class][name]; -- look in the template-specific parameter-lists for the template identified by cite_class if true == state_test (state, name) then return true; end end -- if here, fall into general validation state = whitelist.common_parameters_t[enum_name]; -- all other templates; all normal parameters allowed; this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end return false; -- not supported because not found or name is set to nil end --[=[-------------------------< I N T E R _ W I K I _ C H E C K >---------------------------------------------- check <value> for inter-language interwiki-link markup. <prefix> must be a MediaWiki-recognized language code. when these values have the form (without leading colon): [[<prefix>:link|label]] return label as plain-text [[<prefix>:link]] return <prefix>:link as plain-text return value as is else ]=] local function inter_wiki_check (parameter, value) local prefix = value:match ('%[%[(%a+):'); -- get an interwiki prefix if one exists local _; if prefix and cfg.inter_wiki_map[prefix:lower()] then -- if prefix is in the map, needs preceding colon so utilities.set_message ('err_bad_paramlink', parameter); -- emit an error message _, value, _ = utilities.is_wikilink (value); -- extract label portion from wikilink end return value; end --[[--------------------------< M I S S I N G _ P I P E _ C H E C K >------------------------------------------ Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal sign, compare the alphanumeric string to the list of cs1|2 parameters. If found, then the string is possibly a parameter that is missing its pipe. There are two tests made: {{cite ... |title=Title access-date=2016-03-17}} -- the first parameter has a value and whitespace separates that value from the missing pipe parameter name {{cite ... |title=access-date=2016-03-17}} -- the first parameter has no value (whitespace after the first = is trimmed by MediaWiki) cs1|2 shares some parameter names with XML/HTML attributes: class=, title=, etc. To prevent false positives XML/HTML tags are removed before the search. If a missing pipe is detected, this function adds the missing pipe maintenance category. ]] local function missing_pipe_check (parameter, value) local capture; value = value:gsub ('%b<>', ''); -- remove XML/HTML tags because attributes: class=, title=, etc. capture = value:match ('%s+(%a[%w%-]+)%s*=') or value:match ('^(%a[%w%-]+)%s*='); -- find and categorize parameters with possible missing pipes if capture and validate (capture) then -- if the capture is a valid parameter name utilities.set_message ('err_missing_pipe', parameter); end end --[[--------------------------< H A S _ E X T R A N E O U S _ P U N C T >-------------------------------------- look for extraneous terminal punctuation in most parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_punc (param, value) if 'number' == type (param) then return; end param = param:gsub ('%d+', '#'); -- enumerated name-list mask params allow terminal punct; normalize if cfg.punct_skip[param] then return; -- parameter name found in the skip table so done end if value:match ('[,;:]$') then utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end if value:match ('^=') then -- sometimes an extraneous '=' character appears ... utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end end --[[--------------------------< H A S _ T W L _ U R L >-------------------------------------------------------- look for The Wikipedia Library urls in url-holding parameters. TWL urls are accessible only for readers who are active extended confirmed Wikipedia editors. This function sets an error message when such urls are discovered and when appropriate, sets the |<param>-url-access=subscription. returns nothing. looks for: '.wikipedialibrary.idm.oclc.org' ]] local function has_twl_url (url_params_t, cite_args_t) local url_error_t = {}; -- sequence of url-holding parameters that have a TWL url for param, value in pairs (url_params_t) do if value:find ('%.wikipedialibrary%.idm%.oclc%.org') then -- has the TWL base url? table.insert (url_error_t, param); -- add parameter name to the error list end end if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); -- sor for error messaging for i, param in ipairs (url_error_t) do if cfg.url_access_map_t[param] then -- if <param> has a matching -access parameter cite_args_t[cfg.url_access_map_t[param]] = cfg.keywords_xlate.subscription; -- set |<param>-url-access=subscription end url_error_t[i] = utilities.wrap_style ('parameter', param); -- make the parameter pretty for error message end utilities.set_message ('err_param_has_twl_url', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< H A S _ E X T R A N E O U S _ U R L >------------------------------------------ look for extraneous url parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_url (non_url_param_t) local url_error_t = {}; check_for_url (non_url_param_t, url_error_t); -- extraneous url check if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); utilities.set_message ('err_param_has_ext_link', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< _ C I T A T I O N >------------------------------------------------------------ Module entry point frame – from template call (citation()); may be nil when called from another module args_t – table of all cs1|2 parameters in the template (the parent frame) config_t – table of template-supplied parameter (the #invoke frame) ]] local function _citation (frame, args_t, config_t) -- save a copy in case we need to display an error message in preview mode if not frame then frame = mw.getCurrentFrame(); -- if called from another module, get a frame for frame-provided functions end -- i18n: set the name that your wiki uses to identify sandbox subpages from sandbox template invoke (or can be set here) local sandbox = ((config_t.SandboxPath and '' ~= config_t.SandboxPath) and config_t.SandboxPath) or '/sandbox'; -- sandbox path from {{#invoke:Citation/CS1/sandbox|citation|SandboxPath=/...}} is_sandbox = nil ~= string.find (frame:getTitle(), sandbox, 1, true); -- is this invoke the sandbox module? sandbox = is_sandbox and sandbox or ''; -- use i18n sandbox to load sandbox modules when this module is the sandox; live modules else cfg = mw.loadData ('Module:Citation/CS1/Configuration' .. sandbox); -- load sandbox versions of support modules when {{#invoke:Citation/CS1/sandbox|...}}; live modules else whitelist = mw.loadData ('Module:Citation/CS1/Whitelist' .. sandbox); utilities = require ('Module:Citation/CS1/Utilities' .. sandbox); validation = require ('Module:Citation/CS1/Date_validation' .. sandbox); identifiers = require ('Module:Citation/CS1/Identifiers' .. sandbox); metadata = require ('Module:Citation/CS1/COinS' .. sandbox); utilities.set_selected_modules (cfg); -- so that functions in Utilities can see the selected cfg tables identifiers.set_selected_modules (cfg, utilities); -- so that functions in Identifiers can see the selected cfg tables and selected Utilities module validation.set_selected_modules (cfg, utilities); -- so that functions in Date validataion can see selected cfg tables and the selected Utilities module metadata.set_selected_modules (cfg, utilities); -- so that functions in COinS can see the selected cfg tables and selected Utilities module z = utilities.z; -- table of error and category tables in Module:Citation/CS1/Utilities local cite_args_t = {}; -- because args_t is the parent (template) frame args (which cannot be modified); params and their values will be placed here is_preview_mode = not utilities.is_set (frame:preprocess ('{{REVISIONID}}')); local suggestions = {}; -- table where we store suggestions if we need to loadData them local error_text; -- used as a flag local capture; -- the single supported capture when matching unknown parameters using patterns local empty_unknowns = {}; -- sequence table to hold empty unknown params for error message listing for k, v in pairs (args_t) do -- get parameters from the parent (template) frame v = mw.ustring.gsub (v, '^%s*(.-)%s*$', '%1'); -- trim leading/trailing whitespace; when v is only whitespace, becomes empty string if v ~= '' then if ('string' == type (k)) then k = mw.ustring.gsub (k, '%d', cfg.date_names.local_digits); -- for enumerated parameters, translate 'local' digits to Western 0-9 end if not validate( k, config_t.CitationClass ) then if type (k) ~= 'string' then -- exclude empty numbered parameters if v:match("%S+") ~= nil then error_text = utilities.set_message ('err_text_ignored', {v}); end elseif validate (k:lower(), config_t.CitationClass) then error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, k:lower()}); -- suggest the lowercase version of the parameter else if nil == suggestions.suggestions then -- if this table is nil then we need to load it suggestions = mw.loadData ('Module:Citation/CS1/Suggestions' .. sandbox); --load sandbox version of suggestion module when {{#invoke:Citation/CS1/sandbox|...}}; live module else end for pattern, param in pairs (suggestions.patterns) do -- loop through the patterns to see if we can suggest a proper parameter capture = k:match (pattern); -- the whole match if no capture in pattern else the capture if a match if capture then -- if the pattern matches param = utilities.substitute (param, capture); -- add the capture to the suggested parameter (typically the enumerator) if validate (param, config_t.CitationClass) then -- validate the suggestion to make sure that the suggestion is supported by this template (necessary for limited parameter lists) error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, param}); -- set the suggestion error message else error_text = utilities.set_message ('err_parameter_ignored', {k}); -- suggested param not supported by this template v = ''; -- unset end end end if not utilities.is_set (error_text) then -- couldn't match with a pattern, is there an explicit suggestion? if (suggestions.suggestions[ k:lower() ] ~= nil) and validate (suggestions.suggestions[ k:lower() ], config_t.CitationClass) then utilities.set_message ('err_parameter_ignored_suggest', {k, suggestions.suggestions[ k:lower() ]}); else utilities.set_message ('err_parameter_ignored', {k}); v = ''; -- unset value assigned to unrecognized parameters (this for the limited parameter lists) end end end end cite_args_t[k] = v; -- save this parameter and its value elseif not utilities.is_set (v) then -- for empty parameters if not validate (k, config_t.CitationClass, true) then -- is this empty parameter a valid parameter k = ('' == k) and '(empty string)' or k; -- when k is empty string (or was space(s) trimmed to empty string), replace with descriptive text table.insert (empty_unknowns, utilities.wrap_style ('parameter', k)); -- format for error message and add to the list end end end if 0 ~= #empty_unknowns then -- create empty unknown error message utilities.set_message ('err_param_unknown_empty', { 1 == #empty_unknowns and '' or 's', utilities.make_sep_list (#empty_unknowns, empty_unknowns) }); end local non_url_param_t = {}; -- table of parameters and values that are not url-holding parameters local url_param_t = {}; -- table of url-holding paramters and their values for k, v in pairs (cite_args_t) do if 'string' == type (k) then -- don't evaluate positional parameters has_invisible_chars (k, v); -- look for invisible characters end has_extraneous_punc (k, v); -- look for extraneous terminal punctuation in parameter values missing_pipe_check (k, v); -- do we think that there is a parameter that is missing a pipe? cite_args_t[k] = inter_wiki_check (k, v); -- when language interwiki-linked parameter missing leading colon replace with wiki-link label if 'string' == type (k) then -- when parameter k is not positional if not cfg.url_skip[k] then -- and not in url skip table non_url_param_t[k] = v; -- make a parameter/value list for extraneous url check else -- and is in url skip table (a url-holding parameter) url_param_t[k] = v; -- make a parameter/value list to check for values that are The Wikipedia Library url end end end has_extraneous_url (non_url_param_t); -- look for url in parameter values where a url does not belong has_twl_url (url_param_t, cite_args_t); -- look for url-holding parameters that hold a The Wikipedia Library url return table.concat ({ frame:extensionTag ('templatestyles', '', {src='Module:Citation/CS1' .. sandbox .. '/styles.css'}), citation0 (config_t, cite_args_t) }); end --[[--------------------------< C I T A T I O N >-------------------------------------------------------------- Template entry point ]] local function citation (frame) local config_t = {}; -- table to store parameters from the module {{#invoke:}} local args_t = frame:getParent().args; -- get template's preset parameters for k, v in pairs (frame.args) do -- get parameters from the {{#invoke}} frame config_t[k] = v; -- args_t[k] = v; -- crude debug support that allows us to render a citation from module {{#invoke:}}; skips parameter validation; TODO: keep? end return _citation (frame, args_t, config_t) end --[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------ ]] return { citation = citation, -- template entry point _citation = _citation, -- module entry point } kb46osf34dkt3wnijj8gkggcolbrkmi 736728 736727 2025-09-02T13:17:58Z en>Trappist the monk 0 bug fix; 736728 Scribunto text/plain require ('strict'); --[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- each of these counts against the Lua upvalue limit ]] local validation; -- functions in Module:Citation/CS1/Date_validation local utilities; -- functions in Module:Citation/CS1/Utilities local z = {}; -- table of tables in Module:Citation/CS1/Utilities local identifiers; -- functions and tables in Module:Citation/CS1/Identifiers local metadata; -- functions in Module:Citation/CS1/COinS local cfg = {}; -- table of configuration tables that are defined in Module:Citation/CS1/Configuration local whitelist = {}; -- table of tables listing valid template parameter names; defined in Module:Citation/CS1/Whitelist --[[------------------< P A G E S C O P E V A R I A B L E S >--------------- declare variables here that have page-wide scope that are not brought in from other modules; that are created here and used here ]] local added_deprecated_cat; -- Boolean flag so that the category is added only once local added_vanc_errs; -- Boolean flag so we only emit one Vancouver error / category local added_generic_name_errs; -- Boolean flag so we only emit one generic name error / category and stop testing names once an error is encountered local added_numeric_name_errs; -- Boolean flag so we only emit one numeric name error / category and stop testing names once an error is encountered local added_numeric_name_maint; -- Boolean flag so we only emit one numeric name maint category and stop testing names once a category has been emitted local is_preview_mode; -- true when article is in preview mode; false when using 'Preview page with this template' (previewing the module) local is_sandbox; -- true when using sandbox modules to render citation --[[--------------------------< F I R S T _ S E T >------------------------------------------------------------ Locates and returns the first set value in a table of values where the order established in the table, left-to-right (or top-to-bottom), is the order in which the values are evaluated. Returns nil if none are set. This version replaces the original 'for _, val in pairs do' and a similar version that used ipairs. With the pairs version the order of evaluation could not be guaranteed. With the ipairs version, a nil value would terminate the for-loop before it reached the actual end of the list. ]] local function first_set (list, count) local i = 1; while i <= count do -- loop through all items in list if utilities.is_set( list[i] ) then return list[i]; -- return the first set list member end i = i + 1; -- point to next end end --[[--------------------------< A D D _ V A N C _ E R R O R >---------------------------------------------------- Adds a single Vancouver system error message to the template's output regardless of how many error actually exist. To prevent duplication, added_vanc_errs is nil until an error message is emitted. added_vanc_errs is a Boolean declared in page scope variables above ]] local function add_vanc_error (source, position) if added_vanc_errs then return end added_vanc_errs = true; -- note that we've added this category utilities.set_message ('err_vancouver', {source, position}); end --[[--------------------------< I S _ S C H E M E >------------------------------------------------------------ does this thing that purports to be a URI scheme seem to be a valid scheme? The scheme is checked to see if it is in agreement with http://tools.ietf.org/html/std66#section-3.1 which says: Scheme names consist of a sequence of characters beginning with a letter and followed by any combination of letters, digits, plus ("+"), period ("."), or hyphen ("-"). returns true if it does, else false ]] local function is_scheme (scheme) return scheme and scheme:match ('^%a[%a%d%+%.%-]*:'); -- true if scheme is set and matches the pattern end --[=[-------------------------< I S _ D O M A I N _ N A M E >-------------------------------------------------- Does this thing that purports to be a domain name seem to be a valid domain name? Syntax defined here: http://tools.ietf.org/html/rfc1034#section-3.5 BNF defined here: https://tools.ietf.org/html/rfc4234 Single character names are generally reserved; see https://tools.ietf.org/html/draft-ietf-dnsind-iana-dns-01#page-15; see also [[Single-letter second-level domain]] list of TLDs: https://www.iana.org/domains/root/db RFC 952 (modified by RFC 1123) requires the first and last character of a hostname to be a letter or a digit. Between the first and last characters the name may use letters, digits, and the hyphen. Also allowed are IPv4 addresses. IPv6 not supported domain is expected to be stripped of any path so that the last character in the last character of the TLD. tld is two or more alpha characters. Any preceding '//' (from splitting a URL with a scheme) will be stripped here. Perhaps not necessary but retained in case it is necessary for IPv4 dot decimal. There are several tests: the first character of the whole domain name including subdomains must be a letter or a digit internationalized domain name (ASCII characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the TLD) see https://tools.ietf.org/html/rfc3490 single-letter/digit second-level domains in the .org, .cash, and .today TLDs q, x, and z SL domains in the .com TLD i and q SL domains in the .net TLD single-letter SL domains in the ccTLDs (where the ccTLD is two letters) two-character SL domains in gTLDs (where the gTLD is two or more letters) three-plus-character SL domains in gTLDs (where the gTLD is two or more letters) IPv4 dot-decimal address format; TLD not allowed returns true if domain appears to be a proper name and TLD or IPv4 address, else false ]=] local function is_domain_name (domain) if not domain then return false; -- if not set, abandon end domain = domain:gsub ('^//', ''); -- strip '//' from domain name if present; done here so we only have to do it once if not domain:match ('^[%w]') then -- first character must be letter or digit return false; end if domain:match ('^%a+:') then -- hack to detect things that look like s:Page:Title where Page: is namespace at Wikisource return false; end local patterns = { -- patterns that look like URLs '%f[%w][%w][%w%-]+[%w]%.%a%a+$', -- three or more character hostname.hostname or hostname.tld '%f[%w][%w][%w%-]+[%w]%.xn%-%-[%w]+$', -- internationalized domain name with ACE prefix '%f[%a][qxz]%.com$', -- assigned one character .com hostname (x.com times out 2015-12-10) '%f[%a][iq]%.net$', -- assigned one character .net hostname (q.net registered but not active 2015-12-10) '%f[%w][%w]%.%a%a$', -- one character hostname and ccTLD (2 chars) '%f[%w][%w][%w]%.%a%a+$', -- two character hostname and TLD '^%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?', -- IPv4 address '[%a%d]+%:?' -- IPv6 address } for _, pattern in ipairs (patterns) do -- loop through the patterns list if domain:match (pattern) then return true; -- if a match then we think that this thing that purports to be a URL is a URL end end for _, d in ipairs (cfg.single_letter_2nd_lvl_domains_t) do -- look for single letter second level domain names for these top level domains if domain:match ('%f[%w][%w]%.' .. d) then return true end end return false; -- no matches, we don't know what this thing is end --[[--------------------------< I S _ U R L >------------------------------------------------------------------ returns true if the scheme and domain parts of a URL appear to be a valid URL; else false. This function is the last step in the validation process. This function is separate because there are cases that are not covered by split_url(), for example is_parameter_ext_wikilink() which is looking for bracketted external wikilinks. ]] local function is_url (scheme, domain) if utilities.is_set (scheme) then -- if scheme is set check it and domain return is_scheme (scheme) and is_domain_name (domain); else return is_domain_name (domain); -- scheme not set when URL is protocol-relative end end --[[--------------------------< S P L I T _ U R L >------------------------------------------------------------ Split a URL into a scheme, authority indicator, and domain. First remove Fully Qualified Domain Name terminator (a dot following TLD) (if any) and any path(/), query(?) or fragment(#). If protocol-relative URL, return nil scheme and domain else return nil for both scheme and domain. When not protocol-relative, get scheme, authority indicator, and domain. If there is an authority indicator (one or more '/' characters immediately following the scheme's colon), make sure that there are only 2. Any URL that does not have news: scheme must have authority indicator (//). TODO: are there other common schemes like news: that don't use authority indicator? Strip off any port and path; ]] local function split_url (url_str) local scheme, authority, domain; url_str = url_str:gsub ('([%a%d])%.?[/%?#].*$', '%1'); -- strip FQDN terminator and path(/), query(?), fragment (#) (the capture prevents false replacement of '//') if url_str:match ('^//%S*') then -- if there is what appears to be a protocol-relative URL domain = url_str:match ('^//(%S*)') elseif url_str:match ('%S-:/*%S+') then -- if there is what appears to be a scheme, optional authority indicator, and domain name scheme, authority, domain = url_str:match ('(%S-:)(/*)(%S+)'); -- extract the scheme, authority indicator, and domain portions if utilities.is_set (authority) then authority = authority:gsub ('//', '', 1); -- replace place 1 pair of '/' with nothing; if utilities.is_set(authority) then -- if anything left (1 or 3+ '/' where authority should be) then return scheme; -- return scheme only making domain nil which will cause an error message end else if not scheme:match ('^news:') then -- except for news:..., MediaWiki won't link URLs that do not have authority indicator; TODO: a better way to do this test? return scheme; -- return scheme only making domain nil which will cause an error message end end domain = domain:gsub ('(%a):%d+', '%1'); -- strip port number if present end return scheme, domain; end --[[--------------------------< L I N K _ P A R A M _ O K >--------------------------------------------------- checks the content of |title-link=, |series-link=, |author-link=, etc. for properly formatted content: no wikilinks, no URLs Link parameters are to hold the title of a Wikipedia article, so none of the WP:TITLESPECIALCHARACTERS are allowed: # < > [ ] | { } _ except the underscore which is used as a space in wiki URLs and # which is used for section links returns false when the value contains any of these characters. When there are no illegal characters, this function returns TRUE if value DOES NOT appear to be a valid URL (the |<param>-link= parameter is ok); else false when value appears to be a valid URL (the |<param>-link= parameter is NOT ok). ]] local function link_param_ok (value) local scheme, domain; if value:find ('[<>%[%]|{}]') then -- if any prohibited characters return false; end scheme, domain = split_url (value); -- get scheme or nil and domain or nil from URL; return not is_url (scheme, domain); -- return true if value DOES NOT appear to be a valid URL end --[[--------------------------< L I N K _ T I T L E _ O K >--------------------------------------------------- Use link_param_ok() to validate |<param>-link= value and its matching |<title>= value. |<title>= may be wiki-linked but not when |<param>-link= has a value. This function emits an error message when that condition exists check <link> for inter-language interwiki-link prefix. prefix must be a MediaWiki-recognized language code and must begin with a colon. ]] local function link_title_ok (link, lorig, title, torig) local orig; if utilities.is_set (link) then -- don't bother if <param>-link doesn't have a value if not link_param_ok (link) then -- check |<param>-link= markup orig = lorig; -- identify the failing link parameter elseif title:find ('%[%[') then -- check |title= for wikilink markup orig = torig; -- identify the failing |title= parameter elseif link:match ('^%a+:') then -- if the link is what looks like an interwiki local prefix = link:match ('^(%a+):'):lower(); -- get the interwiki prefix if cfg.inter_wiki_map[prefix] then -- if prefix is in the map, must have preceding colon orig = lorig; -- flag as error end end end if utilities.is_set (orig) then link = ''; -- unset utilities.set_message ('err_bad_paramlink', orig); -- URL or wikilink in |title= with |title-link=; end return link; -- link if ok, empty string else end --[[--------------------------< C H E C K _ U R L >------------------------------------------------------------ Determines whether a URL string appears to be valid. First we test for space characters. If any are found, return false. Then split the URL into scheme and domain portions, or for protocol-relative (//example.com) URLs, just the domain. Use is_url() to validate the two portions of the URL. If both are valid, or for protocol-relative if domain is valid, return true, else false. Because it is different from a standard URL, and because this module used external_link() to make external links that work for standard and news: links, we validate newsgroup names here. The specification for a newsgroup name is at https://tools.ietf.org/html/rfc5536#section-3.1.4 ]] local function check_url( url_str ) if nil == url_str:match ("^%S+$") then -- if there are any spaces in |url=value it can't be a proper URL return false; end local scheme, domain; scheme, domain = split_url (url_str); -- get scheme or nil and domain or nil from URL; if 'news:' == scheme then -- special case for newsgroups return domain:match('^[%a%d%+%-_]+%.[%a%d%+%-_%.]*[%a%d%+%-_]$'); end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[=[-------------------------< I S _ P A R A M E T E R _ E X T _ W I K I L I N K >---------------------------- Return true if a parameter value has a string that begins and ends with square brackets [ and ] and the first non-space characters following the opening bracket appear to be a URL. The test will also find external wikilinks that use protocol-relative URLs. Also finds bare URLs. The frontier pattern prevents a match on interwiki-links which are similar to scheme:path URLs. The tests that find bracketed URLs are required because the parameters that call this test (currently |title=, |chapter=, |work=, and |publisher=) may have wikilinks and there are articles or redirects like '//Hus' so, while uncommon, |title=[[//Hus]] is possible as might be [[en://Hus]]. ]=] local function is_parameter_ext_wikilink (value) local scheme, domain; if value:match ('%f[%[]%[%a%S*:%S+.*%]') then -- if ext. wikilink with scheme and domain: [xxxx://yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(%a%S*:%S+).*%]')); elseif value:match ('%f[%[]%[//%S+.*%]') then -- if protocol-relative ext. wikilink: [//yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(//%S+).*%]')); elseif value:match ('%a%S*:%S+') then -- if bare URL with scheme; may have leading or trailing plain text scheme, domain = split_url (value:match ('(%a%S*:%S+)')); elseif value:match ('^//%S+') or value:match ('%s//%S+') then -- if protocol-relative bare URL: //yyyyy.zzz; authority indicator (//) must be be preceded nothing or by whitespace scheme, domain = split_url (value:match ('(//%S+)')); -- what is left should be the domain else return false; -- didn't find anything that is obviously a URL end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[[-------------------------< C H E C K _ F O R _ U R L >----------------------------------------------------- loop through a list of parameters and their values. Look at the value and if it has an external link, emit an error message. ]] local function check_for_url (parameter_list, error_list) for k, v in pairs (parameter_list) do -- for each parameter in the list if is_parameter_ext_wikilink (v) then -- look at the value; if there is a URL add an error message table.insert (error_list, utilities.wrap_style ('parameter', k)); end end end --[[--------------------------< S A F E _ F O R _ U R L >------------------------------------------------------ Escape sequences for content that will be used for URL descriptions ]] local function safe_for_url( str ) if str:match( "%[%[.-%]%]" ) ~= nil then utilities.set_message ('err_wikilink_in_url', {}); end return str:gsub( '[%[%]\n]', { ['['] = '&#91;', [']'] = '&#93;', ['\n'] = ' ' } ); end --[[--------------------------< E X T E R N A L _ L I N K >---------------------------------------------------- Format an external link with error checking ]] local function external_link (URL, label, source, access) local err_msg = ''; local domain; local path; local base_url; if not utilities.is_set (label) then label = URL; if utilities.is_set (source) then utilities.set_message ('err_bare_url_missing_title', {utilities.wrap_style ('parameter', source)}); else error (cfg.messages["bare_url_no_origin"]); -- programmer error; valid parameter name does not have matching meta-parameter end end if not check_url (URL) then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); end domain, path = URL:match ('^([/%.%-%+:%a%d]+)([/%?#].*)$'); -- split the URL into scheme plus domain and path if path then -- if there is a path portion path = path:gsub ('[%[%]]', {['['] = '%5b', [']'] = '%5d'}); -- replace '[' and ']' with their percent-encoded values URL = table.concat ({domain, path}); -- and reassemble end base_url = table.concat ({ "[", URL, " ", safe_for_url (label), "]" }); -- assemble a wiki-markup URL if utilities.is_set (access) then -- access level (subscription, registration, limited) base_url = utilities.substitute (cfg.presentation['ext-link-access-signal'], {cfg.presentation[access].class, cfg.presentation[access].title, base_url}); -- add the appropriate icon end return base_url; end --[[--------------------------< D E P R E C A T E D _ P A R A M E T E R >-------------------------------------- Categorize and emit an error message when the citation contains one or more deprecated parameters. The function includes the offending parameter name to the error message. Only one error message is emitted regardless of the number of deprecated parameters in the citation. added_deprecated_cat is a Boolean declared in page scope variables above ]] local function deprecated_parameter(name) if not added_deprecated_cat then added_deprecated_cat = true; -- note that we've added this category utilities.set_message ('err_deprecated_params', {name}); -- add error message end end --[=[-------------------------< K E R N _ Q U O T E S >-------------------------------------------------------- Apply kerning to open the space between the quote mark provided by the module and a leading or trailing quote mark contained in a |title= or |chapter= parameter's value. This function will positive kern either single or double quotes: "'Unkerned title with leading and trailing single quote marks'" " 'Kerned title with leading and trailing single quote marks' " (in real life the kerning isn't as wide as this example) Double single quotes (italic or bold wiki-markup) are not kerned. Replaces Unicode quote marks in plain text or in the label portion of a [[L|D]] style wikilink with typewriter quote marks regardless of the need for kerning. Unicode quote marks are not replaced in simple [[D]] wikilinks. Call this function for chapter titles, for website titles, etc.; not for book titles. ]=] local function kern_quotes (str) local cap = ''; local wl_type, label, link; wl_type, label, link = utilities.is_wikilink (str); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] if 1 == wl_type then -- [[D]] simple wikilink with or without quote marks if mw.ustring.match (str, '%[%[[\"“”\'‘’].+[\"“”\'‘’]%]%]') then -- leading and trailing quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); str = utilities.substitute (cfg.presentation['kern-right'], str); elseif mw.ustring.match (str, '%[%[[\"“”\'‘’].+%]%]') then -- leading quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); elseif mw.ustring.match (str, '%[%[.+[\"“”\'‘’]%]%]') then -- trailing quote marks str = utilities.substitute (cfg.presentation['kern-right'], str); end else -- plain text or [[L|D]]; text in label variable label = mw.ustring.gsub (label, '[“”]', '\"'); -- replace “” (U+201C & U+201D) with " (typewriter double quote mark) label = mw.ustring.gsub (label, '[‘’]', '\''); -- replace ‘’ (U+2018 & U+2019) with ' (typewriter single quote mark) cap = mw.ustring.match (label, "^([\"\'][^\'].+)"); -- match leading double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-left'], cap); end cap = mw.ustring.match (label, "^(.+[^\'][\"\'])$") -- match trailing double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-right'], cap); end if 2 == wl_type then str = utilities.make_wikilink (link, label); -- reassemble the wikilink else str = label; end end return str; end --[[--------------------------< F O R M A T _ S C R I P T _ V A L U E >---------------------------------------- |script-title= holds title parameters that are not written in Latin-based scripts: Chinese, Japanese, Arabic, Hebrew, etc. These scripts should not be italicized and may be written right-to-left. The value supplied by |script-title= is concatenated onto Title after Title has been wrapped in italic markup. Regardless of language, all values provided by |script-title= are wrapped in <bdi>...</bdi> tags to isolate RTL languages from the English left to right. |script-title= provides a unique feature. The value in |script-title= may be prefixed with a two-character ISO 639-1 language code and a colon: |script-title=ja:*** *** (where * represents a Japanese character) Spaces between the two-character code and the colon and the colon and the first script character are allowed: |script-title=ja : *** *** |script-title=ja: *** *** |script-title=ja :*** *** Spaces preceding the prefix are allowed: |script-title = ja:*** *** The prefix is checked for validity. If it is a valid ISO 639-1 language code, the lang attribute (lang="ja") is added to the <bdi> tag so that browsers can know the language the tag contains. This may help the browser render the script more correctly. If the prefix is invalid, the lang attribute is not added. At this time there is no error message for this condition. Supports |script-title=, |script-chapter=, |script-<periodical>= ]] local function format_script_value (script_value, script_param) local lang=''; -- initialize to empty string local name; if script_value:match('^%l%l%l?%s*:') then -- if first 3 or 4 non-space characters are script language prefix lang = script_value:match('^(%l%l%l?)%s*:%s*%S.*'); -- get the language prefix or nil if there is no script if not utilities.is_set (lang) then utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing title part']}); -- prefix without 'title'; add error message return ''; -- script_value was just the prefix so return empty string end -- if we get this far we have prefix and script name = cfg.lang_tag_remap[lang] or mw.language.fetchLanguageName( lang, cfg.this_wiki_code ); -- get language name so that we can use it to categorize if utilities.is_set (name) then -- is prefix a proper ISO 639-1 language code? script_value = script_value:gsub ('^%l+%s*:%s*', ''); -- strip prefix from script -- is prefix one of these language codes? if utilities.in_array (lang, cfg.script_lang_codes) then utilities.add_prop_cat ('script', {name, lang}) else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['unknown language code']}); -- unknown script-language; add error message end lang = ' lang="' .. lang .. '" '; -- convert prefix into a lang attribute else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['invalid language code']}); -- invalid language code; add error message lang = ''; -- invalid so set lang to empty string end else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing prefix']}); -- no language code prefix; add error message end script_value = utilities.substitute (cfg.presentation['bdi'], {lang, script_value}); -- isolate in case script is RTL return script_value; end --[[--------------------------< S C R I P T _ C O N C A T E N A T E >------------------------------------------ Initially for |title= and |script-title=, this function concatenates those two parameter values after the script value has been wrapped in <bdi> tags. ]] local function script_concatenate (title, script, script_param) if utilities.is_set (script) then script = format_script_value (script, script_param); -- <bdi> tags, lang attribute, categorization, etc.; returns empty string on error if utilities.is_set (script) then title = title .. ' ' .. script; -- concatenate title and script title end end return title; end --[[--------------------------< W R A P _ M S G >-------------------------------------------------------------- Applies additional message text to various parameter values. Supplied string is wrapped using a message_list configuration taking one argument. Supports lower case text for {{citation}} templates. Additional text taken from citation_config.messages - the reason this function is similar to but separate from wrap_style(). ]] local function wrap_msg (key, str, lower) if not utilities.is_set ( str ) then return ""; end if true == lower then local msg; msg = cfg.messages[key]:lower(); -- set the message to lower case before return utilities.substitute ( msg, str ); -- including template text else return utilities.substitute ( cfg.messages[key], str ); end end --[[----------------< W I K I S O U R C E _ U R L _ M A K E >------------------- Makes a Wikisource URL from Wikisource interwiki-link. Returns the URL and appropriate label; nil else. str is the value assigned to |chapter= (or aliases) or |title= or |title-link= ]] local function wikisource_url_make (str) local wl_type, D, L; local ws_url, ws_label; local wikisource_prefix = table.concat ({'https://', cfg.this_wiki_code, '.wikisource.org/wiki/'}); wl_type, D, L = utilities.is_wikilink (str); -- wl_type is 0 (not a wikilink), 1 (simple wikilink), 2 (complex wikilink) if 0 == wl_type then -- not a wikilink; might be from |title-link= str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 1 == wl_type then -- simple wikilink: [[Wikisource:ws article]] str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 2 == wl_type then -- non-so-simple wikilink: [[Wikisource:ws article|displayed text]] ([[L|D]]) str = L:match ('^[Ww]ikisource:(.+)') or L:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_label = D; -- get ws article name from display portion of interwiki link ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title without namespace from link portion of wikilink }); end end if ws_url then ws_url = mw.uri.encode (ws_url, 'WIKI'); -- make a usable URL ws_url = ws_url:gsub ('%%23', '#'); -- undo percent-encoding of fragment marker end return ws_url, ws_label, L or D; -- return proper URL or nil and a label or nil end --[[----------------< F O R M A T _ P E R I O D I C A L >----------------------- Format the three periodical parameters: |script-<periodical>=, |<periodical>=, and |trans-<periodical>= into a single Periodical meta-parameter. ]] local function format_periodical (script_periodical, script_periodical_source, periodical, trans_periodical) if not utilities.is_set (periodical) then periodical = ''; -- to be safe for concatenation else periodical = utilities.wrap_style ('italic-title', periodical); -- style end periodical = script_concatenate (periodical, script_periodical, script_periodical_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (trans_periodical) then trans_periodical = utilities.wrap_style ('trans-italic-title', trans_periodical); if utilities.is_set (periodical) then periodical = periodical .. ' ' .. trans_periodical; else -- here when trans-periodical without periodical or script-periodical periodical = trans_periodical; utilities.set_message ('err_trans_missing_title', {'periodical'}); end end return periodical; end --[[------------------< F O R M A T _ C H A P T E R _ T I T L E >--------------- Format the four chapter parameters: |script-chapter=, |chapter=, |trans-chapter=, and |chapter-url= into a single chapter meta- parameter (chapter_url_source used for error messages). ]] local function format_chapter_title (script_chapter, script_chapter_source, chapter, chapter_source, trans_chapter, trans_chapter_source, chapter_url, chapter_url_source, no_quotes, access) local ws_url, ws_label, L = wikisource_url_make (chapter); -- make a wikisource URL and label from a wikisource interwiki link if ws_url then ws_label = ws_label:gsub ('_', ' '); -- replace underscore separators with space characters chapter = ws_label; end if not utilities.is_set (chapter) then chapter = ''; -- to be safe for concatenation else if false == no_quotes then chapter = kern_quotes (chapter); -- if necessary, separate chapter title's leading and trailing quote marks from module provided quote marks chapter = utilities.wrap_style ('quoted-title', chapter); end end chapter = script_concatenate (chapter, script_chapter, script_chapter_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (chapter_url) then chapter = external_link (chapter_url, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate elseif ws_url then chapter = external_link (ws_url, chapter .. '&nbsp;', 'ws link in chapter'); -- adds bare_url_missing_title error if appropriate; space char to move icon away from chap text; TODO: better way to do this? chapter = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, chapter}); end if utilities.is_set (trans_chapter) then trans_chapter = utilities.wrap_style ('trans-quoted-title', trans_chapter); if utilities.is_set (chapter) then chapter = chapter .. ' ' .. trans_chapter; else -- here when trans_chapter without chapter or script-chapter chapter = trans_chapter; chapter_source = trans_chapter_source:match ('trans%-?(.+)'); -- when no chapter, get matching name from trans-<param> utilities.set_message ('err_trans_missing_title', {chapter_source}); end end return chapter; end --[[----------------< H A S _ I N V I S I B L E _ C H A R S >------------------- This function searches a parameter's value for non-printable or invisible characters. The search stops at the first match. This function will detect the visible replacement character when it is part of the Wikisource. Detects but ignores nowiki and math stripmarkers. Also detects other named stripmarkers (gallery, math, pre, ref) and identifies them with a slightly different error message. See also coins_cleanup(). Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker that was detected along with its position (or, for multi-byte characters, the position of its first byte) in the parameter value. ]] local function has_invisible_chars (param, v) local position = ''; -- position of invisible char or starting position of stripmarker local capture; -- used by stripmarker detection to hold name of the stripmarker local stripmarker; -- boolean set true when a stripmarker is found capture = string.match (v, '[%w%p ]*'); -- test for values that are simple ASCII text and bypass other tests if true if capture == v then -- if same there are no Unicode characters return; end for _, invisible_char in ipairs (cfg.invisible_chars) do local char_name = invisible_char[1]; -- the character or group name local pattern = invisible_char[2]; -- the pattern used to find it position, _, capture = mw.ustring.find (v, pattern); -- see if the parameter value contains characters that match the pattern if position and (cfg.invisible_defs.zwj == capture) then -- if we found a zero-width joiner character if mw.ustring.find (v, cfg.indic_script) then -- it's ok if one of the Indic scripts position = nil; -- unset position elseif cfg.emoji_t[mw.ustring.codepoint (v, position+1)] then -- is zwj followed by a character listed in emoji{}? position = nil; -- unset position end end if position then if 'nowiki' == capture or 'math' == capture or -- nowiki and math stripmarkers (not an error condition) ('templatestyles' == capture and utilities.in_array (param, {'id', 'quote'})) then -- templatestyles stripmarker allowed in these parameters stripmarker = true; -- set a flag elseif true == stripmarker and cfg.invisible_defs.del == capture then -- because stripmakers begin and end with the delete char, assume that we've found one end of a stripmarker position = nil; -- unset else local err_msg; if capture and not (cfg.invisible_defs.del == capture or cfg.invisible_defs.zwj == capture) then err_msg = capture .. ' ' .. char_name; else err_msg = char_name .. ' ' .. 'character'; end utilities.set_message ('err_invisible_char', {err_msg, utilities.wrap_style ('parameter', param), position}); -- add error message return; -- and done with this parameter end end end end --[[-------------------< A R G U M E N T _ W R A P P E R >---------------------- Argument wrapper. This function provides support for argument mapping defined in the configuration file so that multiple names can be transparently aliased to single internal variable. ]] local function argument_wrapper ( args ) local origin = {}; return setmetatable({ ORIGIN = function ( self, k ) local dummy = self[k]; -- force the variable to be loaded. return origin[k]; end }, { __index = function ( tbl, k ) if origin[k] ~= nil then return nil; end local args, list, v = args, cfg.aliases[k]; if type( list ) == 'table' then v, origin[k] = utilities.select_one ( args, list, 'err_redundant_parameters' ); if origin[k] == nil then origin[k] = ''; -- Empty string, not nil end elseif list ~= nil then v, origin[k] = args[list], list; else -- maybe let through instead of raising an error? -- v, origin[k] = args[k], k; error( cfg.messages['unknown_argument_map'] .. ': ' .. k); end -- Empty strings, not nil; if v == nil then v = ''; origin[k] = ''; end tbl = rawset( tbl, k, v ); return v; end, }); end --[[--------------------------< N O W R A P _ D A T E >------------------------- When date is YYYY-MM-DD format wrap in nowrap span: <span ...>YYYY-MM-DD</span>. When date is DD MMMM YYYY or is MMMM DD, YYYY then wrap in nowrap span: <span ...>DD MMMM</span> YYYY or <span ...>MMMM DD,</span> YYYY DOES NOT yet support MMMM YYYY or any of the date ranges. ]] local function nowrap_date (date) local cap = ''; local cap2 = ''; if date:match("^%d%d%d%d%-%d%d%-%d%d$") then date = utilities.substitute (cfg.presentation['nowrap1'], date); elseif date:match("^%a+%s*%d%d?,%s+%d%d%d%d$") or date:match ("^%d%d?%s*%a+%s+%d%d%d%d$") then cap, cap2 = string.match (date, "^(.*)%s+(%d%d%d%d)$"); date = utilities.substitute (cfg.presentation['nowrap2'], {cap, cap2}); end return date; end --[[--------------------------< S E T _ T I T L E T Y P E >--------------------- This function sets default title types (equivalent to the citation including |type=<default value>) for those templates that have defaults. Also handles the special case where it is desirable to omit the title type from the rendered citation (|type=none). ]] local function set_titletype (cite_class, title_type) if utilities.is_set (title_type) then if 'none' == cfg.keywords_xlate[title_type] then title_type = ''; -- if |type=none then type parameter not displayed end return title_type; -- if |type= has been set to any other value use that value end return cfg.title_types [cite_class] or ''; -- set template's default title type; else empty string for concatenation end --[[--------------------------< S A F E _ J O I N >----------------------------- Joins a sequence of strings together while checking for duplicate separation characters. ]] local function safe_join( tbl, duplicate_char ) local f = {}; -- create a function table appropriate to type of 'duplicate character' if 1 == #duplicate_char then -- for single byte ASCII characters use the string library functions f.gsub = string.gsub f.match = string.match f.sub = string.sub else -- for multi-byte characters use the ustring library functions f.gsub = mw.ustring.gsub f.match = mw.ustring.match f.sub = mw.ustring.sub end local str = ''; -- the output string local comp = ''; -- what does 'comp' mean? local end_chr = ''; local trim; for _, value in ipairs( tbl ) do if value == nil then value = ''; end if str == '' then -- if output string is empty str = value; -- assign value to it (first time through the loop) elseif value ~= '' then if value:sub(1, 1) == '<' then -- special case of values enclosed in spans and other markup. comp = value:gsub( "%b<>", "" ); -- remove HTML markup (<span>string</span> -> string) else comp = value; end -- typically duplicate_char is sepc if f.sub(comp, 1, 1) == duplicate_char then -- is first character same as duplicate_char? why test first character? -- Because individual string segments often (always?) begin with terminal punct for the -- preceding segment: 'First element' .. 'sepc next element' .. etc.? trim = false; end_chr = f.sub(str, -1, -1); -- get the last character of the output string -- str = str .. "<HERE(enchr=" .. end_chr .. ")" -- debug stuff? if end_chr == duplicate_char then -- if same as separator str = f.sub(str, 1, -2); -- remove it elseif end_chr == "'" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "''" then -- if last three chars of str are sepc'' str = f.sub(str, 1, -4) .. "''"; -- remove them and add back '' elseif f.sub(str, -5, -1) == duplicate_char .. "]]''" then -- if last five chars of str are sepc]]'' trim = true; -- why? why do this and next differently from previous? elseif f.sub(str, -4, -1) == duplicate_char .. "]''" then -- if last four chars of str are sepc]'' trim = true; -- same question end elseif end_chr == "]" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "]]" then -- if last three chars of str are sepc]] wikilink trim = true; elseif f.sub(str, -3, -1) == duplicate_char .. '"]' then -- if last three chars of str are sepc"] quoted external link trim = true; elseif f.sub(str, -2, -1) == duplicate_char .. "]" then -- if last two chars of str are sepc] external link trim = true; elseif f.sub(str, -4, -1) == duplicate_char .. "'']" then -- normal case when |url=something & |title=Title. trim = true; end elseif end_chr == " " then -- if last char of output string is a space if f.sub(str, -2, -1) == duplicate_char .. " " then -- if last two chars of str are <sepc><space> str = f.sub(str, 1, -3); -- remove them both end end if trim then if value ~= comp then -- value does not equal comp when value contains HTML markup local dup2 = duplicate_char; if f.match(dup2, "%A" ) then dup2 = "%" .. dup2; end -- if duplicate_char not a letter then escape it value = f.gsub(value, "(%b<>)" .. dup2, "%1", 1 ) -- remove duplicate_char if it follows HTML markup else value = f.sub(value, 2, -1 ); -- remove duplicate_char when it is first character end end end str = str .. value; -- add it to the output string end end return str; end --[[--------------------------< I S _ S U F F I X >----------------------------- returns true if suffix is properly formed Jr, Sr, or ordinal in the range 1–9. Puncutation not allowed. ]] local function is_suffix (suffix) if utilities.in_array (suffix, {'Jr', 'Sr', 'Jnr', 'Snr', '1st', '2nd', '3rd'}) or suffix:match ('^%dth$') then return true; end return false; end --[[--------------------< I S _ G O O D _ V A N C _ N A M E >------------------- For Vancouver style, author/editor names are supposed to be rendered in Latin (read ASCII) characters. When a name uses characters that contain diacritical marks, those characters are to be converted to the corresponding Latin character. When a name is written using a non-Latin alphabet or logogram, that name is to be transliterated into Latin characters. The module doesn't do this so editors may/must. This test allows |first= and |last= names to contain any of the letters defined in the four Unicode Latin character sets [http://www.unicode.org/charts/PDF/U0000.pdf C0 Controls and Basic Latin] 0041–005A, 0061–007A [http://www.unicode.org/charts/PDF/U0080.pdf C1 Controls and Latin-1 Supplement] 00C0–00D6, 00D8–00F6, 00F8–00FF [http://www.unicode.org/charts/PDF/U0100.pdf Latin Extended-A] 0100–017F [http://www.unicode.org/charts/PDF/U0180.pdf Latin Extended-B] 0180–01BF, 01C4–024F |lastn= also allowed to contain hyphens, spaces, and apostrophes. (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) |firstn= also allowed to contain hyphens, spaces, apostrophes, and periods This original test: if nil == mw.ustring.find (last, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%'%.]+[2-6%a]*$") then was written outside of the code editor and pasted here because the code editor gets confused between character insertion point and cursor position. The test has been rewritten to use decimal character escape sequence for the individual bytes of the Unicode characters so that it is not necessary to use an external editor to maintain this code. \195\128-\195\150 – À-Ö (U+00C0–U+00D6 – C0 controls) \195\152-\195\182 – Ø-ö (U+00D8-U+00F6 – C0 controls) \195\184-\198\191 – ø-ƿ (U+00F8-U+01BF – C0 controls, Latin extended A & B) \199\132-\201\143 – DŽ-ɏ (U+01C4-U+024F – Latin extended B) ]] local function is_good_vanc_name (last, first, suffix, position) if not suffix then if first:find ('[,%s]') then -- when there is a space or comma, might be first name/initials + generational suffix first = first:match ('(.-)[,%s]+'); -- get name/initials suffix = first:match ('[,%s]+(.+)$'); -- get generational suffix end end if utilities.is_set (suffix) then if not is_suffix (suffix) then add_vanc_error (cfg.err_msg_supl.suffix, position); return false; -- not a name with an appropriate suffix end end if nil == mw.ustring.find (last, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%'%.]*$") then add_vanc_error (cfg.err_msg_supl['non-Latin char'], position); return false; -- not a string of Latin characters; Vancouver requires Romanization end; return true; end --[[--------------------------< R E D U C E _ T O _ I N I T I A L S >------------------------------------------ Attempts to convert names to initials in support of |name-list-style=vanc. Names in |firstn= may be separated by spaces or hyphens, or for initials, a period. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35062/. Vancouver style requires family rank designations (Jr, II, III, etc.) to be rendered as Jr, 2nd, 3rd, etc. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35085/. This code only accepts and understands generational suffix in the Vancouver format because Roman numerals look like, and can be mistaken for, initials. This function uses ustring functions because firstname initials may be any of the Unicode Latin characters accepted by is_good_vanc_name (). ]] local function reduce_to_initials (first, position) if first:find (',', 1, true) then return first; -- commas not allowed; abandon end local name, suffix = mw.ustring.match (first, "^(%u+) ([%dJS][%drndth]+)$"); if not name then -- if not initials and a suffix name = mw.ustring.match (first, "^(%u+)$"); -- is it just initials? end if name then -- if first is initials with or without suffix if 3 > mw.ustring.len (name) then -- if one or two initials if suffix then -- if there is a suffix if is_suffix (suffix) then -- is it legitimate? return first; -- one or two initials and a valid suffix so nothing to do else add_vanc_error (cfg.err_msg_supl.suffix, position); -- one or two initials with invalid suffix so error message return first; -- and return first unmolested end else return first; -- one or two initials without suffix; nothing to do end end end -- if here then name has 3 or more uppercase letters so treat them as a word local initials_t, names_t = {}, {}; -- tables to hold name parts and initials local i = 1; -- counter for number of initials names_t = mw.text.split (first, '[%s%-]+'); -- split into a sequence of names and possible suffix while names_t[i] do -- loop through the sequence if 1 < i and names_t[i]:match ('[%dJS][%drndth]+%.?$') then -- if not the first name, and looks like a suffix (may have trailing dot) names_t[i] = names_t[i]:gsub ('%.', ''); -- remove terminal dot if present if is_suffix (names_t[i]) then -- if a legitimate suffix table.insert (initials_t, ' ' .. names_t[i]); -- add a separator space, insert at end of initials sequence break; -- and done because suffix must fall at the end of a name end -- no error message if not a suffix; possibly because of Romanization end if 3 > i then table.insert (initials_t, mw.ustring.sub (names_t[i], 1, 1)); -- insert the initial at end of initials sequence end i = i + 1; -- bump the counter end return table.concat (initials_t); -- Vancouver format does not include spaces. end --[[--------------------------< I N T E R W I K I _ P R E F I X E N _ G E T >---------------------------------- extract interwiki prefixen from <value>. Returns two one or two values: false – no prefixen nil – prefix exists but not recognized project prefix, language prefix – when value has either of: :<project>:<language>:<article> :<language>:<project>:<article> project prefix, nil – when <value> has only a known single-letter prefix nil, language prefix – when <value> has only a known language prefix accepts single-letter project prefixen: 'd' (wikidata), 's' (wikisource), and 'w' (wikipedia) prefixes; at this writing, the other single-letter prefixen (b (wikibook), c (commons), m (meta), n (wikinews), q (wikiquote), and v (wikiversity)) are not supported. ]] local function interwiki_prefixen_get (value, is_link) if not value:find (':%l+:') then -- if no prefix return false; -- abandon; boolean here to distinguish from nil fail returns later end local prefix_patterns_linked_t = { -- sequence of valid interwiki and inter project prefixen '^%[%[:([dsw]):(%l%l+):', -- wikilinked; project and language prefixes '^%[%[:(%l%l+):([dsw]):', -- wikilinked; language and project prefixes '^%[%[:([dsw]):', -- wikilinked; project prefix '^%[%[:(%l%l+):', -- wikilinked; language prefix } local prefix_patterns_unlinked_t = { -- sequence of valid interwiki and inter project prefixen '^:([dsw]):(%l%l+):', -- project and language prefixes '^:(%l%l+):([dsw]):', -- language and project prefixes '^:([dsw]):', -- project prefix '^:(%l%l+):', -- language prefix } local cap1, cap2; for _, pattern in ipairs ((is_link and prefix_patterns_linked_t) or prefix_patterns_unlinked_t) do cap1, cap2 = value:match (pattern); if cap1 then break; -- found a match so stop looking end end if cap1 and cap2 then -- when both then :project:language: or :language:project: (both forms allowed) if 1 == #cap1 then -- length == 1 then :project:language: if cfg.inter_wiki_map[cap2] then -- is language prefix in the interwiki map? return cap1, cap2; -- return interwiki project and interwiki language end else -- here when :language:project: if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return cap2, cap1; -- return interwiki project and interwiki language end end return nil; -- unknown interwiki language elseif not (cap1 or cap2) then -- both are nil? return nil; -- we got something that looks like a project prefix but isn't; return fail elseif 1 == #cap1 then -- here when one capture return cap1, nil; -- length is 1 so return project, nil language else -- here when one capture and its length it more than 1 if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return nil, cap1; -- return nil project, language end end end --[[--------------------------< L I S T _ P E O P L E >-------------------------- Formats a list of people (authors, contributors, editors, interviewers, translators) names in the list will be linked when |<name>-link= has a value |<name>-mask- does NOT have a value; masked names are presumed to have been rendered previously so should have been linked there when |<name>-mask=0, the associated name is not rendered ]] local function list_people (control, people, etal) local sep; local namesep; local format = control.format; local maximum = control.maximum; local name_list = {}; if 'vanc' == format then -- Vancouver-like name styling? sep = cfg.presentation['sep_nl_vanc']; -- name-list separator between names is a comma namesep = cfg.presentation['sep_name_vanc']; -- last/first separator is a space else sep = cfg.presentation['sep_nl']; -- name-list separator between names is a semicolon namesep = cfg.presentation['sep_name']; -- last/first separator is <comma><space> end if sep:sub (-1, -1) ~= " " then sep = sep .. " " end if utilities.is_set (maximum) and maximum < 1 then return "", 0; end -- returned 0 is for EditorCount; not used for other names for i, person in ipairs (people) do if utilities.is_set (person.last) then local mask = person.mask; local one; local sep_one = sep; if utilities.is_set (maximum) and i > maximum then etal = true; break; end if mask then local n = tonumber (mask); -- convert to a number if it can be converted; nil else if n then one = 0 ~= n and string.rep("&mdash;", n) or nil; -- make a string of (n > 0) mdashes, nil else, to replace name person.link = nil; -- don't create link to name if name is replaces with mdash string or has been set nil else one = mask; -- replace name with mask text (must include name-list separator) sep_one = " "; -- modify name-list separator end else one = person.last; -- get surname local first = person.first -- get given name if utilities.is_set (first) then if ("vanc" == format) then -- if Vancouver format one = one:gsub ('%.', ''); -- remove periods from surnames (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) if not person.corporate and is_good_vanc_name (one, first, nil, i) then -- and name is all Latin characters; corporate authors not tested first = reduce_to_initials (first, i); -- attempt to convert first name(s) to initials end end one = one .. namesep .. first; end end if utilities.is_set (person.link) then one = utilities.make_wikilink (person.link, one); -- link author/editor end if one then -- if <one> has a value (name, mdash replacement, or mask text replacement) local proj, tag = interwiki_prefixen_get (one, true); -- get the interwiki prefixen if present if 'w' == proj and ('Wikipedia' == mw.site.namespaces.Project['name']) then proj = nil; -- for stuff like :w:de:<article>, :w is unnecessary TODO: maint cat? end if proj then local proj_name = ({['d'] = 'Wikidata', ['s'] = 'Wikisource', ['w'] = 'Wikipedia'})[proj]; -- :w (wikipedia) for linking from a non-wikipedia project if proj_name then one = one .. utilities.wrap_style ('interproj', proj_name); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interproj-linked-name', proj); -- categorize it; <proj> is sort key tag = nil; -- unset; don't do both project and language end end if tag == cfg.this_wiki_code then tag = nil; -- stuff like :en:<article> at en.wiki is pointless TODO: maint cat? end if tag then local lang = cfg.lang_tag_remap[tag] or cfg.mw_languages_by_tag_t[tag]; if lang then -- error messaging done in extract_names() where we know parameter names one = one .. utilities.wrap_style ('interwiki', lang); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interwiki-linked-name', tag); -- categorize it; <tag> is sort key end end table.insert (name_list, one); -- add it to the list of names table.insert (name_list, sep_one); -- add the proper name-list separator end end end local count = #name_list / 2; -- (number of names + number of separators) divided by 2 if 0 < count then if 1 < count and not etal then if 'amp' == format then name_list[#name_list-2] = " & "; -- replace last separator with ampersand text elseif 'and' == format then if 2 == count then name_list[#name_list-2] = cfg.presentation.sep_nl_and; -- replace last separator with 'and' text else name_list[#name_list-2] = cfg.presentation.sep_nl_end; -- replace last separator with '(sep) and' text end end end name_list[#name_list] = nil; -- erase the last separator end local result = table.concat (name_list); -- construct list if etal and utilities.is_set (result) then -- etal may be set by |display-authors=etal but we might not have a last-first list result = result .. sep .. cfg.messages['et al']; -- we've got a last-first list and etal so add et al. end return result, count; -- return name-list string and count of number of names (count used for editor names only) end --[[--------------------< M A K E _ C I T E R E F _ I D >----------------------- Generates a CITEREF anchor ID if we have at least one name or a date. Otherwise returns an empty string. namelist is one of the contributor-, author-, or editor-name lists chosen in that order. year is Year or anchor_year. ]] local function make_citeref_id (namelist, year) local names={}; -- a table for the one to four names and year for i,v in ipairs (namelist) do -- loop through the list and take up to the first four last names names[i] = v.last if i == 4 then break end -- if four then done end table.insert (names, year); -- add the year at the end local id = table.concat(names); -- concatenate names and year for CITEREF id if utilities.is_set (id) then -- if concatenation is not an empty string return "CITEREF" .. id; -- add the CITEREF portion else return ''; -- return an empty string; no reason to include CITEREF id in this citation end end --[[--------------------------< C I T E _ C L A S S _A T T R I B U T E _M A K E >------------------------------ construct <cite> tag class attribute for this citation. <cite_class> – config.CitationClass from calling template <mode> – value from |mode= parameter ]] local function cite_class_attribute_make (cite_class, mode) local class_t = {}; table.insert (class_t, 'citation'); -- required for blue highlight if 'citation' ~= cite_class then table.insert (class_t, cite_class); -- identify this template for user css table.insert (class_t, utilities.is_set (mode) and mode or 'cs1'); -- identify the citation style for user css or javascript else table.insert (class_t, utilities.is_set (mode) and mode or 'cs2'); -- identify the citation style for user css or javascript end for _, prop_key in ipairs (z.prop_keys_t) do table.insert (class_t, prop_key); -- identify various properties for user css or javascript end return table.concat (class_t, ' '); -- make a big string and done end --[[---------------------< N A M E _ H A S _ E T A L >-------------------------- Evaluates the content of name parameters (author, editor, etc.) for variations on the theme of et al. If found, the et al. is removed, a flag is set to true and the function returns the modified name and the flag. This function never sets the flag to false but returns its previous state because it may have been set by previous passes through this function or by the associated |display-<names>=etal parameter ]] local function name_has_etal (name, etal, nocat, param) if utilities.is_set (name) then -- name can be nil in which case just return local patterns = cfg.et_al_patterns; -- get patterns from configuration for _, pattern in ipairs (patterns) do -- loop through all of the patterns if name:match (pattern) then -- if this 'et al' pattern is found in name name = name:gsub (pattern, ''); -- remove the offending text etal = true; -- set flag (may have been set previously here or by |display-<names>=etal) if not nocat then -- no categorization for |vauthors= utilities.set_message ('err_etal', {param}); -- and set an error if not added end end end end return name, etal; end --[[---------------------< N A M E _ I S _ N U M E R I C >---------------------- Add an error message and category when <name> parameter value does not contain letters. Add a maintenance category when <name> parameter value has numeric characters mixed with characters that are not numeric characters; could be letters and/or punctuation characters. This function will only emit one error and one maint message for the current template. Does not emit both error and maint messages/categories for the same parameter value. returns nothing ]] local function name_is_numeric (name, name_alias, list_name) local patterns = { '^%D+%d', -- <name> must have digits preceded by other characters '^%D*%d+%D+', -- <name> must have digits followed by other characters } if not added_numeric_name_errs and mw.ustring.match (name, '^[%A]+$') then -- if we have not already set an error message and <name> does not have any alpha characters utilities.set_message ('err_numeric_names', name_alias); -- add an error message added_numeric_name_errs = true; -- set the flag so we emit only one error message return; -- when here no point in further testing; abandon end if not added_numeric_name_maint then -- if we have already set a maint message for _, pattern in ipairs (patterns) do -- spin through list of patterns if mw.ustring.match (name, pattern) then -- digits preceded or followed by anything but digits; %D+ includes punctuation utilities.set_message ('maint_numeric_names', cfg.special_case_translation [list_name]); -- add a maint cat for this template added_numeric_name_maint = true; -- set the flag so we emit only one maint message return; -- when here no point in further testing; abandon end end end end --[[-----------------< N A M E _ H A S _ M U L T _ N A M E S >------------------ Evaluates the content of last/surname (authors etc.) parameters for multiple names. Multiple names are indicated if there is more than one comma or any "unescaped" semicolons. Escaped semicolons are ones used as part of selected HTML entities. If the condition is met, the function adds the multiple name maintenance category. Same test for first except that commas should not appear in given names (MOS:JR says that the generational suffix does not take a separator character). Titles, degrees, postnominals, affiliations, all normally comma separated don't belong in a citation. <name> – name parameter value <list_name> – AuthorList, EditorList, etc <limit> – number of allowed commas; 1 (default) for surnames; 0 for given names returns nothing ]] local function name_has_mult_names (name, list_name, limit) local _, commas, semicolons, nbsps; limit = limit and limit or 1; if utilities.is_set (name) then _, commas = name:gsub (',', ''); -- count the number of commas _, semicolons = name:gsub (';', ''); -- count the number of semicolons -- nbsps probably should be its own separate count rather than merged in -- some way with semicolons because Lua patterns do not support the -- grouping operator that regex does, which means there is no way to add -- more entities to escape except by adding more counts with the new -- entities _, nbsps = name:gsub ('&nbsp;',''); -- count nbsps -- There is exactly 1 semicolon per &nbsp; entity, so subtract nbsps -- from semicolons to 'escape' them. If additional entities are added, -- they also can be subtracted. if limit < commas or 0 < (semicolons - nbsps) then utilities.set_message ('maint_mult_names', cfg.special_case_translation [list_name]); -- add a maint message end end end --[=[-------------------------< I S _ G E N E R I C >---------------------------------------------------------- Compares values assigned to various parameters according to the string provided as <item> in the function call. <item> can have on of two values: 'generic_names' – for name-holding parameters: |last=, |first=, |editor-last=, etc 'generic_titles' – for |title= There are two types of generic tests. The 'accept' tests look for a pattern that should not be rejected by the 'reject' test. For example, |author=[[John Smith (author)|Smith, John]] would be rejected by the 'author' reject test. But piped wikilinks with 'author' disambiguation should not be rejected so the 'accept' test prevents that from happening. Accept tests are always performed before reject tests. Each of the 'accept' and 'reject' sequence tables hold tables for en.wiki (['en']) and local.wiki (['local']) that each can hold a test sequence table The sequence table holds, at index [1], a test pattern, and, at index [2], a boolean control value. The control value tells string.find() or mw.ustring.find() to do plain-text search (true) or a pattern search (false). The intent of all this complexity is to make these searches as fast as possible so that we don't run out of processing time on very large articles. Returns true when a reject test finds the pattern or string false when an accept test finds the pattern or string nil else ]=] local function is_generic (item, value, wiki) local test_val; local str_lower = { -- use string.lower() for en.wiki (['en']) and use mw.ustring.lower() or local.wiki (['local']) ['en'] = string.lower, ['local'] = mw.ustring.lower, } local str_find = { -- use string.find() for en.wiki (['en']) and use mw.ustring.find() or local.wiki (['local']) ['en'] = string.find, ['local'] = mw.ustring.find, } local function test (val, test_t, wiki) -- local function to do the testing; <wiki> selects lower() and find() functions val = test_t[2] and str_lower[wiki](value) or val; -- when <test_t[2]> set to 'true', plaintext search using lowercase value return str_find[wiki] (val, test_t[1], 1, test_t[2]); -- return nil when not found or matched end local test_types_t = {'accept', 'reject'}; -- test accept patterns first, then reject patterns local wikis_t = {'en', 'local'}; -- do tests for each of these keys; en.wiki first, local.wiki second for _, test_type in ipairs (test_types_t) do -- for each test type for _, generic_value in pairs (cfg.special_case_translation[item][test_type]) do -- spin through the list of generic value fragments to accept or reject for _, wiki in ipairs (wikis_t) do if generic_value[wiki] then if test (value, generic_value[wiki], wiki) then -- go do the test return ('reject' == test_type); -- param value rejected, return true; false else end end end end end end --[[--------------------------< N A M E _ I S _ G E N E R I C >------------------------------------------------ calls is_generic() to determine if <name> is a 'generic name' listed in cfg.generic_names; <name_alias> is the parameter name used in error messaging ]] local function name_is_generic (name, name_alias) if not added_generic_name_errs and is_generic ('generic_names', name) then utilities.set_message ('err_generic_name', name_alias); -- set an error message added_generic_name_errs = true; end end --[[--------------------------< N A M E _ C H E C K S >-------------------------------------------------------- This function calls various name checking functions used to validate the content of the various name-holding parameters. ]] local function name_checks (last, first, list_name, last_alias, first_alias) local accept_name; if utilities.is_set (last) then last, accept_name = utilities.has_accept_as_written (last); -- remove accept-this-as-written markup when it wraps all of <last> if not accept_name then -- <last> not wrapped in accept-as-written markup name_has_mult_names (last, list_name); -- check for multiple names in the parameter name_is_numeric (last, last_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (last, last_alias); -- check for names found in the generic names list end end if utilities.is_set (first) then first, accept_name = utilities.has_accept_as_written (first); -- remove accept-this-as-written markup when it wraps all of <first> if not accept_name then -- <first> not wrapped in accept-as-written markup name_has_mult_names (first, list_name, 0); -- check for multiple names in the parameter; 0 is number of allowed commas in a given name name_is_numeric (first, first_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (first, first_alias); -- check for names found in the generic names list end local wl_type, D = utilities.is_wikilink (first); if 0 ~= wl_type then first = D; utilities.set_message ('err_bad_paramlink', first_alias); end end return last, first; -- done end --[[----------------------< E X T R A C T _ N A M E S >------------------------- Gets name list from the input arguments Searches through args in sequential order to find |lastn= and |firstn= parameters (or their aliases), and their matching link and mask parameters. Stops searching when both |lastn= and |firstn= are not found in args after two sequential attempts: found |last1=, |last2=, and |last3= but doesn't find |last4= and |last5= then the search is done. This function emits an error message when there is a |firstn= without a matching |lastn=. When there are 'holes' in the list of last names, |last1= and |last3= are present but |last2= is missing, an error message is emitted. |lastn= is not required to have a matching |firstn=. When an author or editor parameter contains some form of 'et al.', the 'et al.' is stripped from the parameter and a flag (etal) returned that will cause list_people() to add the static 'et al.' text from Module:Citation/CS1/Configuration. This keeps 'et al.' out of the template's metadata. When this occurs, an error is emitted. ]] local function extract_names(args, list_name) local names = {}; -- table of names local last; -- individual name components local first; local link; local mask; local i = 1; -- loop counter/indexer local n = 1; -- output table indexer local count = 0; -- used to count the number of times we haven't found a |last= (or alias for authors, |editor-last or alias for editors) local etal = false; -- return value set to true when we find some form of et al. in an author parameter local last_alias, first_alias, link_alias; -- selected parameter aliases used in error messaging while true do last, last_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'err_redundant_parameters', i ); -- search through args for name components beginning at 1 first, first_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'err_redundant_parameters', i ); link, link_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ); mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); if last then -- error check |lastn= alias for unknown interwiki link prefix; done here because this is where we have the parameter name local project, language = interwiki_prefixen_get (last, true); -- true because we expect interwiki links in |lastn= to be wikilinked if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', last_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? last = utilities.remove_wiki_link (last); -- remove wikilink markup; show display value only end end if link then -- error check |linkn= alias for unknown interwiki link prefix local project, language = interwiki_prefixen_get (link, false); -- false because wiki links in |author-linkn= is an error if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', link_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? link = nil; -- unset so we don't link link_alias = nil; end end last, etal = name_has_etal (last, etal, false, last_alias); -- find and remove variations on et al. first, etal = name_has_etal (first, etal, false, first_alias); -- find and remove variations on et al. last, first = name_checks (last, first, list_name, last_alias, first_alias); -- multiple names, extraneous annotation, etc. checks if first and not last then -- if there is a firstn without a matching lastn local alias = first_alias:find ('given', 1, true) and 'given' or 'first'; -- get first or given form of the alias utilities.set_message ('err_first_missing_last', { first_alias, -- param name of alias missing its mate first_alias:gsub (alias, {['first'] = 'last', ['given'] = 'surname'}), -- make param name appropriate to the alias form }); -- add this error message elseif not first and not last then -- if both firstn and lastn aren't found, are we done? count = count + 1; -- number of times we haven't found last and first if 2 <= count then -- two missing names and we give up break; -- normal exit or there is a two-name hole in the list; can't tell which end else -- we have last with or without a first local result; link = link_title_ok (link, link_alias, last, last_alias); -- check for improper wiki-markup if first then link = link_title_ok (link, link_alias, first, first_alias); -- check for improper wiki-markup end names[n] = {last = last, first = first, link = link, mask = mask, corporate = false}; -- add this name to our names list (corporate for |vauthors= only) n = n + 1; -- point to next location in the names table if 1 == count then -- if the previous name was missing utilities.set_message ('err_missing_name', {list_name:match ("(%w+)List"):lower(), i - 1}); -- add this error message end count = 0; -- reset the counter, we're looking for two consecutive missing names end i = i + 1; -- point to next args location end return names, etal; -- all done, return our list of names and the etal flag end --[[--------------------------< N A M E _ T A G _ G E T >------------------------------------------------------ attempt to decode |language=<lang_param> and return language name and matching tag; nil else. This function looks for: <lang_param> as a tag in cfg.lang_tag_remap{} <lang_param> as a name in cfg.lang_name_remap{} <lang_param> as a name in cfg.mw_languages_by_name_t <lang_param> as a tag in cfg.mw_languages_by_tag_t when those fail, presume that <lang_param> is an IETF-like tag that MediaWiki does not recognize. Strip all script, region, variant, whatever subtags from <lang_param> to leave just a two or three character language tag and look for the new <lang_param> in cfg.mw_languages_by_tag_t{} on success, returns name (in properly capitalized form) and matching tag (in lowercase); on failure returns nil ]] local function name_tag_get (lang_param) local lang_param_lc = mw.ustring.lower (lang_param); -- use lowercase as an index into the various tables local name; local tag; name = cfg.lang_tag_remap[lang_param_lc]; -- assume <lang_param_lc> is a tag; attempt to get remapped language name if name then -- when <name>, <lang_param> is a tag for a remapped language name if cfg.lang_name_remap[name:lower()][2] ~= lang_param_lc then utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added return name, cfg.lang_name_remap[name:lower()][2]; -- so return name and tag from lang_name_remap[name]; special case to xlate sr-ec and sr-el to sr-cyrl and sr-latn end return name, lang_param_lc; -- so return <name> from remap and <lang_param_lc> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- still assuming that <lang_param_lc> is a tag; strip script, region, variant subtags name = cfg.lang_tag_remap[tag]; -- attempt to get remapped language name with language subtag only if name then -- when <name>, <tag> is a tag for a remapped language name return name, tag; -- so return <name> from remap and <tag> end if cfg.lang_name_remap[lang_param_lc] then -- not a remapped tag, assume <lang_param_lc> is a name; attempt to get remapped language tag return cfg.lang_name_remap[lang_param_lc][1], cfg.lang_name_remap[lang_param_lc][2]; -- for this <lang_param_lc>, return a (possibly) new name and appropriate tag end name = cfg.mw_languages_by_tag_t[lang_param_lc]; -- assume that <lang_param_lc> is a tag; attempt to get its matching language name if name then return name, lang_param_lc; -- <lang_param_lc> is a tag so return it and <name> end tag = cfg.mw_languages_by_name_t[lang_param_lc]; -- assume that <lang_param_lc> is a language name; attempt to get its matching tag if tag then return cfg.mw_languages_by_tag_t[tag], tag; -- <lang_param_lc> is a name so return the name from the table and <tag> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- is <lang_param_lc> an IETF-like tag that MediaWiki doesn't recognize? <tag> gets the language subtag; nil else if tag then name = cfg.mw_languages_by_tag_t[tag]; -- attempt to get a language name using the shortened <tag> if name then return name, tag; -- <lang_param_lc> is an unrecognized IETF-like tag so return <name> and language subtag end end end --[[-------------------< L A N G U A G E _ P A R A M E T E R >------------------ Gets language name from a provided two- or three-character ISO 639 code. If a code is recognized by MediaWiki, use the returned name; if not, then use the value that was provided with the language parameter. When |language= contains a recognized language (either code or name), the page is assigned to the category for that code: Category:Norwegian-language sources (no). For valid three-character code languages, the page is assigned to the single category for '639-2' codes: Category:CS1 ISO 639-2 language sources. Languages that are the same as the local wiki are not categorized. MediaWiki does not recognize three-character equivalents of two-character codes: code 'ar' is recognized but code 'ara' is not. This function supports multiple languages in the form |language=nb, French, th where the language names or codes are separated from each other by commas with optional space characters. ]] local function language_parameter (lang) local tag; -- some form of IETF-like language tag; language subtag with optional region, sript, vatiant, etc subtags local lang_subtag; -- ve populates |language= with mostly unecessary region subtags the MediaWiki does not recognize; this is the base language subtag local name; -- the language name local language_list = {}; -- table of language names to be rendered local names_t = {}; -- table made from the value assigned to |language= local this_wiki_name = mw.language.fetchLanguageName (cfg.this_wiki_code, cfg.this_wiki_code); -- get this wiki's language name names_t = mw.text.split (lang, '%s*,%s*'); -- names should be a comma separated list for _, lang in ipairs (names_t) do -- reuse lang here because we don't yet know if lang is a language name or a language tag name, tag = name_tag_get (lang); -- attempt to get name/tag pair for <lang>; <name> has proper capitalization; <tag> is lowercase if utilities.is_set (tag) then lang_subtag = tag:gsub ('^(%a%a%a?)%-.*', '%1'); -- for categorization, strip any IETF-like tags from language tag if cfg.this_wiki_code ~= lang_subtag then -- when the language is not the same as this wiki's language if 2 == lang_subtag:len() then -- and is a two-character tag utilities.add_prop_cat ('foreign-lang-source', {name, tag}, lang_subtag); -- categorize it; tag appended to allow for multiple language categorization else -- or is a recognized language (but has a three-character tag) utilities.add_prop_cat ('foreign-lang-source-2', {lang_subtag}, lang_subtag); -- categorize it differently TODO: support multiple three-character tag categories per cs1|2 template? end elseif cfg.local_lang_cat_enable then -- when the language and this wiki's language are the same and categorization is enabled utilities.add_prop_cat ('local-lang-source', {name, lang_subtag}); -- categorize it end else name = lang; -- return whatever <lang> has so that we show something utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added end table.insert (language_list, name); name = ''; -- so we can reuse it end name = utilities.make_sep_list (#language_list, language_list); if (1 == #language_list) and (lang_subtag == cfg.this_wiki_code) then -- when only one language, find lang name in this wiki lang name; for |language=en-us, 'English' in 'American English' return ''; -- if one language and that language is this wiki's return an empty string (no annotation) end return (" " .. wrap_msg ('language', name)); -- otherwise wrap with '(in ...)' --[[ TODO: should only return blank or name rather than full list so we can clean up the bunched parenthetical elements Language, Type, Format ]] end --[[-----------------------< S E T _ C S _ S T Y L E >-------------------------- Gets the default CS style configuration for the given mode. Returns default separator and either postscript as passed in or the default. In CS1, the default postscript and separator are '.'. In CS2, the default postscript is the empty string and the default separator is ','. ]] local function set_cs_style (postscript, mode) if utilities.is_set(postscript) then -- emit a maintenance message if user postscript is the default cs1 postscript -- we catch the opposite case for cs2 in set_style if mode == 'cs1' and postscript == cfg.presentation['ps_' .. mode] then utilities.set_message ('maint_postscript'); end else postscript = cfg.presentation['ps_' .. mode]; end return cfg.presentation['sep_' .. mode], postscript; end --[[--------------------------< S E T _ S T Y L E >----------------------------- Sets the separator and postscript styles. Checks the |mode= first and the #invoke CitationClass second. Removes the postscript if postscript == none. ]] local function set_style (mode, postscript, cite_class) local sep; if 'cs2' == mode then sep, postscript = set_cs_style (postscript, 'cs2'); elseif 'cs1' == mode then sep, postscript = set_cs_style (postscript, 'cs1'); elseif 'citation' == cite_class then sep, postscript = set_cs_style (postscript, 'cs2'); else sep, postscript = set_cs_style (postscript, 'cs1'); end if cfg.keywords_xlate[postscript:lower()] == 'none' then -- emit a maintenance message if user postscript is the default cs2 postscript -- we catch the opposite case for cs1 in set_cs_style if 'cs2' == mode or ('cs1' ~= mode and 'citation' == cite_class) then -- {{citation |title=Title |mode=cs1 |postscript=none}} should not emit maint message utilities.set_message ('maint_postscript'); end postscript = ''; end return sep, postscript end --[=[-------------------------< I S _ P D F >----------------------------------- Determines if a URL has the file extension that is one of the PDF file extensions used by [[MediaWiki:Common.css]] when applying the PDF icon to external links. returns true if file extension is one of the recognized extensions, else false ]=] local function is_pdf (url) return url:match ('%.pdf$') or url:match ('%.PDF$') or url:match ('%.pdf[%?#]') or url:match ('%.PDF[%?#]') or url:match ('%.PDF&#035') or url:match ('%.pdf&#035'); end --[[--------------------------< S T Y L E _ F O R M A T >----------------------- Applies CSS style to |format=, |chapter-format=, etc. Also emits an error message if the format parameter does not have a matching URL parameter. If the format parameter is not set and the URL contains a file extension that is recognized as a PDF document by MediaWiki's commons.css, this code will set the format parameter to (PDF) with the appropriate styling. ]] local function style_format (format, url, fmt_param, url_param) if utilities.is_set (format) then format = utilities.wrap_style ('format', format); -- add leading space, parentheses, resize if not utilities.is_set (url) then utilities.set_message ('err_format_missing_url', {fmt_param, url_param}); -- add an error message end elseif is_pdf (url) then -- format is not set so if URL is a PDF file then format = utilities.wrap_style ('format', 'PDF'); -- set format to PDF else format = ''; -- empty string for concatenation end return format; end --[[---------------------< G E T _ D I S P L A Y _ N A M E S >------------------ Returns a number that defines the number of names displayed for author and editor name lists and a Boolean flag to indicate when et al. should be appended to the name list. When the value assigned to |display-xxxxors= is a number greater than or equal to zero, return the number and the previous state of the 'etal' flag (false by default but may have been set to true if the name list contains some variant of the text 'et al.'). When the value assigned to |display-xxxxors= is the keyword 'etal', return a number that is one greater than the number of authors in the list and set the 'etal' flag true. This will cause the list_people() to display all of the names in the name list followed by 'et al.' In all other cases, returns nil and the previous state of the 'etal' flag. inputs: max: A['DisplayAuthors'] or A['DisplayEditors'], etc; a number or some flavor of etal count: #a or #e list_name: 'authors' or 'editors' etal: author_etal or editor_etal This function sets an error message when |display-xxxxors= value greater than or equal to number of names but not when <max> comes from {{cs1 config}} global settings. When using global settings, <param> is set to the keyword 'cs1 config' which is used to supress the normal error. Error is suppressed because it is to be expected that some citations in an article will have the same or fewer names that the limit specified in {{cs1 config}}. ]] local function get_display_names (max, count, list_name, etal, param) if utilities.is_set (max) then if 'etal' == max:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings max = count + 1; -- number of authors + 1 so display all author name plus et al. etal = true; -- overrides value set by extract_names() elseif max:match ('^%d+$') then -- if is a string of numbers max = tonumber (max); -- make it a number if (max >= count) and ('cs1 config' ~= param) then -- error when local |display-xxxxors= value greater than or equal to number of names; not an error when using global setting utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; end else -- not a valid keyword or number utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; -- unset; as if |display-xxxxors= had not been set end end return max, etal; end --[[----------< E X T R A _ T E X T _ I N _ P A G E _ C H E C K >--------------- Adds error if |page=, |pages=, |quote-page=, |quote-pages= has what appears to be some form of p. or pp. abbreviation in the first characters of the parameter content. check page for extraneous p, p., pp, pp., pg, pg. at start of parameter value: good pattern: '^P[^%.P%l]' matches when page begins PX or P# but not Px where x and X are letters and # is a digit bad pattern: '^[Pp][PpGg]' matches when page begins pp, pP, Pp, PP, pg, pG, Pg, PG ]] local function extra_text_in_page_check (val, name) if not val:match (cfg.vol_iss_pg_patterns.good_ppattern) then for _, pattern in ipairs (cfg.vol_iss_pg_patterns.bad_ppatterns) do -- spin through the selected sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message ('err_extra_text_pages', name); -- add error message return; -- and done end end end end --[[--------------------------< E X T R A _ T E X T _ I N _ V O L _ I S S _ C H E C K >------------------------ Adds error if |volume= or |issue= has what appears to be some form of redundant 'type' indicator. Applies to both; this function looks for issue text in both |issue= and |volume= and looks for volume-like text in |voluem= and |issue=. For |volume=: 'V.', or 'Vol.' (with or without the dot) abbreviations or 'Volume' in the first characters of the parameter content (all case insensitive). 'V' and 'v' (without the dot) are presumed to be roman numerals so are allowed. For |issue=: 'No.', 'I.', 'Iss.' (with or without the dot) abbreviations, or 'Issue' in the first characters of the parameter content (all case insensitive); numero styling: 'n°' with degree sign U+00B0, and № precomposed numero sign U+2116. Single character values ('v', 'i', 'n') allowed when not followed by separator character ('.', ':', '=', or whitespace character) – param values are trimmed of whitespace by MediaWiki before delivered to the module. <val> is |volume= or |issue= parameter value <name> is |volume= or |issue= parameter name for error message <selector> is 'v' for |volume=, 'i' for |issue= sets error message on failure; returns nothing ]] local function extra_text_in_vol_iss_check (val, name, selector) if not utilities.is_set (val) then return; end local handler = 'v' == selector and 'err_extra_text_volume' or 'err_extra_text_issue'; val = val:lower(); -- force parameter value to lower case for _, pattern in ipairs (cfg.vol_iss_pg_patterns.vi_patterns_t) do -- spin through the sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message (handler, name); -- add error message return; -- and done end end end --[=[-------------------------< G E T _ V _ N A M E _ T A B L E >---------------------------------------------- split apart a |vauthors= or |veditors= parameter. This function allows for corporate names, wrapped in doubled parentheses to also have commas; in the old version of the code, the doubled parentheses were included in the rendered citation and in the metadata. Individual author names may be wikilinked |vauthors=Jones AB, [[E. B. White|White EB]], ((Black, Brown, and Co.)) ]=] local function get_v_name_table (vparam, output_table, output_link_table) local _, accept = utilities.has_accept_as_written (vparam); if accept then utilities.add_prop_cat ('vanc-accept'); -- add properties category end local name_table = mw.text.split(vparam, "%s*,%s*"); -- names are separated by commas local wl_type, label, link; -- wl_type not used here; just a placeholder local i = 1; while name_table[i] do if name_table[i]:match ('^%(%(.*[^%)][^%)]$') then -- first segment of corporate with one or more commas; this segment has the opening doubled parentheses local name = name_table[i]; i = i + 1; -- bump indexer to next segment while name_table[i] do name = name .. ', ' .. name_table[i]; -- concatenate with previous segments if name_table[i]:match ('^.*%)%)$') then -- if this table member has the closing doubled parentheses break; -- and done reassembling so end i = i + 1; -- bump indexer end table.insert (output_table, name); -- and add corporate name to the output table table.insert (output_link_table, ''); -- no wikilink else wl_type, label, link = utilities.is_wikilink (name_table[i]); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] table.insert (output_table, label); -- add this name if 1 == wl_type then table.insert (output_link_table, label); -- simple wikilink [[D]] else table.insert (output_link_table, link); -- no wikilink or [[L|D]]; add this link if there is one, else empty string end end i = i + 1; end return output_table; end --[[--------------------------< P A R S E _ V A U T H O R S _ V E D I T O R S >-------------------------------- This function extracts author / editor names from |vauthors= or |veditors= and finds matching |xxxxor-maskn= and |xxxxor-linkn= in args. It then returns a table of assembled names just as extract_names() does. Author / editor names in |vauthors= or |veditors= must be in Vancouver system style. Corporate or institutional names may sometimes be required and because such names will often fail the is_good_vanc_name() and other format compliance tests, are wrapped in doubled parentheses ((corporate name)) to suppress the format tests. Supports generational suffixes Jr, 2nd, 3rd, 4th–6th. This function sets the Vancouver error when a required comma is missing and when there is a space between an author's initials. ]] local function parse_vauthors_veditors (args, vparam, list_name) local names = {}; -- table of names assembled from |vauthors=, |author-maskn=, |author-linkn= local v_name_table = {}; local v_link_table = {}; -- when name is wikilinked, targets go in this table local etal = false; -- return value set to true when we find some form of et al. vauthors parameter local last, first, link, mask, suffix; local corporate = false; vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period) v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); -- names are separated by commas for i, v_name in ipairs(v_name_table) do first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor local accept_name; v_name, accept_name = utilities.has_accept_as_written (v_name); -- remove accept-this-as-written markup when it wraps all of <v_name> if accept_name then last = v_name; corporate = true; -- flag used in list_people() elseif string.find(v_name, "%s") then if v_name:find('[;%.]') then -- look for commonly occurring punctuation characters; add_vanc_error (cfg.err_msg_supl.punctuation, i); end local lastfirstTable = {} lastfirstTable = mw.text.split(v_name, "%s+") first = table.remove(lastfirstTable); -- removes and returns value of last element in table which should be initials or generational suffix if not mw.ustring.match (first, '^%u+$') then -- mw.ustring here so that later we will catch non-Latin characters suffix = first; -- not initials so assume that whatever we got is a generational suffix first = table.remove(lastfirstTable); -- get what should be the initials from the table end last = table.concat(lastfirstTable, ' ') -- returns a string that is the concatenation of all other names that are not initials and generational suffix if not utilities.is_set (last) then first = ''; -- unset last = v_name; -- last empty because something wrong with first add_vanc_error (cfg.err_msg_supl.name, i); end if mw.ustring.match (last, '%a+%s+%u+%s+%a+') then add_vanc_error (cfg.err_msg_supl['missing comma'], i); -- matches last II last; the case when a comma is missing end if mw.ustring.match (v_name, ' %u %u$') then -- this test is in the wrong place TODO: move or replace with a more appropriate test add_vanc_error (cfg.err_msg_supl.initials, i); -- matches a space between two initials end else last = v_name; -- last name or single corporate name? Doesn't support multiword corporate names? do we need this? end if utilities.is_set (first) then if not mw.ustring.match (first, "^%u?%u$") then -- first shall contain one or two upper-case letters, nothing else add_vanc_error (cfg.err_msg_supl.initials, i); -- too many initials; mixed case initials (which may be ok Romanization); hyphenated initials end is_good_vanc_name (last, first, suffix, i); -- check first and last before restoring the suffix which may have a non-Latin digit if utilities.is_set (suffix) then first = first .. ' ' .. suffix; -- if there was a suffix concatenate with the initials suffix = ''; -- unset so we don't add this suffix to all subsequent names end else if not corporate then is_good_vanc_name (last, '', nil, i); end end link = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ) or v_link_table[i]; mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); names[i] = {last = last, first = first, link = link, mask = mask, corporate = corporate}; -- add this assembled name to our names list end return names, etal; -- all done, return our list of names end --[[--------------------------< S E L E C T _ A U T H O R _ E D I T O R _ S O U R C E >------------------------ Select one of |authors=, |authorn= / |lastn / firstn=, or |vauthors= as the source of the author name list or select one of |editorn= / editor-lastn= / |editor-firstn= or |veditors= as the source of the editor name list. Only one of these appropriate three will be used. The hierarchy is: |authorn= (and aliases) highest and |authors= lowest; |editorn= (and aliases) highest and |veditors= lowest (support for |editors= withdrawn) When looking for |authorn= / |editorn= parameters, test |xxxxor1= and |xxxxor2= (and all of their aliases); stops after the second test which mimicks the test used in extract_names() when looking for a hole in the author name list. There may be a better way to do this, I just haven't discovered what that way is. Emits an error message when more than one xxxxor name source is provided. In this function, vxxxxors = vauthors or veditors; xxxxors = authors as appropriate. ]] local function select_author_editor_source (vxxxxors, xxxxors, args, list_name) local lastfirst = false; if utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 1 ) or -- do this twice in case we have a |first1= without a |last1=; this ... utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 1 ) or -- ... also catches the case where |first= is used with |vauthors= utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 2 ) or utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 2 ) then lastfirst = true; end if (utilities.is_set (vxxxxors) and true == lastfirst) or -- these are the three error conditions (utilities.is_set (vxxxxors) and utilities.is_set (xxxxors)) or (true == lastfirst and utilities.is_set (xxxxors)) then local err_name; if 'AuthorList' == list_name then -- figure out which name should be used in error message err_name = 'author'; else err_name = 'editor'; end utilities.set_message ('err_redundant_parameters', err_name .. '-name-list parameters'); -- add error message end if true == lastfirst then return 1 end; -- return a number indicating which author name source to use if utilities.is_set (vxxxxors) then return 2 end; if utilities.is_set (xxxxors) then return 3 end; return 1; -- no authors so return 1; this allows missing author name test to run in case there is a first without last end --[[--------------------------< I S _ V A L I D _ P A R A M E T E R _ V A L U E >------------------------------ This function is used to validate a parameter's assigned value for those parameters that have only a limited number of allowable values (yes, y, true, live, dead, etc.). When the parameter value has not been assigned a value (missing or empty in the source template) the function returns the value specified by ret_val. If the parameter value is one of the list of allowed values returns the translated value; else, emits an error message and returns the value specified by ret_val. TODO: explain <invert> ]] local function is_valid_parameter_value (value, name, possible, ret_val, invert) if not utilities.is_set (value) then return ret_val; -- an empty parameter is ok end if (not invert and utilities.in_array (value, possible)) then -- normal; <value> is in <possible> table return cfg.keywords_xlate[value]; -- return translation of parameter keyword elseif invert and not utilities.in_array (value, possible) then -- invert; <value> is not in <possible> table return value; -- return <value> as it is else utilities.set_message ('err_invalid_param_val', {name, value}); -- not an allowed value so add error message return ret_val; end end --[[--------------------------< T E R M I N A T E _ N A M E _ L I S T >---------------------------------------- This function terminates a name list (author, contributor, editor) with a separator character (sepc) and a space when the last character is not a sepc character or when the last three characters are not sepc followed by two closing square brackets (close of a wikilink). When either of these is true, the name_list is terminated with a single space character. ]] local function terminate_name_list (name_list, sepc) if (string.sub (name_list, -3, -1) == sepc .. '. ') then -- if already properly terminated return name_list; -- just return the name list elseif (string.sub (name_list, -1, -1) == sepc) or (string.sub (name_list, -3, -1) == sepc .. ']]') then -- if last name in list ends with sepc char return name_list .. " "; -- don't add another else return name_list .. sepc .. ' '; -- otherwise terminate the name list end end --[[-------------------------< F O R M A T _ V O L U M E _ I S S U E >----------------------------------------- returns the concatenation of the formatted volume and issue (or journal article number) parameters as a single string; or formatted volume or formatted issue, or an empty string if neither are set. ]] local function format_volume_issue (volume, issue, article, cite_class, origin, sepc, lower) if not utilities.is_set (volume) and not utilities.is_set (issue) and not utilities.is_set (article) then return ''; end -- same condition as in format_pages_sheets() local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); local is_numeric_vol = volume and (volume:match ('^[MDCLXVI]+$') or volume:match ('^%d+$')); -- is only uppercase roman numerals or only digits? local is_long_vol = volume and (4 < mw.ustring.len(volume)); -- is |volume= value longer than 4 characters? if volume and (not is_numeric_vol and is_long_vol) then -- when not all digits or Roman numerals, is |volume= longer than 4 characters? utilities.add_prop_cat ('long-vol'); -- yes, add properties cat end if is_journal then -- journal-style formatting local vol = ''; if utilities.is_set (volume) then if is_numeric_vol then -- |volume= value all digits or all uppercase Roman numerals? vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, volume}); -- render in bold face elseif is_long_vol then -- not all digits or Roman numerals; longer than 4 characters? vol = utilities.substitute (cfg.messages['j-vol'], {sepc, utilities.hyphen_to_dash (volume)}); -- not bold else -- four or fewer characters vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, utilities.hyphen_to_dash (volume)}); -- bold end end vol = vol .. (utilities.is_set (issue) and utilities.substitute (cfg.messages['j-issue'], issue) or '') vol = vol .. (utilities.is_set (article) and utilities.substitute (cfg.messages['j-article-num'], article) or '') return vol; end if 'podcast' == cite_class and utilities.is_set (issue) then return wrap_msg ('issue', {sepc, issue}, lower); end if 'conference' == cite_class and utilities.is_set (article) then -- |article-number= supported only in journal and conference cites if utilities.is_set (volume) and utilities.is_set (article) then -- both volume and article number return wrap_msg ('vol-art', {sepc, utilities.hyphen_to_dash (volume), article}, lower); elseif utilities.is_set (article) then -- article number alone; when volume alone, handled below return wrap_msg ('art', {sepc, article}, lower); end end -- all other types of citation if utilities.is_set (volume) and utilities.is_set (issue) then return wrap_msg ('vol-no', {sepc, utilities.hyphen_to_dash (volume), issue}, lower); elseif utilities.is_set (volume) then return wrap_msg ('vol', {sepc, utilities.hyphen_to_dash (volume)}, lower); else return wrap_msg ('issue', {sepc, issue}, lower); end end --[[-------------------------< F O R M A T _ P A G E S _ S H E E T S >----------------------------------------- adds static text to one of |page(s)= or |sheet(s)= values and returns it with all of the others set to empty strings. The return order is: page, pages, sheet, sheets Singular has priority over plural when both are provided. ]] local function format_pages_sheets (page, pages, sheet, sheets, cite_class, origin, sepc, nopp, lower) if 'map' == cite_class then -- only cite map supports sheet(s) as in-source locators if utilities.is_set (sheet) then if 'journal' == origin then return '', '', wrap_msg ('j-sheet', sheet, lower), ''; else return '', '', wrap_msg ('sheet', {sepc, sheet}, lower), ''; end elseif utilities.is_set (sheets) then if 'journal' == origin then return '', '', '', wrap_msg ('j-sheets', sheets, lower); else return '', '', '', wrap_msg ('sheets', {sepc, sheets}, lower); end end end local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); if utilities.is_set (page) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], page), '', '', ''; elseif not nopp then return utilities.substitute (cfg.messages['p-prefix'], {sepc, page}), '', '', ''; else return utilities.substitute (cfg.messages['nopp'], {sepc, page}), '', '', ''; end elseif utilities.is_set (pages) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], pages), '', '', ''; elseif tonumber(pages) ~= nil and not nopp then -- if pages is only digits, assume a single page number return '', utilities.substitute (cfg.messages['p-prefix'], {sepc, pages}), '', ''; elseif not nopp then return '', utilities.substitute (cfg.messages['pp-prefix'], {sepc, pages}), '', ''; else return '', utilities.substitute (cfg.messages['nopp'], {sepc, pages}), '', ''; end end return '', '', '', ''; -- return empty strings end --[[--------------------------< I N S O U R C E _ L O C _ G E T >---------------------------------------------- returns one of the in-source locators: page, pages, or at. If any of these are interwiki links to Wikisource, returns the label portion of the interwiki-link as plain text for use in COinS. This COinS thing is done because here we convert an interwiki-link to an external link and add an icon span around that; get_coins_pages() doesn't know about the span. TODO: should it? TODO: add support for sheet and sheets?; streamline; TODO: make it so that this function returns only one of the three as the single in-source (the return value assigned to a new name)? ]] local function insource_loc_get (page, page_orig, pages, pages_orig, at) local ws_url, ws_label, coins_pages, L; -- for Wikisource interwiki-links; TODO: this corrupts page metadata (span remains in place after cleanup; fix there?) if utilities.is_set (page) then if utilities.is_set (pages) or utilities.is_set (at) then pages = ''; -- unset the others at = ''; end extra_text_in_page_check (page, page_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (page); -- make ws URL from |page= interwiki link; link portion L becomes tooltip label if ws_url then page = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in page'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? page = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, page}); coins_pages = ws_label; end elseif utilities.is_set (pages) then if utilities.is_set (at) then at = ''; -- unset end extra_text_in_page_check (pages, pages_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (pages); -- make ws URL from |pages= interwiki link; link portion L becomes tooltip label if ws_url then pages = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in pages'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? pages = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, pages}); coins_pages = ws_label; end elseif utilities.is_set (at) then ws_url, ws_label, L = wikisource_url_make (at); -- make ws URL from |at= interwiki link; link portion L becomes tooltip label if ws_url then at = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in at'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? at = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, at}); coins_pages = ws_label; end end return page, pages, at, coins_pages; end --[[--------------------------< I S _ U N I Q U E _ A R C H I V E _ U R L >------------------------------------ add error message when |archive-url= value is same as |url= or chapter-url= (or alias...) value ]] local function is_unique_archive_url (archive, url, c_url, source, date) if utilities.is_set (archive) then if archive == url or archive == c_url then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); -- add error message return '', ''; -- unset |archive-url= and |archive-date= because same as |url= or |chapter-url= end end return archive, date; end --[=[-------------------------< A R C H I V E _ U R L _ C H E C K >-------------------------------------------- Check archive.org URLs to make sure they at least look like they are pointing at valid archives and not to the save snapshot URL or to calendar pages. When the archive URL is 'https://web.archive.org/save/' (or http://...) archive.org saves a snapshot of the target page in the URL. That is something that Wikipedia should not allow unwitting readers to do. When the archive.org URL does not have a complete timestamp, archive.org chooses a snapshot according to its own algorithm or provides a calendar 'search' result. [[WP:ELNO]] discourages links to search results. This function looks at the value assigned to |archive-url= and returns empty strings for |archive-url= and |archive-date= and an error message when: |archive-url= holds an archive.org save command URL |archive-url= is an archive.org URL that does not have a complete timestamp (YYYYMMDDhhmmss 14 digits) in the correct place otherwise returns |archive-url= and |archive-date= There are two mostly compatible archive.org URLs: //web.archive.org/<timestamp>... -- the old form //web.archive.org/web/<timestamp>... -- the new form The old form does not support or map to the new form when it contains a display flag. There are four identified flags ('id_', 'js_', 'cs_', 'im_') but since archive.org ignores others following the same form (two letters and an underscore) we don't check for these specific flags but we do check the form. This function supports a preview mode. When the article is rendered in preview mode, this function may return a modified archive URL: for save command errors, return undated wildcard (/*/) for timestamp errors when the timestamp has a wildcard, return the URL unmodified for timestamp errors when the timestamp does not have a wildcard, return with timestamp limited to six digits plus wildcard (/yyyymm*/) A secondary function is to return an archive-url timestamp from those urls that have them (archive.org and archive.today). The timestamp is used by validation.archive_date_check() to see if the value in |archive-date= matches the timestamp in the archive url. ]=] local function archive_url_check (url, date) local err_msg = ''; -- start with the error message empty local path, timestamp, flag; -- portions of the archive.org URL timestamp = url:match ('//archive.today/(%d%d%d%d%d%d%d%d%d%d%d%d%d%d)/') or -- get timestamp from archive.today urls url:match ('//archive.today/(%d%d%d%d%.%d%d%.%d%d%-%d%d%d%d%d%d)/'); -- this timestamp needs cleanup if timestamp then -- if this was an archive.today url ... return url, date, timestamp:gsub ('[%.%-]', ''); -- return ArchiveURL, ArchiveDate, and timestamp (dots and dashes removed) from |archive-url=, and done end -- here for archive.org urls if (not url:match('//web%.archive%.org/')) and (not url:match('//liveweb%.archive%.org/')) then -- also deprecated liveweb Wayback machine URL return url, date; -- not an archive.org archive, return ArchiveURL and ArchiveDate end if url:match('//web%.archive%.org/save/') then -- if a save command URL, we don't want to allow saving of the target page err_msg = cfg.err_msg_supl.save; url = url:gsub ('(//web%.archive%.org)/save/', '%1/*/', 1); -- for preview mode: modify ArchiveURL elseif url:match('//liveweb%.archive%.org/') then err_msg = cfg.err_msg_supl.liveweb; else path, timestamp, flag = url:match('//web%.archive%.org/([^%d]*)(%d+)([^/]*)/'); -- split out some of the URL parts for evaluation if not path then -- malformed in some way; pattern did not match err_msg = cfg.err_msg_supl.timestamp; elseif 14 ~= timestamp:len() then -- path and flag optional, must have 14-digit timestamp here err_msg = cfg.err_msg_supl.timestamp; if '*' ~= flag then local replacement = timestamp:match ('^%d%d%d%d%d%d') or timestamp:match ('^%d%d%d%d'); -- get the first 6 (YYYYMM) or first 4 digits (YYYY) if replacement then -- nil if there aren't at least 4 digits (year) replacement = replacement .. string.rep ('0', 14 - replacement:len()); -- year or yearmo (4 or 6 digits) zero-fill to make 14-digit timestamp url=url:gsub ('(//web%.archive%.org/[^%d]*)%d[^/]*', '%1' .. replacement .. '*', 1) -- for preview, modify ts to 14 digits plus splat for calendar display end end elseif utilities.is_set (path) and 'web/' ~= path then -- older archive URLs do not have the extra 'web/' path element err_msg = cfg.err_msg_supl.path; elseif utilities.is_set (flag) and not utilities.is_set (path) then -- flag not allowed with the old form URL (without the 'web/' path element) err_msg = cfg.err_msg_supl.flag; elseif utilities.is_set (flag) and not flag:match ('%a%a_') then -- flag if present must be two alpha characters and underscore (requires 'web/' path element) err_msg = cfg.err_msg_supl.flag; else return url, date, timestamp; -- return ArchiveURL, ArchiveDate, and timestamp from |archive-url= end end -- if here, something not right so utilities.set_message ('err_archive_url', {err_msg}); -- add error message and if is_preview_mode then return url, date, timestamp; -- preview mode so return ArchiveURL, ArchiveDate, and timestamp from |archive-url= else return '', ''; -- return empty strings for ArchiveURL and ArchiveDate end end --[[--------------------------< P L A C E _ C H E C K >-------------------------------------------------------- check |place=, |publication-place=, |location= to see if these params include digits. This function added because many editors misuse location to specify the in-source location (|page(s)= and |at= are supposed to do that) returns the original parameter value without modification; added maint cat when parameter value contains digits ]] local function place_check (param_val) if not utilities.is_set (param_val) then -- parameter empty or omitted return param_val; -- return that empty state end if mw.ustring.find (param_val, '%d') then -- not empty, are there digits in the parameter value utilities.set_message ('maint_location'); -- yep, add maint cat end return param_val; -- and done end --[[--------------------------< I S _ A R C H I V E D _ C O P Y >---------------------------------------------- compares |title= to 'Archived copy' (placeholder added by bots that can't find proper title); if matches, return true; nil else ]] local function is_archived_copy (title) title = mw.ustring.lower(title); -- switch title to lower case if title:find (cfg.special_case_translation.archived_copy.en) then -- if title is 'Archived copy' return true; elseif cfg.special_case_translation.archived_copy['local'] then if mw.ustring.find (title, cfg.special_case_translation.archived_copy['local']) then -- mw.ustring() because might not be Latin script return true; end end end --[[--------------------------< D I S P L A Y _ N A M E S _ S E L E C T >-------------------------------------- for any of the |display-authors=, |display-editors=, etc parameters, select either the local or global setting. When both are present, look at <local_display_names> value. When the value is some sort of 'et al.'string, special handling is required. When {{cs1 config}} has |display-<namelist>= AND this template has |display-<namelist>=etal AND: the number of names specified by <number_of_names> is: greater than the number specified in the global |display-<namelist>= parameter (<global_display_names>) use global |display-<namelist>= parameter value set overridden maint category less than or equal to the number specified in the global |display-<namelist>= parameter use local |display-<namelist>= parameter value The purpose of this function is to prevent categorizing a template that has fewer names than the global setting to keep the etal annotation specified by <local_display_names>. ]] local function display_names_select (global_display_names, local_display_names, param_name, number_of_names, test) if global_display_names and utilities.is_set (local_display_names) then -- when both if 'etal' == local_display_names:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings number_of_names = tonumber (number_of_names); -- convert these to numbers for comparison local global_display_names_num = tonumber (global_display_names); -- <global_display_names> not set when parameter value is not digits if number_of_names > global_display_names_num then -- template has more names than global config allows to be displayed? utilities.set_message ('maint_overridden_setting'); -- set a maint message because global is overriding local |display-<namelist>=etal return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local because fewer names so let <local_display_names> control end end -- here when <global_display_names> and <local_display_names> both numbers; <global_display_names> controls utilities.set_message ('maint_overridden_setting'); -- set a maint message return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) end -- here when only one of <global_display_names> or <local_display_names> set if global_display_names then return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local end end --[[--------------------------< M O D E _ S E T >-------------------------------------------------------------- fetch global mode setting from {{cs1 config}} (if present) or from |mode= (if present); global setting overrides local |mode= parameter value. When both are present, emit maintenance message ]] local function mode_set (Mode, Mode_origin) local mode; if cfg.global_cs1_config_t['Mode'] then -- global setting in {{cs1 config}}; nil when empty or assigned value invalid mode = is_valid_parameter_value (cfg.global_cs1_config_t['Mode'], 'cs1 config: mode', cfg.keywords_lists['mode'], ''); -- error messaging 'param' here is a hoax else mode = is_valid_parameter_value (Mode, Mode_origin, cfg.keywords_lists['mode'], ''); end if cfg.global_cs1_config_t['Mode'] and utilities.is_set (Mode) then -- when template has |mode=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end return mode; end --[[--------------------------< Q U O T E _ M A K E >---------------------------------------------------------- create quotation from |quote=, |trans-quote=, and/or script-quote= with or without |quote-page= or |quote-pages= when any of those three quote parameters are set, this function unsets <PostScript>. When none of those parameters are set, |quote-page= and |quote-pages= are unset to nil so that they are not included in the template's metadata ]] local function quote_make (quote, trans_quote, script_quote, quote_page, quote_pages, nopp, sepc, postscript) if utilities.is_set (quote) or utilities.is_set (trans_quote) or utilities.is_set (script_quote) then if utilities.is_set (quote) then if quote:sub(1, 1) == '"' and quote:sub(-1, -1) == '"' then -- if first and last characters of quote are quote marks quote = quote:sub(2, -2); -- strip them off end end quote = kern_quotes (quote); -- kern if needed quote = utilities.wrap_style ('quoted-text', quote ); -- wrap in <q>...</q> tags if utilities.is_set (script_quote) then quote = script_concatenate (quote, script_quote, 'script-quote'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after quote is wrapped end if utilities.is_set (trans_quote) then if trans_quote:sub(1, 1) == '"' and trans_quote:sub(-1, -1) == '"' then -- if first and last characters of |trans-quote are quote marks trans_quote = trans_quote:sub(2, -2); -- strip them off end quote = quote .. " " .. utilities.wrap_style ('trans-quoted-title', trans_quote ); end if utilities.is_set (quote_page) or utilities.is_set (quote_pages) then -- add page prefix local quote_prefix = ''; if utilities.is_set (quote_page) then extra_text_in_page_check (quote_page, 'quote-page'); -- add to maint cat if |quote-page= value begins with what looks like p., pp., etc. if not nopp then quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_page}), '', '', ''; else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_page}), '', '', ''; end elseif utilities.is_set (quote_pages) then extra_text_in_page_check (quote_pages, 'quote-pages'); -- add to maint cat if |quote-pages= value begins with what looks like p., pp., etc. if tonumber(quote_pages) ~= nil and not nopp then -- if only digits, assume single page quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_pages}), '', ''; elseif not nopp then quote_prefix = utilities.substitute (cfg.messages['pp-prefix'], {sepc, quote_pages}), '', ''; else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_pages}), '', ''; end end quote = quote_prefix .. ": " .. quote; else quote = sepc .. " " .. quote; end postscript = ""; -- cs1|2 does not supply terminal punctuation when |quote= is set elseif utilities.is_set (quote_page) or utilities.is_set (quote_pages) then quote_page = nil; -- unset; these require |quote=; TODO: error message? quote_pages = nil; end return quote, quote_page, quote_pages, postscript; end --[[--------------------------< C H E C K _ P U B L I S H E R _ N A M E >-------------------------------------- look for variations of '<text>: <text>' that might be '<location>: <publisher>' in |publisher= parameter value. when found, emit a maintenance message; return nil else <publisher> is the value assigned to |publisher= or |institution= ]] local function check_publisher_name (publisher) local patterns_t = { '^[%w%s]+%s*:%s*[%w%s]+$', -- plain text <location>: <publisher> '^%[+[%w%s:|]+%]+%s*:%s*[%w%s]+$', -- partially wikilinked [[<location>]]: <publisher> '^[%w%s]+%s*:%s*%[+[%w%s:|]+%]+$', -- partially wikilinked <location>: [[<publisher>]] '^%[+[%w%s:|]+%]+%s*:%s*%[+[%w%s:|]+%]+$', -- wikilinked [[<location>]]: [[<publisher>]] } for _, pattern in ipairs (patterns_t) do -- spin through the patterns_t sequence if mw.ustring.match (publisher, pattern) then -- does this pattern match? utilities.set_message ('maint_publisher_location'); -- set a maint message return; -- and done end end end --[[--------------------------< I S _ P A G E _ A R T _ N U M >------------------------------------------------ compare the trailing (rightmost) characters of the |doi= value against the whole value assigned to |page(s)=. return boolean true when: |page(s)= has exactly 8 digits and a dot between the fourth and fifth digits matches the trailing 9 characters of the |doi= value: |page=12345678 → |page=1234.5678 matches |doi=10.xxxx/yyyy1234.5678 |page(s)= is 5 or more characters and matches |doi= values's trailing characters |page(s)= begins with a lowercase 'e' and |page(s)= without the 'e' matches |doi= values's trailing characters: |page=e12345 → |page=12345 matches |doi=10.xxxx/yyyy12345 |page(s)= begins with a uppercase 'CD' followed by (typically) six digits matches |doi= values that ends with 'CDxxxxxx.pubx' (where 'x' is any single digit) return nil when |page(s)= values: are ranges separated by underscore, hyphen, emdash, endash, figure dash, or minus character are comma- or semicolon-separated lists of pages have external urls (has text 'http') are digit-only values less than 10000 do not match |doi= values's trailing characters ]] local function is_page_art_num (page, doi) if not (utilities.is_set (page) and utilities.is_set (doi)) then -- both required return; -- abandon; nothing to do end if page:match ('[,;_−–—‒%-]') then -- when |page(s)= might be a page range or a separated list of pages return; -- abandon end page = page:lower(); -- because doi names are case insensitive doi = doi:lower(); -- force these to lowercase for testing if page:match ('http') then -- when |page(s)= appears to hold a url return; -- abandon end if tonumber (page) then -- is |page(s)= digits only if 10000 > tonumber (page) then -- when |page(s)= less than 10000 return; -- abandon end if doi:match (page .. '$') then -- digits only page number match the last digits in |doi=? return true; end if 8 == page:len() then -- special case when |page(s)= is exactly 8 digits local dot_page = page:gsub ('(%d%d%d%d)(%d%d%d%d)', '%1.%2'); -- make a |page=xxxx.yyyy version commonly used in |doi= if doi:match (dot_page .. '$') then -- 8-digit dotted page number match the last characters in |doi=? return true; end end else -- here when |page(s)= is alpha-numeric if 4 < page:len() then -- when |page(s)= is five or more characters if doi:match (page .. '$') then -- alpha-numeric page match the last characters in |doi=? return true; end local epage = page:match ('^e([%w]+)$'); -- if first character of |page= is 'e', remove it if epage and doi:match (epage .. '$') then -- page number match the last characters in |doi=? return true; end local cdpage = page:match ('^cd%d+$'); -- if first characters of |page= are 'CD' and last characters are digits (typically 6 digits) if cdpage and doi:match (cdpage .. '%.pub%d$') then -- page number matches doi 'CDxxxxxx.pubx' where 'x' is a digit return true; end end end end --[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------ This is the main function doing the majority of the citation formatting. ]] local function citation0( config, args ) --[[ Load Input Parameters The argument_wrapper facilitates the mapping of multiple aliases to single internal variable. ]] local A = argument_wrapper ( args ); local i -- Pick out the relevant fields from the arguments. Different citation templates -- define different field names for the same underlying things. local author_etal; local a = {}; -- authors list from |lastn= / |firstn= pairs or |vauthors= local Authors; local NameListStyle; if cfg.global_cs1_config_t['NameListStyle'] then -- global setting in {{cs1 config}} overrides local |name-list-style= parameter value; nil when empty or assigned value invalid NameListStyle = is_valid_parameter_value (cfg.global_cs1_config_t['NameListStyle'], 'cs1 config: name-list-style', cfg.keywords_lists['name-list-style'], ''); -- error messaging 'param' here is a hoax else NameListStyle = is_valid_parameter_value (A['NameListStyle'], A:ORIGIN('NameListStyle'), cfg.keywords_lists['name-list-style'], ''); end if cfg.global_cs1_config_t['NameListStyle'] and utilities.is_set (A['NameListStyle']) then -- when template has |name-list-style=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end local Collaboration = A['Collaboration']; do -- to limit scope of selected local selected = select_author_editor_source (A['Vauthors'], A['Authors'], args, 'AuthorList'); if 1 == selected then a, author_etal = extract_names (args, 'AuthorList'); -- fetch author list from |authorn= / |lastn= / |firstn=, |author-linkn=, and |author-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be a, author_etal = parse_vauthors_veditors (args, A['Vauthors'], 'AuthorList'); -- fetch author list from |vauthors=, |author-linkn=, and |author-maskn= elseif 3 == selected then Authors = A['Authors']; -- use content of |people= or |credits=; |authors= is deprecated; TODO: constrain |people= and |credits= to cite av media, episode, serial? end if utilities.is_set (Collaboration) then author_etal = true; -- so that |display-authors=etal not required end end local editor_etal; local e = {}; -- editors list from |editor-lastn= / |editor-firstn= pairs or |veditors= do -- to limit scope of selected local selected = select_author_editor_source (A['Veditors'], nil, args, 'EditorList'); -- support for |editors= withdrawn if 1 == selected then e, editor_etal = extract_names (args, 'EditorList'); -- fetch editor list from |editorn= / |editor-lastn= / |editor-firstn=, |editor-linkn=, and |editor-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be e, editor_etal = parse_vauthors_veditors (args, args.veditors, 'EditorList'); -- fetch editor list from |veditors=, |editor-linkn=, and |editor-maskn= end end local Chapter = A['Chapter']; -- done here so that we have access to |contribution= from |chapter= aliases local Chapter_origin = A:ORIGIN ('Chapter'); local Contribution; -- because contribution is required for contributor(s) if 'contribution' == Chapter_origin then Contribution = Chapter; -- get the name of the contribution end local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (A['Periodical']) then -- |contributor= and |contribution= only supported in book cites c = extract_names (args, 'ContributorList'); -- fetch contributor list from |contributorn= / |contributor-lastn=, -firstn=, -linkn=, -maskn= if 0 < #c then if not utilities.is_set (Contribution) then -- |contributor= requires |contribution= utilities.set_message ('err_contributor_missing_required_param', 'contribution'); -- add missing contribution error message c = {}; -- blank the contributors' table; it is used as a flag later end if 0 == #a then -- |contributor= requires |author= utilities.set_message ('err_contributor_missing_required_param', 'author'); -- add missing author error message c = {}; -- blank the contributors' table; it is used as a flag later end end else -- if not a book cite if utilities.select_one (args, cfg.aliases['ContributorList-Last'], 'err_redundant_parameters', 1 ) then -- are there contributor name list parameters? utilities.set_message ('err_contributor_ignored'); -- add contributor ignored error message end Contribution = nil; -- unset end local Title = A['Title']; local TitleLink = A['TitleLink']; local auto_select = ''; -- default is auto local accept_link; TitleLink, accept_link = utilities.has_accept_as_written (TitleLink, true); -- test for accept-this-as-written markup if (not accept_link) and utilities.in_array (TitleLink, {'none', 'pmc', 'doi'}) then -- check for special keywords auto_select = TitleLink; -- remember selection for later TitleLink = ''; -- treat as if |title-link= would have been empty end TitleLink = link_title_ok (TitleLink, A:ORIGIN ('TitleLink'), Title, 'title'); -- check for wiki-markup in |title-link= or wiki-markup in |title= when |title-link= is set local Section = ''; -- {{cite map}} only; preset to empty string for concatenation if not used if 'map' == config.CitationClass and 'section' == Chapter_origin then Section = A['Chapter']; -- get |section= from |chapter= alias list; |chapter= and the other aliases not supported in {{cite map}} Chapter = ''; -- unset for now; will be reset later from |map= if present end local Periodical = A['Periodical']; local Periodical_origin = A:ORIGIN('Periodical'); local ScriptPeriodical = A['ScriptPeriodical']; local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical'); local TransPeriodical = A['TransPeriodical']; local TransPeriodical_origin = A:ORIGIN ('TransPeriodical'); if (utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical))) then local param; if utilities.is_set (Periodical) then -- get a parameter name from one of these periodical related meta-parameters Periodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = Periodical_origin -- get parameter name for error messaging elseif utilities.is_set (TransPeriodical) then TransPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = TransPeriodical_origin; -- get parameter name for error messaging elseif utilities.is_set (ScriptPeriodical) then ScriptPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = ScriptPeriodical_origin; -- get parameter name for error messaging end if utilities.is_set (param) then -- if we found one utilities.set_message ('err_periodical_ignored', {param}); -- emit an error message end end if utilities.is_set (Periodical) then local i; Periodical, i = utilities.strip_apostrophe_markup (Periodical); -- strip apostrophe markup so that metadata isn't contaminated if i then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {Periodical_origin}); end end if 'mailinglist' == config.CitationClass then -- special case for {{cite mailing list}} if utilities.is_set (Periodical) and utilities.is_set (A ['MailingList']) then -- both set emit an error TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', Periodical_origin) .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'mailinglist')}); end Periodical = A ['MailingList']; -- error or no, set Periodical to |mailinglist= value because this template is {{cite mailing list}} Periodical_origin = A:ORIGIN('MailingList'); end -- web and news not tested for now because of -- Wikipedia:Administrators%27_noticeboard#Is_there_a_semi-automated_tool_that_could_fix_these_annoying_"Cite_Web"_errors? if not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) then -- 'periodical' templates require periodical parameter -- local p = {['journal'] = 'journal', ['magazine'] = 'magazine', ['news'] = 'newspaper', ['web'] = 'website'}; -- for error message local p = {['journal'] = 'journal', ['magazine'] = 'magazine'}; -- for error message if p[config.CitationClass] then utilities.set_message ('err_missing_periodical', {config.CitationClass, p[config.CitationClass]}); end end local Volume; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) then if not utilities.in_array (Periodical_origin, cfg.citation_no_volume_t) then -- {{citation}} does not render |volume= when these parameters are used Volume = A['Volume']; -- but does for all other 'periodicals' end elseif utilities.is_set (ScriptPeriodical) then if 'script-website' ~= ScriptPeriodical_origin then -- {{citation}} does not render volume for |script-website= Volume = A['Volume']; -- but does for all other 'periodicals' end else Volume = A['Volume']; -- and does for non-'periodical' cites end elseif utilities.in_array (config.CitationClass, cfg.templates_using_volume) then -- render |volume= for cs1 according to the configuration settings Volume = A['Volume']; end extra_text_in_vol_iss_check (Volume, A:ORIGIN ('Volume'), 'v'); local Issue; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) and utilities.in_array (Periodical_origin, cfg.citation_issue_t) then -- {{citation}} may render |issue= when these parameters are used Issue = utilities.hyphen_to_dash (A['Issue']); end elseif utilities.in_array (config.CitationClass, cfg.templates_using_issue) then -- conference & map books do not support issue; {{citation}} listed here because included in settings table if not (utilities.in_array (config.CitationClass, {'conference', 'map', 'citation'}) and not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical))) then Issue = utilities.hyphen_to_dash (A['Issue']); end end local ArticleNumber; if utilities.in_array (config.CitationClass, {'journal', 'conference'}) or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then ArticleNumber = A['ArticleNumber']; end extra_text_in_vol_iss_check (Issue, A:ORIGIN ('Issue'), 'i'); local Page; local Pages; local At; local QuotePage; local QuotePages; if not utilities.in_array (config.CitationClass, cfg.templates_not_using_page) then -- TODO: rewrite to emit ignored parameter error message? Page = A['Page']; Pages = utilities.hyphen_to_dash (A['Pages']); At = A['At']; QuotePage = A['QuotePage']; QuotePages = utilities.hyphen_to_dash (A['QuotePages']); end local NoPP = is_valid_parameter_value (A['NoPP'], A:ORIGIN('NoPP'), cfg.keywords_lists['yes_true_y'], nil); local Mode = mode_set (A['Mode'], A:ORIGIN('Mode')); -- separator character and postscript local sepc, PostScript = set_style (Mode:lower(), A['PostScript'], config.CitationClass); local Quote; Quote, QuotePage, QuotePages, PostScript = quote_make (A['Quote'], A['TransQuote'], A['ScriptQuote'], QuotePage, QuotePages, NoPP, sepc, PostScript); local Edition = A['Edition']; local PublicationPlace = place_check (A['PublicationPlace'], A:ORIGIN('PublicationPlace')); local Place = place_check (A['Place'], A:ORIGIN('Place')); local PublisherName = A['PublisherName']; local PublisherName_origin = A:ORIGIN('PublisherName'); if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then local i = 0; PublisherName, i = utilities.strip_apostrophe_markup (PublisherName); -- strip apostrophe markup so that metadata isn't contaminated; publisher is never italicized if i and (0 < i) then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {PublisherName_origin}); end end if ('document' == config.CitationClass) and not utilities.is_set (PublisherName) then utilities.set_message ('err_missing_publisher', {config.CitationClass, 'publisher'}); end local Newsgroup = A['Newsgroup']; -- TODO: strip apostrophe markup? local Newsgroup_origin = A:ORIGIN('Newsgroup'); if 'newsgroup' == config.CitationClass then if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then -- general use parameter |publisher= not allowed in cite newsgroup utilities.set_message ('err_parameter_ignored', {PublisherName_origin}); end PublisherName = nil; -- ensure that this parameter is unset for the time being; will be used again after COinS end if 'book' == config.CitationClass or 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then local accept; PublisherName, accept = utilities.has_accept_as_written (PublisherName); -- check for and remove accept-as-written markup from |publisher= wrapped if not accept then -- when no accept-as-written markup check_publisher_name (PublisherName); -- emit maint message when |publisher= might be prefixed with publisher's location end end local URL = A['URL']; -- TODO: better way to do this for URL, ChapterURL, and MapURL? local UrlAccess = is_valid_parameter_value (A['UrlAccess'], A:ORIGIN('UrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (URL) and utilities.is_set (UrlAccess) then UrlAccess = nil; utilities.set_message ('err_param_access_requires_param', 'url'); end local ChapterURL = A['ChapterURL']; local ChapterUrlAccess = is_valid_parameter_value (A['ChapterUrlAccess'], A:ORIGIN('ChapterUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (ChapterURL) and utilities.is_set (ChapterUrlAccess) then ChapterUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {A:ORIGIN('ChapterUrlAccess'):gsub ('%-access', '')}); end local MapUrlAccess = is_valid_parameter_value (A['MapUrlAccess'], A:ORIGIN('MapUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (A['MapURL']) and utilities.is_set (MapUrlAccess) then MapUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {'map-url'}); end local this_page = mw.title.getCurrentTitle(); -- also used for COinS and for language local no_tracking_cats = is_valid_parameter_value (A['NoTracking'], A:ORIGIN('NoTracking'), cfg.keywords_lists['yes_true_y'], nil); -- check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories if not utilities.is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page if cfg.uncategorized_namespaces[this_page.namespace] then -- is this page's namespace id one of the uncategorized namespace ids? no_tracking_cats = "true"; -- set no_tracking_cats end for _, v in ipairs (cfg.uncategorized_subpages) do -- cycle through page name patterns if this_page.text:match (v) then -- test page name against each pattern no_tracking_cats = "true"; -- set no_tracking_cats break; -- bail out if one is found end end end -- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it) utilities.select_one (args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'err_redundant_parameters'); -- this is a dummy call simply to get the error message and category local coins_pages; Page, Pages, At, coins_pages = insource_loc_get (Page, A:ORIGIN('Page'), Pages, A:ORIGIN('Pages'), At); if utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- both |publication-place= and |place= (|location=) allowed if different utilities.add_prop_cat ('location-test'); -- add property cat to evaluate how often PublicationPlace and Place are used together if PublicationPlace == Place then Place = ''; -- unset; don't need both if they are the same end elseif not utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- when only |place= (|location=) is set ... PublicationPlace = Place; -- promote |place= (|location=) to |publication-place end if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same local URL_origin = A:ORIGIN('URL'); -- get name of parameter that holds URL local ChapterURL_origin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL local ScriptChapter = A['ScriptChapter']; local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); local Format = A['Format']; local ChapterFormat = A['ChapterFormat']; local TransChapter = A['TransChapter']; local TransChapter_origin = A:ORIGIN ('TransChapter'); local TransTitle = A['TransTitle']; local ScriptTitle = A['ScriptTitle']; --[[ Parameter remapping for cite encyclopedia: When the citation has these parameters: |encyclopedia= and |title= then map |title= to |article= and |encyclopedia= to |title= for rendering |encyclopedia= and |article= then map |encyclopedia= to |title= for rendering |trans-title= maps to |trans-chapter= when |title= is re-mapped |url= maps to |chapter-url= when |title= is remapped All other combinations of |encyclopedia=, |title=, and |article= are not modified ]] local Encyclopedia = A['Encyclopedia']; -- used as a flag by this module and by ~/COinS local ScriptEncyclopedia = A['ScriptEncyclopedia']; local TransEncyclopedia = A['TransEncyclopedia']; if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then -- emit error message when Encyclopedia set but template is other than {{cite encyclopedia}} or {{citation}} if 'encyclopaedia' ~= config.CitationClass and 'citation' ~= config.CitationClass then if utilities.is_set (Encyclopedia) then utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('Encyclopedia')}); else utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('ScriptEncyclopedia')}); end Encyclopedia = nil; -- unset these because not supported by this template ScriptEncyclopedia = nil; TransEncyclopedia = nil; end elseif utilities.is_set (TransEncyclopedia) then utilities.set_message ('err_trans_missing_title', {'encyclopedia'}); end if ('encyclopaedia' == config.CitationClass) or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Periodical) and utilities.is_set (Encyclopedia) then -- when both parameters set emit an error message; {{citation}} only; Periodical not allowed in {{cite encyclopedia}} utilities.set_message ('err_periodical_ignored', {Periodical_origin}); end if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then Periodical = Encyclopedia; -- error or no, set Periodical to Encyclopedia for rendering; {{citation}} could (not legitimately) have both; use Encyclopedia Periodical_origin = A:ORIGIN ('Encyclopedia'); ScriptPeriodical = ScriptEncyclopedia; ScriptPeriodical_origin = A:ORIGIN ('ScriptEncyclopedia'); if utilities.is_set (Title) or utilities.is_set (ScriptTitle) then if not utilities.is_set (Chapter) then Chapter = Title; -- |encyclopedia= and |title= are set so map |title= params to |article= params for rendering ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle') TransChapter = TransTitle; ChapterURL = URL; ChapterURL_origin = URL_origin; ChapterUrlAccess = UrlAccess; ChapterFormat = Format; if not utilities.is_set (ChapterURL) and utilities.is_set (TitleLink) then Chapter = utilities.make_wikilink (TitleLink, Chapter); end Title = Periodical; -- now map |encyclopedia= params to |title= params for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; URL = ''; Format = ''; TitleLink = ''; end elseif utilities.is_set (Chapter) or utilities.is_set (ScriptChapter) then -- |title= not set Title = Periodical; -- |encyclopedia= set and |article= set so map |encyclopedia= to |title= for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; end end end -- special case for cite techreport. local ID = A['ID']; if (config.CitationClass == "techreport") then -- special case for cite techreport if utilities.is_set (A['Number']) then -- cite techreport uses 'number', which other citations alias to 'issue' if not utilities.is_set (ID) then -- can we use ID for the "number"? ID = A['Number']; -- yes, use it else -- ID has a value so emit error message utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'id') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'number')}); end end end -- Account for the oddity that is {{cite conference}}, before generation of COinS data. local ChapterLink -- = A['ChapterLink']; -- deprecated as a parameter but still used internally by cite episode local Conference = A['Conference']; local BookTitle = A['BookTitle']; local TransTitle_origin = A:ORIGIN ('TransTitle'); if 'conference' == config.CitationClass then if utilities.is_set (BookTitle) then Chapter = Title; Chapter_origin = 'title'; -- ChapterLink = TitleLink; -- |chapter-link= is deprecated ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; URL_origin = ''; ChapterFormat = Format; TransChapter = TransTitle; TransChapter_origin = TransTitle_origin; Title = BookTitle; Format = ''; -- TitleLink = ''; TransTitle = ''; URL = ''; end elseif 'speech' ~= config.CitationClass then Conference = ''; -- not cite conference or cite speech so make sure this is empty string end local use_lowercase = ( sepc == ',' ); -- controls capitalization of certain static text -- cite map oddities local Cartography = ""; local Scale = ""; local Sheet = A['Sheet'] or ''; local Sheets = A['Sheets'] or ''; if config.CitationClass == "map" then if utilities.is_set (Chapter) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'map') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', Chapter_origin)}); -- add error message end Chapter = A['Map']; Chapter_origin = A:ORIGIN('Map'); ChapterURL = A['MapURL']; ChapterURL_origin = A:ORIGIN('MapURL'); TransChapter = A['TransMap']; ScriptChapter = A['ScriptMap'] ScriptChapter_origin = A:ORIGIN('ScriptMap') ChapterUrlAccess = MapUrlAccess; ChapterFormat = A['MapFormat']; Cartography = A['Cartography']; if utilities.is_set ( Cartography ) then Cartography = sepc .. " " .. wrap_msg ('cartography', Cartography, use_lowercase); end Scale = A['Scale']; if utilities.is_set ( Scale ) then Scale = sepc .. " " .. Scale; end end -- Account for the oddities that are {{cite episode}} and {{cite serial}}, before generation of COinS data. local Series = A['Series']; if 'episode' == config.CitationClass or 'serial' == config.CitationClass then local SeriesLink = A['SeriesLink']; SeriesLink = link_title_ok (SeriesLink, A:ORIGIN ('SeriesLink'), Series, 'series'); -- check for wiki-markup in |series-link= or wiki-markup in |series= when |series-link= is set local Network = A['Network']; local Station = A['Station']; local s, n = {}, {}; -- do common parameters first if utilities.is_set (Network) then table.insert(n, Network); end if utilities.is_set (Station) then table.insert(n, Station); end ID = table.concat(n, sepc .. ' '); if 'episode' == config.CitationClass then -- handle the oddities that are strictly {{cite episode}} local Season = A['Season']; local SeriesNumber = A['SeriesNumber']; if utilities.is_set (Season) and utilities.is_set (SeriesNumber) then -- these are mutually exclusive so if both are set TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'season') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'seriesno')}); -- add error message SeriesNumber = ''; -- unset; prefer |season= over |seriesno= end -- assemble a table of parts concatenated later into Series if utilities.is_set (Season) then table.insert(s, wrap_msg ('season', Season, use_lowercase)); end if utilities.is_set (SeriesNumber) then table.insert(s, wrap_msg ('seriesnum', SeriesNumber, use_lowercase)); end if utilities.is_set (Issue) then table.insert(s, wrap_msg ('episode', Issue, use_lowercase)); end Issue = ''; -- unset because this is not a unique parameter Chapter = Title; -- promote title parameters to chapter ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle'); ChapterLink = TitleLink; -- alias |episode-link= TransChapter = TransTitle; ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; ChapterFormat = Format; Title = Series; -- promote series to title TitleLink = SeriesLink; Series = table.concat(s, sepc .. ' '); -- this is concatenation of season, seriesno, episode number if utilities.is_set (ChapterLink) and not utilities.is_set (ChapterURL) then -- link but not URL Chapter = utilities.make_wikilink (ChapterLink, Chapter); elseif utilities.is_set (ChapterLink) and utilities.is_set (ChapterURL) then -- if both are set, URL links episode; Series = utilities.make_wikilink (ChapterLink, Series); end URL = ''; -- unset TransTitle = ''; ScriptTitle = ''; Format = ''; else -- now oddities that are cite serial Issue = ''; -- unset because this parameter no longer supported by the citation/core version of cite serial Chapter = A['Episode']; -- TODO: make |episode= available to cite episode someday? if utilities.is_set (Series) and utilities.is_set (SeriesLink) then Series = utilities.make_wikilink (SeriesLink, Series); end Series = utilities.wrap_style ('italic-title', Series); -- series is italicized end end -- end of {{cite episode}} stuff -- handle type parameter for those CS1 citations that have default values local TitleType = A['TitleType']; local Degree = A['Degree']; if utilities.in_array (config.CitationClass, {'AV-media-notes', 'document', 'interview', 'mailinglist', 'map', 'podcast', 'pressrelease', 'report', 'speech', 'techreport', 'thesis'}) then TitleType = set_titletype (config.CitationClass, TitleType); if utilities.is_set (Degree) and "Thesis" == TitleType then -- special case for cite thesis TitleType = Degree .. ' ' .. cfg.title_types ['thesis']:lower(); end end if utilities.is_set (TitleType) then -- if type parameter is specified TitleType = utilities.substitute ( cfg.messages['type'], TitleType); -- display it in parentheses -- TODO: Hack on TitleType to fix bunched parentheses problem end -- legacy: promote PublicationDate to Date if neither Date nor Year are set. local Date = A['Date']; local Date_origin; -- to hold the name of parameter promoted to Date; required for date error messaging local PublicationDate = A['PublicationDate']; local Year = A['Year']; if utilities.is_set (Year) then validation.year_check (Year); -- returns nothing; emits maint message when |year= doesn't hold a 'year' value end if not utilities.is_set (Date) then Date = Year; -- promote Year to Date Year = nil; -- make nil so Year as empty string isn't used for CITEREF if not utilities.is_set (Date) and utilities.is_set (PublicationDate) then -- use PublicationDate when |date= and |year= are not set Date = PublicationDate; -- promote PublicationDate to Date PublicationDate = ''; -- unset, no longer needed Date_origin = A:ORIGIN('PublicationDate'); -- save the name of the promoted parameter else Date_origin = A:ORIGIN('Year'); -- save the name of the promoted parameter end else Date_origin = A:ORIGIN('Date'); -- not a promotion; name required for error messaging end if PublicationDate == Date then PublicationDate = ''; end -- if PublicationDate is same as Date, don't display in rendered citation --[[ Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates. This must be done before we do COinS because here is where we get the date used in the metadata. Date validation supporting code is in Module:Citation/CS1/Date_validation ]] local DF = is_valid_parameter_value (A['DF'], A:ORIGIN('DF'), cfg.keywords_lists['df'], ''); if not utilities.is_set (DF) then DF = cfg.global_df; -- local |df= if present overrides global df set by {{use xxx date}} template end local ArchiveURL; local ArchiveDate; local ArchiveFormat = A['ArchiveFormat']; local archive_url_timestamp; -- timestamp from wayback machine url ArchiveURL, ArchiveDate, archive_url_timestamp = archive_url_check (A['ArchiveURL'], A['ArchiveDate']) ArchiveFormat = style_format (ArchiveFormat, ArchiveURL, 'archive-format', 'archive-url'); ArchiveURL, ArchiveDate = is_unique_archive_url (ArchiveURL, URL, ChapterURL, A:ORIGIN('ArchiveURL'), ArchiveDate); -- add error message when URL or ChapterURL == ArchiveURL local AccessDate = A['AccessDate']; local COinS_date = {}; -- holds date info extracted from |date= for the COinS metadata by Module:Date verification local DoiBroken = A['DoiBroken']; local Embargo = A['Embargo']; local anchor_year; -- used in the CITEREF identifier do -- create defined block to contain local variables error_message, date_parameters_list, mismatch local error_message = ''; -- AirDate has been promoted to Date so not necessary to check it local date_parameters_list = { ['access-date'] = {val = AccessDate, name = A:ORIGIN ('AccessDate')}, ['archive-date'] = {val = ArchiveDate, name = A:ORIGIN ('ArchiveDate')}, ['date'] = {val = Date, name = Date_origin}, ['doi-broken-date'] = {val = DoiBroken, name = A:ORIGIN ('DoiBroken')}, ['pmc-embargo-date'] = {val = Embargo, name = A:ORIGIN ('Embargo')}, ['publication-date'] = {val = PublicationDate, name = A:ORIGIN ('PublicationDate')}, ['year'] = {val = Year, name = A:ORIGIN ('Year')}, }; local error_list = {}; anchor_year, Embargo = validation.dates(date_parameters_list, COinS_date, error_list); if utilities.is_set (Year) and utilities.is_set (Date) then -- both |date= and |year= not normally needed; validation.year_date_check (Year, A:ORIGIN ('Year'), Date, A:ORIGIN ('Date'), error_list); end if 0 == #error_list then -- error free dates only; 0 when error_list is empty local modified = false; -- flag if utilities.is_set (DF) then -- if we need to reformat dates modified = validation.reformat_dates (date_parameters_list, DF); -- reformat to DF format, use long month names if appropriate end if true == validation.date_hyphen_to_dash (date_parameters_list) then -- convert hyphens to dashes where appropriate modified = true; utilities.set_message ('maint_date_format'); -- hyphens were converted so add maint category end -- for those wikis that can and want to have English date names translated to the local language; not supported at en.wiki if cfg.date_name_auto_xlate_enable and validation.date_name_xlate (date_parameters_list, cfg.date_digit_auto_xlate_enable ) then utilities.set_message ('maint_date_auto_xlated'); -- add maint cat modified = true; end if modified then -- if the date_parameters_list values were modified AccessDate = date_parameters_list['access-date'].val; -- overwrite date holding parameters with modified values ArchiveDate = date_parameters_list['archive-date'].val; Date = date_parameters_list['date'].val; DoiBroken = date_parameters_list['doi-broken-date'].val; PublicationDate = date_parameters_list['publication-date'].val; end if archive_url_timestamp and utilities.is_set (ArchiveDate) then validation.archive_date_check (ArchiveDate, archive_url_timestamp, DF); -- does YYYYMMDD in archive_url_timestamp match date in ArchiveDate end else utilities.set_message ('err_bad_date', {utilities.make_sep_list (#error_list, error_list)}); -- add this error message end end -- end of do if utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) or -- {{cite book}}, {{cite encyclopedia}}; TODO: {{cite conference}} and others? ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) or -- {{citation}} as an encylopedia citation ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then -- {{citation}} as a book citation if utilities.is_set (PublicationPlace) then if not utilities.is_set (PublisherName) then local date = COinS_date.rftdate and tonumber (COinS_date.rftdate:match ('%d%d%d%d')); -- get year portion of COinS date (because in Arabic numerals); convert string to number if date and (1850 <= date) then -- location has no publisher; if date is 1850 or later utilities.set_message ('maint_location_no_publisher'); -- add maint cat end else -- PublisherName has a value if cfg.keywords_xlate['none'] == PublisherName then -- if that value is 'none' (only for book and encyclopedia citations) PublisherName = ''; -- unset end end end end local ID_list = {}; -- sequence table of rendered identifiers local ID_list_coins = {}; -- table of identifiers and their values from args; key is same as cfg.id_handlers's key local Class = A['Class']; -- arxiv class identifier local ID_support = { {A['ASINTLD'], 'ASIN', 'err_asintld_missing_asin', A:ORIGIN ('ASINTLD')}, {DoiBroken, 'DOI', 'err_doibroken_missing_doi', A:ORIGIN ('DoiBroken')}, {Embargo, 'PMC', 'err_embargo_missing_pmc', A:ORIGIN ('Embargo')}, } ID_list, ID_list_coins = identifiers.identifier_lists_get (args, { DoiBroken = DoiBroken, -- for |doi= ASINTLD = A['ASINTLD'], -- for |asin= Embargo = Embargo, -- for |pmc= Class = Class, -- for |arxiv= CitationClass = config.CitationClass, -- for |arxiv= Year=anchor_year, -- for |isbn= }, ID_support); -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, {{cite ssrn}}, before generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv=, |citeseerx=, |medrxiv=, |ssrn= required for their templates if not (args[cfg.id_handlers[config.CitationClass:upper()].parameters[1]] or -- can't use ID_list_coins k/v table here because invalid parameters omitted args[cfg.id_handlers[config.CitationClass:upper()].parameters[2]]) then -- which causes unexpected parameter missing error message utilities.set_message ('err_' .. config.CitationClass .. '_missing'); -- add error message end Periodical = ({['arxiv'] = 'arXiv', ['biorxiv'] = 'bioRxiv', ['citeseerx'] = 'CiteSeerX', ['medrxiv'] = 'medRxiv', ['ssrn'] = 'Social Science Research Network'})[config.CitationClass]; end -- Link the title of the work if no |url= was provided, but we have a |pmc= or a |doi= with |doi-access=free if config.CitationClass == "journal" and not utilities.is_set (URL) and not utilities.is_set (TitleLink) and not utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) then -- TODO: remove 'none' once existing citations have been switched to 'off', so 'none' can be used as token for "no title" instead if 'none' ~= cfg.keywords_xlate[auto_select] then -- if auto-linking not disabled if identifiers.auto_link_urls[auto_select] then -- manual selection URL = identifiers.auto_link_urls[auto_select]; -- set URL to be the same as identifier's external link URL_origin = cfg.id_handlers[auto_select:upper()].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['pmc'] then -- auto-select PMC URL = identifiers.auto_link_urls['pmc']; -- set URL to be the same as the PMC external link if not embargoed URL_origin = cfg.id_handlers['PMC'].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['doi'] then -- auto-select DOI URL = identifiers.auto_link_urls['doi']; URL_origin = cfg.id_handlers['DOI'].parameters[1]; end end if utilities.is_set (URL) then -- set when using an identifier-created URL if utilities.is_set (AccessDate) then -- |access-date= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_accessdate_missing_url'); -- add an error message AccessDate = ''; -- unset end if utilities.is_set (ArchiveURL) then -- |archive-url= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_archive_missing_url'); -- add an error message ArchiveURL = ''; -- unset end end end -- At this point fields may be nil if they weren't specified in the template use. We can use that fact. -- Test if citation has no title if not utilities.is_set (Title) and not utilities.is_set (TransTitle) and not utilities.is_set (ScriptTitle) then -- has special case for cite episode utilities.set_message ('err_citation_missing_title', {'episode' == config.CitationClass and 'series' or 'title'}); end if utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) and utilities.in_array (config.CitationClass, {'journal', 'citation'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and ('journal' == Periodical_origin or 'script-journal' == ScriptPeriodical_origin) then -- special case for journal cites Title = ''; -- set title to empty string utilities.set_message ('maint_untitled'); -- add maint cat end if 'journal' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then if is_page_art_num ((utilities.is_set (Page) and Page) or (utilities.is_set (Pages) and Pages), ID_list_coins['DOI']) then -- does |page(s)= look like it holds an article number utilities.set_message ('maint_page_art_num'); -- add maint cat end end -- COinS metadata (see <http://ocoins.info/>) for automated parsing of citation information. -- handle the oddity that is cite encyclopedia and {{citation |encyclopedia=something}}. Here we presume that -- when Periodical, Title, and Chapter are all set, then Periodical is the book (encyclopedia) title, Title -- is the article title, and Chapter is a section within the article. So, we remap local coins_chapter = Chapter; -- default assuming that remapping not required local coins_title = Title; -- et tu if 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Chapter) and utilities.is_set (Title) and utilities.is_set (Periodical) then -- if all are used then coins_chapter = Title; -- remap coins_title = Periodical; end end local coins_author = a; -- default for coins rft.au if 0 < #c then -- but if contributor list coins_author = c; -- use that instead end -- this is the function call to COinS() local OCinSoutput = metadata.COinS({ ['Periodical'] = utilities.strip_apostrophe_markup (Periodical), -- no markup in the metadata ['Encyclopedia'] = Encyclopedia, -- just a flag; content ignored by ~/COinS ['Chapter'] = metadata.make_coins_title (coins_chapter, ScriptChapter), -- Chapter and ScriptChapter stripped of bold / italic / accept-as-written markup ['Degree'] = Degree; -- cite thesis only ['Title'] = metadata.make_coins_title (coins_title, ScriptTitle), -- Title and ScriptTitle stripped of bold / italic / accept-as-written markup ['PublicationPlace'] = PublicationPlace, ['Date'] = COinS_date.rftdate, -- COinS_date.* has correctly formatted date values if Date is valid; ['Season'] = COinS_date.rftssn, ['Quarter'] = COinS_date.rftquarter, ['Chron'] = COinS_date.rftchron, ['Series'] = Series, ['Volume'] = Volume, ['Issue'] = Issue, ['ArticleNumber'] = ArticleNumber, ['Pages'] = coins_pages or metadata.get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At, QuotePage, QuotePages}, 7)), -- pages stripped of external links ['Edition'] = Edition, ['PublisherName'] = PublisherName or Newsgroup, -- any apostrophe markup already removed from PublisherName ['URL'] = first_set ({ChapterURL, URL}, 2), ['Authors'] = coins_author, ['ID_list'] = ID_list_coins, ['RawPage'] = this_page.prefixedText, }, config.CitationClass); -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, and {{cite ssrn}} AFTER generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- we have set rft.jtitle in COinS to arXiv, bioRxiv, CiteSeerX, medRxiv, or ssrn now unset so it isn't displayed Periodical = ''; -- periodical not allowed in these templates; if article has been published, use cite journal end -- special case for cite newsgroup. Do this after COinS because we are modifying Publishername to include some static text if 'newsgroup' == config.CitationClass and utilities.is_set (Newsgroup) then PublisherName = utilities.substitute (cfg.messages['newsgroup'], external_link( 'news:' .. Newsgroup, Newsgroup, Newsgroup_origin, nil )); end local Editors; local EditorCount; -- used only for choosing {ed.) or (eds.) annotation at end of editor name-list local Contributors; -- assembled contributors name list local contributor_etal; local Translators; -- assembled translators name list local translator_etal; local t = {}; -- translators list from |translator-lastn= / translator-firstn= pairs t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= local Interviewers; local interviewers_list = {}; interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters local interviewer_etal; -- Now perform various field substitutions. -- We also add leading spaces and surrounding markup and punctuation to the -- various parts of the citation, but only when they are non-nil. do local last_first_list; local control = { format = NameListStyle, -- empty string, '&', 'amp', 'and', or 'vanc' maximum = nil, -- as if display-authors or display-editors not set mode = Mode }; do -- do editor name list first because the now unsupported coauthors used to modify control table local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayEditors'], A['DisplayEditors'], A:ORIGIN ('DisplayEditors'), #e); control.maximum, editor_etal = get_display_names (display_names, #e, 'editors', editor_etal, param); Editors, EditorCount = list_people (control, e, editor_etal); if 1 == EditorCount and (true == editor_etal or 1 < #e) then -- only one editor displayed but includes etal then EditorCount = 2; -- spoof to display (eds.) annotation end end do -- now do interviewers local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayInterviewers'], A['DisplayInterviewers'], A:ORIGIN ('DisplayInterviewers'), #interviewers_list); control.maximum, interviewer_etal = get_display_names (display_names, #interviewers_list, 'interviewers', interviewer_etal, param); Interviewers = list_people (control, interviewers_list, interviewer_etal); end do -- now do translators local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayTranslators'], A['DisplayTranslators'], A:ORIGIN ('DisplayTranslators'), #t); control.maximum, translator_etal = get_display_names (display_names, #t, 'translators', translator_etal, param); Translators = list_people (control, t, translator_etal); end do -- now do contributors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayContributors'], A['DisplayContributors'], A:ORIGIN ('DisplayContributors'), #c); control.maximum, contributor_etal = get_display_names (display_names, #c, 'contributors', contributor_etal, param); Contributors = list_people (control, c, contributor_etal); end do -- now do authors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayAuthors'], A['DisplayAuthors'], A:ORIGIN ('DisplayAuthors'), #a, author_etal); control.maximum, author_etal = get_display_names (display_names, #a, 'authors', author_etal, param); last_first_list = list_people (control, a, author_etal); if utilities.is_set (Authors) then Authors, author_etal = name_has_etal (Authors, author_etal, false, 'authors'); -- find and remove variations on et al. if author_etal then Authors = Authors .. ' ' .. cfg.messages['et al']; -- add et al. to authors parameter end else Authors = last_first_list; -- either an author name list or an empty string end end -- end of do if utilities.is_set (Authors) and utilities.is_set (Collaboration) then Authors = Authors .. ' (' .. Collaboration .. ')'; -- add collaboration after et al. end end local ConferenceFormat = A['ConferenceFormat']; local ConferenceURL = A['ConferenceURL']; ConferenceFormat = style_format (ConferenceFormat, ConferenceURL, 'conference-format', 'conference-url'); Format = style_format (Format, URL, 'format', 'url'); -- special case for chapter format so no error message or cat when chapter not supported if not (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia))) then ChapterFormat = style_format (ChapterFormat, ChapterURL, 'chapter-format', 'chapter-url'); end if not utilities.is_set (URL) then if utilities.in_array (config.CitationClass, {"web", "podcast", "mailinglist"}) or -- |url= required for cite web, cite podcast, and cite mailinglist ('citation' == config.CitationClass and ('website' == Periodical_origin or 'script-website' == ScriptPeriodical_origin)) then -- and required for {{citation}} with |website= or |script-website= utilities.set_message ('err_cite_web_url'); end -- do we have |accessdate= without either |url= or |chapter-url=? if utilities.is_set (AccessDate) and not utilities.is_set (ChapterURL) then -- ChapterURL may be set when URL is not set; utilities.set_message ('err_accessdate_missing_url'); AccessDate = ''; end end local UrlStatus = is_valid_parameter_value (A['UrlStatus'], A:ORIGIN('UrlStatus'), cfg.keywords_lists['url-status'], ''); local OriginalURL local OriginalURL_origin local OriginalFormat local OriginalAccess; UrlStatus = UrlStatus:lower(); -- used later when assembling archived text if utilities.is_set ( ArchiveURL ) then if utilities.is_set (ChapterURL) then -- if chapter-url= is set apply archive url to it OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text OriginalURL_origin = ChapterURL_origin; -- name of |chapter-url= parameter for error messages OriginalFormat = ChapterFormat; -- and original |chapter-format= if 'live' ~= UrlStatus then ChapterURL = ArchiveURL -- swap-in the archive's URL ChapterURL_origin = A:ORIGIN('ArchiveURL') -- name of |archive-url= parameter for error messages ChapterFormat = ArchiveFormat or ''; -- swap in archive's format ChapterUrlAccess = nil; -- restricted access levels do not make sense for archived URLs end elseif utilities.is_set (URL) then OriginalURL = URL; -- save copy of original source URL OriginalURL_origin = URL_origin; -- name of URL parameter for error messages OriginalFormat = Format; -- and original |format= OriginalAccess = UrlAccess; if 'live' ~= UrlStatus then -- if URL set then |archive-url= applies to it URL = ArchiveURL -- swap-in the archive's URL URL_origin = A:ORIGIN('ArchiveURL') -- name of archive URL parameter for error messages Format = ArchiveFormat or ''; -- swap in archive's format UrlAccess = nil; -- restricted access levels do not make sense for archived URLs end end elseif utilities.is_set (UrlStatus) then -- if |url-status= is set when |archive-url= is not set utilities.set_message ('maint_url_status'); -- add maint cat end if utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or -- if any of the 'periodical' cites except encyclopedia ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) then local chap_param; if utilities.is_set (Chapter) then -- get a parameter name from one of these chapter related meta-parameters chap_param = A:ORIGIN ('Chapter') elseif utilities.is_set (TransChapter) then chap_param = A:ORIGIN ('TransChapter') elseif utilities.is_set (ChapterURL) then chap_param = A:ORIGIN ('ChapterURL') elseif utilities.is_set (ScriptChapter) then chap_param = ScriptChapter_origin; else utilities.is_set (ChapterFormat) chap_param = A:ORIGIN ('ChapterFormat') end if utilities.is_set (chap_param) then -- if we found one utilities.set_message ('err_chapter_ignored', {chap_param}); -- add error message Chapter = ''; -- and set them to empty string to be safe with concatenation TransChapter = ''; ChapterURL = ''; ScriptChapter = ''; ChapterFormat = ''; end else -- otherwise, format chapter / article title local no_quotes = false; -- default assume that we will be quoting the chapter parameter value if utilities.is_set (Contribution) and 0 < #c then -- if this is a contribution with contributor(s) if utilities.in_array (Contribution:lower(), cfg.keywords_lists.contribution) then -- and a generic contribution title no_quotes = true; -- then render it unquoted end end Chapter = format_chapter_title (ScriptChapter, ScriptChapter_origin, Chapter, Chapter_origin, TransChapter, TransChapter_origin, ChapterURL, ChapterURL_origin, no_quotes, ChapterUrlAccess); -- Contribution is also in Chapter if utilities.is_set (Chapter) then Chapter = Chapter .. ChapterFormat ; if 'map' == config.CitationClass and utilities.is_set (TitleType) then Chapter = Chapter .. ' ' .. TitleType; -- map annotation here; not after title end Chapter = Chapter .. sepc .. ' '; elseif utilities.is_set (ChapterFormat) then -- |chapter= not set but |chapter-format= is so ... Chapter = ChapterFormat .. sepc .. ' '; -- ... ChapterFormat has error message, we want to see it end end -- Format main title local plain_title = false; local accept_title; Title, accept_title = utilities.has_accept_as_written (Title, true); -- remove accept-this-as-written markup when it wraps all of <Title> if accept_title and ('' == Title) then -- only support forced empty for now "(())" Title = cfg.messages['notitle']; -- replace by predefined "No title" message -- TODO: utilities.set_message ( 'err_redundant_parameters', ...); -- issue proper error message instead of muting ScriptTitle = ''; -- just mute for now TransTitle = ''; -- just mute for now plain_title = true; -- suppress text decoration for descriptive title utilities.set_message ('maint_untitled'); -- add maint cat end if not accept_title then -- <Title> not wrapped in accept-as-written markup if '...' == Title:sub (-3) then -- if ellipsis is the last three characters of |title= Title = Title:gsub ('(%.%.%.)%.+$', '%1'); -- limit the number of dots to three elseif not mw.ustring.find (Title, '%.%s*%a%.$') and -- end of title is not a 'dot-(optional space-)letter-dot' initialism ... not mw.ustring.find (Title, '%s+%a%.$') then -- ...and not a 'space-letter-dot' initial (''Allium canadense'' L.) Title = mw.ustring.gsub(Title, '%' .. sepc .. '$', ''); -- remove any trailing separator character; sepc and ms.ustring() here for languages that use multibyte separator characters end if utilities.is_set (ArchiveURL) and is_archived_copy (Title) then utilities.set_message ('maint_archived_copy'); -- add maintenance category before we modify the content of Title end if is_generic ('generic_titles', Title) then utilities.set_message ('err_generic_title'); -- set an error message end end if (not plain_title) and (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'document', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) or ('map' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)))) then -- special case for cite map when the map is in a periodical treat as an article Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from module provided quote marks Title = utilities.wrap_style ('quoted-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); elseif plain_title or ('report' == config.CitationClass) then -- no styling for cite report and descriptive titles (otherwise same as above) Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); -- for cite report, use this form for trans-title else Title = utilities.wrap_style ('italic-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-italic-title', TransTitle); end if utilities.is_set (TransTitle) then if utilities.is_set (Title) then TransTitle = " " .. TransTitle; else utilities.set_message ('err_trans_missing_title', {'title'}); end end if utilities.is_set (Title) then -- TODO: is this the right place to be making Wikisource URLs? if utilities.is_set (TitleLink) and utilities.is_set (URL) then utilities.set_message ('err_wikilink_in_url'); -- set an error message because we can't have both TitleLink = ''; -- unset end if not utilities.is_set (TitleLink) and utilities.is_set (URL) then Title = external_link (URL, Title, URL_origin, UrlAccess) .. TransTitle .. Format; URL = ''; -- unset these because no longer needed Format = ""; elseif utilities.is_set (TitleLink) and not utilities.is_set (URL) then local ws_url; ws_url = wikisource_url_make (TitleLink); -- ignore ws_label return; not used here if ws_url then Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title-link'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], TitleLink, Title}); Title = Title .. TransTitle; else Title = utilities.make_wikilink (TitleLink, Title) .. TransTitle; end else local ws_url, ws_label, L; -- Title has italic or quote markup by the time we get here which causes is_wikilink() to return 0 (not a wikilink) ws_url, ws_label, L = wikisource_url_make (Title:gsub('^[\'"]*(.-)[\'"]*$', '%1')); -- make ws URL from |title= interwiki link (strip italic or quote markup); link portion L becomes tooltip label if ws_url then Title = Title:gsub ('%b[]', ws_label); -- replace interwiki link with ws_label to retain markup Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, Title}); Title = Title .. TransTitle; else Title = Title .. TransTitle; end end else Title = TransTitle; end if utilities.is_set (Place) then Place = " " .. wrap_msg ('written', Place, use_lowercase) .. sepc .. " "; end local ConferenceURL_origin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL if utilities.is_set (Conference) then if utilities.is_set (ConferenceURL) then Conference = external_link( ConferenceURL, Conference, ConferenceURL_origin, nil ); end Conference = sepc .. " " .. Conference .. ConferenceFormat; elseif utilities.is_set (ConferenceURL) then Conference = sepc .. " " .. external_link( ConferenceURL, nil, ConferenceURL_origin, nil ); end local Position = ''; if not utilities.is_set (Position) then local Minutes = A['Minutes']; local Time = A['Time']; if utilities.is_set (Minutes) then if utilities.is_set (Time) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'minutes') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'time')}); end Position = " " .. Minutes .. " " .. cfg.messages['minutes']; else if utilities.is_set (Time) then local TimeCaption = A['TimeCaption'] if not utilities.is_set (TimeCaption) then TimeCaption = cfg.messages['event']; if sepc ~= '.' then TimeCaption = TimeCaption:lower(); end end Position = " " .. TimeCaption .. " " .. Time; end end else Position = " " .. Position; At = ''; end Page, Pages, Sheet, Sheets = format_pages_sheets (Page, Pages, Sheet, Sheets, config.CitationClass, Periodical_origin, sepc, NoPP, use_lowercase); At = utilities.is_set (At) and (sepc .. " " .. At) or ""; Position = utilities.is_set (Position) and (sepc .. " " .. Position) or ""; if config.CitationClass == 'map' then local Sections = A['Sections']; -- Section (singular) is an alias of Chapter so set earlier local Inset = A['Inset']; if utilities.is_set ( Inset ) then Inset = sepc .. " " .. wrap_msg ('inset', Inset, use_lowercase); end if utilities.is_set ( Sections ) then Section = sepc .. " " .. wrap_msg ('sections', Sections, use_lowercase); elseif utilities.is_set ( Section ) then Section = sepc .. " " .. wrap_msg ('section', Section, use_lowercase); end At = At .. Inset .. Section; end local Others = A['Others']; if utilities.is_set (Others) and 0 == #a and 0 == #e then -- add maint cat when |others= has value and used without |author=, |editor= if config.CitationClass == "AV-media-notes" or config.CitationClass == "audio-visual" then -- special maint for AV/M which has a lot of 'false' positives right now utilities.set_message ('maint_others_avm') else utilities.set_message ('maint_others'); end end Others = utilities.is_set (Others) and (sepc .. " " .. Others) or ""; if utilities.is_set (Translators) then Others = safe_join ({sepc .. ' ', wrap_msg ('translated', Translators, use_lowercase), Others}, sepc); end if utilities.is_set (Interviewers) then Others = safe_join ({sepc .. ' ', wrap_msg ('interview', Interviewers, use_lowercase), Others}, sepc); end local TitleNote = A['TitleNote']; TitleNote = utilities.is_set (TitleNote) and (sepc .. " " .. TitleNote) or ""; if utilities.is_set (Edition) then if Edition:match ('%f[%a][Ee]d%n?%.?$') or Edition:match ('%f[%a][Ee]dition$') then -- Ed, ed, Ed., ed., Edn, edn, Edn., edn. utilities.set_message ('err_extra_text_edition'); -- add error message end Edition = " " .. wrap_msg ('edition', Edition); else Edition = ''; end Series = utilities.is_set (Series) and wrap_msg ('series', {sepc, Series}) or ""; -- not the same as SeriesNum local Agency = A['Agency'] or ''; -- |agency= is supported by {{cite magazine}}, {{cite news}}, {{cite press release}}, {{cite web}}, and certain {{citation}} templates if utilities.is_set (Agency) then -- this testing done here because {{citation}} supports 'news' citations if utilities.in_array (config.CitationClass, {'magazine', 'news', 'pressrelease', 'web'}) or ('citation' == config.CitationClass and utilities.in_array (Periodical_origin, {"magazine", "newspaper", "work"})) then Agency = wrap_msg ('agency', {sepc, Agency}); -- format for rendering else Agency = ''; -- unset; not supported utilities.set_message ('err_parameter_ignored', {'agency'}); -- add error message end end Volume = format_volume_issue (Volume, Issue, ArticleNumber, config.CitationClass, Periodical_origin, sepc, use_lowercase); if utilities.is_set (AccessDate) then local retrv_text = " " .. cfg.messages['retrieved'] AccessDate = nowrap_date (AccessDate); -- wrap in nowrap span if date in appropriate format if (sepc ~= ".") then retrv_text = retrv_text:lower() end -- if mode is cs2, lower case AccessDate = utilities.substitute (retrv_text, AccessDate); -- add retrieved text AccessDate = utilities.substitute (cfg.presentation['accessdate'], {sepc, AccessDate}); -- allow editors to hide accessdates end if utilities.is_set (ID) then ID = sepc .. " " .. ID; end local Docket = A['Docket']; if "thesis" == config.CitationClass and utilities.is_set (Docket) then ID = sepc .. " Docket " .. Docket .. ID; end if "report" == config.CitationClass and utilities.is_set (Docket) then -- for cite report when |docket= is set ID = sepc .. ' ' .. Docket; -- overwrite ID even if |id= is set end if utilities.is_set (URL) then URL = " " .. external_link( URL, nil, URL_origin, UrlAccess ); end -- We check length of PostScript here because it will have been nuked by -- the quote parameters. We'd otherwise emit a message even if there wasn't -- a displayed postscript. -- TODO: Should the max size (1) be configurable? -- TODO: Should we check a specific pattern? if utilities.is_set(PostScript) and mw.ustring.len(PostScript) > 1 then utilities.set_message ('maint_postscript') end local Archived; if utilities.is_set (ArchiveURL) then if not utilities.is_set (ArchiveDate) then -- ArchiveURL set but ArchiveDate not set utilities.set_message ('err_archive_missing_date'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end else if utilities.is_set (ArchiveDate) then -- ArchiveURL not set but ArchiveDate is set utilities.set_message ('err_archive_date_missing_url'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end end if utilities.is_set (ArchiveURL) then local arch_text; if "live" == UrlStatus then arch_text = cfg.messages['archived']; if sepc ~= "." then arch_text = arch_text:lower() end if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cfg.messages['archived-live'], {external_link( ArchiveURL, arch_text, A:ORIGIN('ArchiveURL'), nil) .. ArchiveFormat, ArchiveDate } ); else Archived = ''; end if not utilities.is_set (OriginalURL) then utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (OriginalURL) then -- UrlStatus is empty, 'dead', 'unfit', 'usurped', 'bot: unknown' if utilities.in_array (UrlStatus, {'unfit', 'usurped', 'bot: unknown'}) then arch_text = cfg.messages['archived-unfit']; if sepc ~= "." then arch_text = arch_text:lower() end Archived = sepc .. ' ' .. arch_text .. ArchiveDate; -- format already styled if 'bot: unknown' == UrlStatus then utilities.set_message ('maint_bot_unknown'); -- and add a category if not already added else utilities.add_prop_cat ('unfit'); -- and add a category if not already added end else -- UrlStatus is empty, 'dead' arch_text = cfg.messages['archived-dead']; if sepc ~= "." then arch_text = arch_text:lower() end if utilities.is_set (ArchiveDate) then Archived = sepc .. " " .. utilities.substitute ( arch_text, { external_link( OriginalURL, cfg.messages['original'], OriginalURL_origin, OriginalAccess ) .. OriginalFormat, ArchiveDate } ); -- format already styled else Archived = ''; -- unset for concatenation end end else -- OriginalUrl not set utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (ArchiveFormat) then Archived = ArchiveFormat; -- if set and ArchiveURL not set ArchiveFormat has error message else Archived = ''; end local TranscriptURL = A['TranscriptURL'] local TranscriptFormat = A['TranscriptFormat']; TranscriptFormat = style_format (TranscriptFormat, TranscriptURL, 'transcript-format', 'transcripturl'); local Transcript = A['Transcript']; local TranscriptURL_origin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL if utilities.is_set (Transcript) then if utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, Transcript, TranscriptURL_origin, nil ); end Transcript = sepc .. ' ' .. Transcript .. TranscriptFormat; elseif utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, nil, TranscriptURL_origin, nil ); end local Publisher; if utilities.is_set (PublicationDate) then PublicationDate = wrap_msg ('published', PublicationDate); end if utilities.is_set (PublisherName) then if utilities.is_set (PublicationPlace) then Publisher = sepc .. " " .. PublicationPlace .. ": " .. PublisherName .. PublicationDate; else Publisher = sepc .. " " .. PublisherName .. PublicationDate; end elseif utilities.is_set (PublicationPlace) then Publisher= sepc .. " " .. PublicationPlace .. PublicationDate; else Publisher = PublicationDate; end -- Several of the above rely upon detecting this as nil, so do it last. if (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical)) then if utilities.is_set (Title) or utilities.is_set (TitleNote) then Periodical = sepc .. " " .. format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); else Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); end end local Language = A['Language']; if utilities.is_set (Language) then Language = language_parameter (Language); -- format, categories, name from ISO639-1, etc. else Language=''; -- language not specified so make sure this is an empty string; --[[ TODO: need to extract the wrap_msg from language_parameter so that we can solve parentheses bunching problem with Format/Language/TitleType ]] end --[[ Handle the oddity that is cite speech. This code overrides whatever may be the value assigned to TitleNote (through |department=) and forces it to be " (Speech)" so that the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided). ]] if "speech" == config.CitationClass then -- cite speech only TitleNote = TitleType; -- move TitleType to TitleNote so that it renders ahead of |event= TitleType = ''; -- and unset if utilities.is_set (Periodical) then -- if Periodical, perhaps because of an included |website= or |journal= parameter if utilities.is_set (Conference) then -- and if |event= is set Conference = Conference .. sepc .. " "; -- then add appropriate punctuation to the end of the Conference variable before rendering end end end -- Piece all bits together at last. Here, all should be non-nil. -- We build things this way because it is more efficient in LUA -- not to keep reassigning to the same string variable over and over. local tcommon; local tcommon2; -- used for book cite when |contributor= is set if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (Periodical) then -- special cases for book cites if utilities.is_set (Contributors) then -- when we are citing foreword, preface, introduction, etc. tcommon = safe_join ({Title, TitleNote}, sepc); -- author and other stuff will come after this and before tcommon2 tcommon2 = safe_join ({TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); else tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); end elseif 'map' == config.CitationClass then -- special cases for cite map if utilities.is_set (Chapter) then -- map in a book; TitleType is part of Chapter tcommon = safe_join ({Title, Edition, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); elseif utilities.is_set (Periodical) then -- map in a periodical tcommon = safe_join ({Title, TitleType, Periodical, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); else -- a sheet or stand-alone map tcommon = safe_join ({Title, TitleType, Edition, Scale, Series, Language, Cartography, Others, Publisher}, sepc); end elseif 'episode' == config.CitationClass then -- special case for cite episode tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Edition, Publisher}, sepc); else -- all other CS1 templates tcommon = safe_join ({Title, TitleNote, Conference, Periodical, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc); end if #ID_list > 0 then ID_list = safe_join( { sepc .. " ", table.concat( ID_list, sepc .. " " ), ID }, sepc ); else ID_list = ID; end local Via = A['Via']; Via = utilities.is_set (Via) and wrap_msg ('via', Via) or ''; local idcommon; if 'audio-visual' == config.CitationClass or 'episode' == config.CitationClass then -- special case for cite AV media & cite episode position transcript idcommon = safe_join( { ID_list, URL, Archived, Transcript, AccessDate, Via, Quote }, sepc ); else idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, Quote }, sepc ); end local text; local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; local OrigDate = A['OrigDate']; OrigDate = utilities.is_set (OrigDate) and wrap_msg ('origdate', OrigDate) or ''; if utilities.is_set (Date) then if utilities.is_set (Authors) or utilities.is_set (Editors) then -- date follows authors or editors when authors not set Date = " (" .. Date .. ")" .. OrigDate .. sepc .. " "; -- in parentheses else -- neither of authors and editors set if (string.sub(tcommon, -1, -1) == sepc) then -- if the last character of tcommon is sepc Date = " " .. Date .. OrigDate; -- Date does not begin with sepc else Date = sepc .. " " .. Date .. OrigDate; -- Date begins with sepc end end end if utilities.is_set (Authors) then if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Authors termination Authors = terminate_name_list (Authors, sepc); -- when no date, terminate with 0 or 1 sepc and a space end if utilities.is_set (Editors) then local in_text = ''; local post_text = ''; if utilities.is_set (Chapter) and 0 == #c then in_text = cfg.messages['in'] .. ' '; if (sepc ~= '.') then in_text = in_text:lower(); -- lowercase for cs2 end end if EditorCount <= 1 then post_text = ' (' .. cfg.messages['editor'] .. ')'; -- be consistent with no-author, no-date case else post_text = ' (' .. cfg.messages['editors'] .. ')'; end Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space end if utilities.is_set (Contributors) then -- book cite and we're citing the intro, preface, etc. local by_text = sepc .. ' ' .. cfg.messages['by'] .. ' '; if (sepc ~= '.') then by_text = by_text:lower() end -- lowercase for cs2 Authors = by_text .. Authors; -- author follows title so tweak it here if utilities.is_set (Editors) and utilities.is_set (Date) then -- when Editors make sure that Authors gets terminated Authors = terminate_name_list (Authors, sepc); -- terminate with 0 or 1 sepc and a space end if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Contributors termination Contributors = terminate_name_list (Contributors, sepc); -- terminate with 0 or 1 sepc and a space end text = safe_join( {Contributors, Date, Chapter, tcommon, Authors, Place, Editors, tcommon2, pgtext, idcommon }, sepc ); else text = safe_join( {Authors, Date, Chapter, Place, Editors, tcommon, pgtext, idcommon }, sepc ); end elseif utilities.is_set (Editors) then if utilities.is_set (Date) then if EditorCount <= 1 then Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editor']; else Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editors']; end else if EditorCount <= 1 then Editors = Editors .. " (" .. cfg.messages['editor'] .. ")" .. sepc .. " " else Editors = Editors .. " (" .. cfg.messages['editors'] .. ")" .. sepc .. " " end end text = safe_join( {Editors, Date, Chapter, Place, tcommon, pgtext, idcommon}, sepc ); else if utilities.in_array (config.CitationClass, {"journal", "citation"}) and utilities.is_set (Periodical) then text = safe_join( {Chapter, Place, tcommon, pgtext, Date, idcommon}, sepc ); else text = safe_join( {Chapter, Place, tcommon, Date, pgtext, idcommon}, sepc ); end end if utilities.is_set (PostScript) and PostScript ~= sepc then text = safe_join( {text, sepc}, sepc ); -- Deals with italics, spaces, etc. if '.' == sepc then -- remove final seperator if present text = text:gsub ('%' .. sepc .. '$', ''); -- dot must be escaped here else text = mw.ustring.gsub (text, sepc .. '$', ''); -- using ustring for non-dot sepc (likely a non-Latin character) end end text = safe_join( {text, PostScript}, sepc ); -- Now enclose the whole thing in a <cite> element local options_t = {}; options_t.class = cite_class_attribute_make (config.CitationClass, Mode); local Ref = is_valid_parameter_value (A['Ref'], A:ORIGIN('Ref'), cfg.keywords_lists['ref'], nil, true); -- nil when |ref=harv; A['Ref'] else if 'none' ~= cfg.keywords_xlate[(Ref and Ref:lower()) or ''] then local namelist_t = {}; -- holds selected contributor, author, editor name list local year = first_set ({Year, anchor_year}, 2); -- Year first for legacy citations and for YMD dates that require disambiguation if #c > 0 then -- if there is a contributor list namelist_t = c; -- select it elseif #a > 0 then -- or an author list namelist_t = a; elseif #e > 0 then -- or an editor list namelist_t = e; end local citeref_id; if #namelist_t > 0 then -- if there are names in namelist_t citeref_id = make_citeref_id (namelist_t, year); -- go make the CITEREF anchor if mw.uri.anchorEncode (citeref_id) == ((Ref and mw.uri.anchorEncode (Ref)) or '') then -- Ref may already be encoded (by {{sfnref}}) so citeref_id must be encoded before comparison utilities.set_message ('maint_ref_duplicates_default'); end else citeref_id = ''; -- unset end options_t.id = Ref or citeref_id; end if string.len (text:gsub('%b<>', '')) <= 2 then -- remove html and html-like tags; then get length of what remains; z.error_cats_t = {}; -- blank the categories list z.error_msgs_t = {}; -- blank the error messages list OCinSoutput = nil; -- blank the metadata string text = ''; -- blank the the citation utilities.set_message ('err_empty_citation'); -- set empty citation message and category end local render_t = {}; -- here we collect the final bits for concatenation into the rendered citation if utilities.is_set (options_t.id) then -- here we wrap the rendered citation in <cite ...>...</cite> tags table.insert (render_t, utilities.substitute (cfg.presentation['cite-id'], {mw.uri.anchorEncode(options_t.id), mw.text.nowiki(options_t.class), text})); -- when |ref= is set or when there is a namelist else table.insert (render_t, utilities.substitute (cfg.presentation['cite'], {mw.text.nowiki(options_t.class), text})); -- when |ref=none or when namelist_t empty and |ref= is missing or is empty end if OCinSoutput then -- blanked when citation is 'empty' so don't bother to add boilerplate metadata span table.insert (render_t, utilities.substitute (cfg.presentation['ocins'], OCinSoutput)); -- format and append metadata to the citation end local template_name = ('citation' == config.CitationClass) and 'citation' or 'cite ' .. (cfg.citation_class_map_t[config.CitationClass] or config.CitationClass); local template_link = '[[Template:' .. template_name .. '|' .. template_name .. ']]'; local msg_prefix = '<code class="cs1-code">{{' .. template_link .. '}}</code>: '; if 0 ~= #z.error_msgs_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_e, template_link)); table.insert (render_t, ' '); -- insert a space between citation and its error messages table.sort (z.error_msgs_t); -- sort the error messages list; sorting includes wrapping <span> and <code> tags; hidden-error sorts ahead of visible-error local hidden = true; -- presume that the only error messages emited by this template are hidden for _, v in ipairs (z.error_msgs_t) do -- spin through the list of error messages if v:find ('cs1-visible-error', 1, true) then -- look for the visible error class name hidden = false; -- found one; so don't hide the error message prefix break; -- and done because no need to look further end end z.error_msgs_t[1] = table.concat ({utilities.error_comment (msg_prefix, hidden), z.error_msgs_t[1]}); -- add error message prefix to first error message to prevent extraneous punctuation table.insert (render_t, table.concat (z.error_msgs_t, '; ')); -- make a big string of error messages and add it to the rendering end if 0 ~= #z.maint_cats_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_m, template_link)); table.sort (z.maint_cats_t); -- sort the maintenance messages list local maint_msgs_t = {}; -- here we collect all of the maint messages if 0 == #z.error_msgs_t then -- if no error messages table.insert (maint_msgs_t, msg_prefix); -- insert message prefix in maint message livery end for _, v in ipairs( z.maint_cats_t ) do -- append maintenance categories table.insert (maint_msgs_t, -- assemble new maint message and add it to the maint_msgs_t table table.concat ({v, ' (', utilities.substitute (cfg.messages[':cat wikilink'], v), ')'}) ); end table.insert (render_t, utilities.substitute (cfg.presentation['hidden-maint'], table.concat (maint_msgs_t, ' '))); -- wrap the group of maint messages with proper presentation and save end if not no_tracking_cats then local sort_key; local cat_wikilink = 'cat wikilink'; if cfg.enable_sort_keys then -- when namespace sort keys enabled local namespace_number = mw.title.getCurrentTitle().namespace; -- get namespace number for this wikitext sort_key = (0 ~= namespace_number and (cfg.name_space_sort_keys[namespace_number] or cfg.name_space_sort_keys.other)) or nil; -- get sort key character; nil for mainspace cat_wikilink = (not sort_key and 'cat wikilink') or 'cat wikilink sk'; -- make <cfg.messages> key end for _, v in ipairs (z.error_cats_t) do -- append error categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end if cfg.id_limits_data_load_fail then -- boolean true when load failed utilities.set_message ('maint_id_limit_load_fail'); -- done here because this maint cat emits no message end for _, v in ipairs (z.maint_cats_t) do -- append maintenance categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end for _, v in ipairs (z.prop_cats_t) do -- append properties categories table.insert (render_t, utilities.substitute (cfg.messages['cat wikilink'], v)); -- no sort keys end end return table.concat (render_t); -- make a big string and done end --[[--------------------------< V A L I D A T E >-------------------------------------------------------------- Looks for a parameter's name in one of several whitelists. Parameters in the whitelist can have three values: true - active, supported parameters false - deprecated, supported parameters nil - unsupported parameters ]] local function validate (name, cite_class, empty) local name = tostring (name); local enum_name; -- parameter name with enumerator (if any) replaced with '#' local state; local function state_test (state, name) -- local function to do testing of state values if true == state then return true; end -- valid actively supported parameter if false == state then if empty then return nil; end -- empty deprecated parameters are treated as unknowns deprecated_parameter (name); -- parameter is deprecated but still supported return true; end if 'tracked' == state then local base_name = name:gsub ('%d', ''); -- strip enumerators from parameter names that have them to get the base name utilities.add_prop_cat ('tracked-param', {base_name}, base_name); -- add a properties category; <base_name> modifies <key> return true; end return nil; end if name:find ('#') then -- # is a cs1|2 reserved character so parameters with # not permitted return nil; end -- replace enumerator digit(s) with # (|last25= becomes |last#=) (mw.ustring because non-Western 'local' digits) enum_name = mw.ustring.gsub (name, '%d+$', '#'); -- where enumerator is last charaters in parameter name (these to protect |s2cid=) enum_name = mw.ustring.gsub (enum_name, '%d+([%-l])', '#%1'); -- where enumerator is in the middle of the parameter name; |author#link= is the oddity if 'document' == cite_class then -- special case for {{cite document}} state = whitelist.document_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end return false; end if utilities.in_array (cite_class, whitelist.preprint_template_list_t) then -- limited parameter sets allowed for these templates state = whitelist.limited_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end state = whitelist.preprint_arguments_t[cite_class][name]; -- look in the parameter-list for the template identified by cite_class if true == state_test (state, name) then return true; end return false; -- not supported because not found or name is set to nil end -- end limited parameter-set templates if utilities.in_array (cite_class, whitelist.unique_param_template_list_t) then -- template-specific parameters for templates that accept parameters from the basic argument list state = whitelist.unique_arguments_t[cite_class][name]; -- look in the template-specific parameter-lists for the template identified by cite_class if true == state_test (state, name) then return true; end end -- if here, fall into general validation state = whitelist.common_parameters_t[enum_name]; -- all other templates; all normal parameters allowed; this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end return false; -- not supported because not found or name is set to nil end --[=[-------------------------< I N T E R _ W I K I _ C H E C K >---------------------------------------------- check <value> for inter-language interwiki-link markup. <prefix> must be a MediaWiki-recognized language code. when these values have the form (without leading colon): [[<prefix>:link|label]] return label as plain-text [[<prefix>:link]] return <prefix>:link as plain-text return value as is else ]=] local function inter_wiki_check (parameter, value) local prefix = value:match ('%[%[(%a+):'); -- get an interwiki prefix if one exists local _; if prefix and cfg.inter_wiki_map[prefix:lower()] then -- if prefix is in the map, needs preceding colon so utilities.set_message ('err_bad_paramlink', parameter); -- emit an error message _, value, _ = utilities.is_wikilink (value); -- extract label portion from wikilink end return value; end --[[--------------------------< M I S S I N G _ P I P E _ C H E C K >------------------------------------------ Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal sign, compare the alphanumeric string to the list of cs1|2 parameters. If found, then the string is possibly a parameter that is missing its pipe. There are two tests made: {{cite ... |title=Title access-date=2016-03-17}} -- the first parameter has a value and whitespace separates that value from the missing pipe parameter name {{cite ... |title=access-date=2016-03-17}} -- the first parameter has no value (whitespace after the first = is trimmed by MediaWiki) cs1|2 shares some parameter names with XML/HTML attributes: class=, title=, etc. To prevent false positives XML/HTML tags are removed before the search. If a missing pipe is detected, this function adds the missing pipe maintenance category. ]] local function missing_pipe_check (parameter, value) local capture; value = value:gsub ('%b<>', ''); -- remove XML/HTML tags because attributes: class=, title=, etc. capture = value:match ('%s+(%a[%w%-]+)%s*=') or value:match ('^(%a[%w%-]+)%s*='); -- find and categorize parameters with possible missing pipes if capture and validate (capture) then -- if the capture is a valid parameter name utilities.set_message ('err_missing_pipe', parameter); end end --[[--------------------------< H A S _ E X T R A N E O U S _ P U N C T >-------------------------------------- look for extraneous terminal punctuation in most parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_punc (param, value) if 'number' == type (param) then return; end param = param:gsub ('%d+', '#'); -- enumerated name-list mask params allow terminal punct; normalize if cfg.punct_skip[param] then return; -- parameter name found in the skip table so done end if value:match ('[,;:]$') then utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end if value:match ('^=') then -- sometimes an extraneous '=' character appears ... utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end end --[[--------------------------< H A S _ T W L _ U R L >-------------------------------------------------------- look for The Wikipedia Library urls in url-holding parameters. TWL urls are accessible only for readers who are active extended confirmed Wikipedia editors. This function sets an error message when such urls are discovered and when appropriate, sets the |<param>-url-access=subscription. returns nothing. looks for: '.wikipedialibrary.idm.oclc.org' ]] local function has_twl_url (url_params_t, cite_args_t) local url_error_t = {}; -- sequence of url-holding parameters that have a TWL url for param, value in pairs (url_params_t) do if value:find ('%.wikipedialibrary%.idm%.oclc%.org') then -- has the TWL base url? table.insert (url_error_t, param); -- add parameter name to the error list end end if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); -- sor for error messaging for i, param in ipairs (url_error_t) do if cfg.url_access_map_t[param] then -- if <param> has a matching -access parameter cite_args_t[cfg.url_access_map_t[param]] = cfg.keywords_xlate.subscription; -- set |<param>-url-access=subscription end url_error_t[i] = utilities.wrap_style ('parameter', param); -- make the parameter pretty for error message end utilities.set_message ('err_param_has_twl_url', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< H A S _ E X T R A N E O U S _ U R L >------------------------------------------ look for extraneous url parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_url (non_url_param_t) local url_error_t = {}; check_for_url (non_url_param_t, url_error_t); -- extraneous url check if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); utilities.set_message ('err_param_has_ext_link', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< _ C I T A T I O N >------------------------------------------------------------ Module entry point frame – from template call (citation()); may be nil when called from another module args_t – table of all cs1|2 parameters in the template (the parent frame) config_t – table of template-supplied parameter (the #invoke frame) ]] local function _citation (frame, args_t, config_t) -- save a copy in case we need to display an error message in preview mode if not frame then frame = mw.getCurrentFrame(); -- if called from another module, get a frame for frame-provided functions end -- i18n: set the name that your wiki uses to identify sandbox subpages from sandbox template invoke (or can be set here) local sandbox = ((config_t.SandboxPath and '' ~= config_t.SandboxPath) and config_t.SandboxPath) or '/sandbox'; -- sandbox path from {{#invoke:Citation/CS1/sandbox|citation|SandboxPath=/...}} is_sandbox = nil ~= string.find (frame:getTitle(), sandbox, 1, true); -- is this invoke the sandbox module? sandbox = is_sandbox and sandbox or ''; -- use i18n sandbox to load sandbox modules when this module is the sandox; live modules else cfg = mw.loadData ('Module:Citation/CS1/Configuration' .. sandbox); -- load sandbox versions of support modules when {{#invoke:Citation/CS1/sandbox|...}}; live modules else whitelist = mw.loadData ('Module:Citation/CS1/Whitelist' .. sandbox); utilities = require ('Module:Citation/CS1/Utilities' .. sandbox); validation = require ('Module:Citation/CS1/Date_validation' .. sandbox); identifiers = require ('Module:Citation/CS1/Identifiers' .. sandbox); metadata = require ('Module:Citation/CS1/COinS' .. sandbox); utilities.set_selected_modules (cfg); -- so that functions in Utilities can see the selected cfg tables identifiers.set_selected_modules (cfg, utilities); -- so that functions in Identifiers can see the selected cfg tables and selected Utilities module validation.set_selected_modules (cfg, utilities); -- so that functions in Date validataion can see selected cfg tables and the selected Utilities module metadata.set_selected_modules (cfg, utilities); -- so that functions in COinS can see the selected cfg tables and selected Utilities module z = utilities.z; -- table of error and category tables in Module:Citation/CS1/Utilities local cite_args_t = {}; -- because args_t is the parent (template) frame args (which cannot be modified); params and their values will be placed here is_preview_mode = not utilities.is_set (frame:preprocess ('{{REVISIONID}}')); local suggestions = {}; -- table where we store suggestions if we need to loadData them local error_text; -- used as a flag local capture; -- the single supported capture when matching unknown parameters using patterns local empty_unknowns = {}; -- sequence table to hold empty unknown params for error message listing for k, v in pairs (args_t) do -- get parameters from the parent (template) frame v = mw.ustring.gsub (v, '^%s*(.-)%s*$', '%1'); -- trim leading/trailing whitespace; when v is only whitespace, becomes empty string if v ~= '' then if ('string' == type (k)) then k = mw.ustring.gsub (k, '%d', cfg.date_names.local_digits); -- for enumerated parameters, translate 'local' digits to Western 0-9 end if not validate( k, config_t.CitationClass ) then if type (k) ~= 'string' then -- exclude empty numbered parameters if v:match("%S+") ~= nil then error_text = utilities.set_message ('err_text_ignored', {v}); end elseif validate (k:lower(), config_t.CitationClass) then error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, k:lower()}); -- suggest the lowercase version of the parameter else if nil == suggestions.suggestions then -- if this table is nil then we need to load it suggestions = mw.loadData ('Module:Citation/CS1/Suggestions' .. sandbox); --load sandbox version of suggestion module when {{#invoke:Citation/CS1/sandbox|...}}; live module else end for pattern, param in pairs (suggestions.patterns) do -- loop through the patterns to see if we can suggest a proper parameter capture = k:match (pattern); -- the whole match if no capture in pattern else the capture if a match if capture then -- if the pattern matches param = utilities.substitute (param, capture); -- add the capture to the suggested parameter (typically the enumerator) if validate (param, config_t.CitationClass) then -- validate the suggestion to make sure that the suggestion is supported by this template (necessary for limited parameter lists) error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, param}); -- set the suggestion error message else error_text = utilities.set_message ('err_parameter_ignored', {k}); -- suggested param not supported by this template v = ''; -- unset end end end if not utilities.is_set (error_text) then -- couldn't match with a pattern, is there an explicit suggestion? if (suggestions.suggestions[ k:lower() ] ~= nil) and validate (suggestions.suggestions[ k:lower() ], config_t.CitationClass) then utilities.set_message ('err_parameter_ignored_suggest', {k, suggestions.suggestions[ k:lower() ]}); else utilities.set_message ('err_parameter_ignored', {k}); v = ''; -- unset value assigned to unrecognized parameters (this for the limited parameter lists) end end end end cite_args_t[k] = v; -- save this parameter and its value elseif not utilities.is_set (v) then -- for empty parameters if not validate (k, config_t.CitationClass, true) then -- is this empty parameter a valid parameter k = ('' == k) and '(empty string)' or k; -- when k is empty string (or was space(s) trimmed to empty string), replace with descriptive text table.insert (empty_unknowns, utilities.wrap_style ('parameter', k)); -- format for error message and add to the list end end end if 0 ~= #empty_unknowns then -- create empty unknown error message utilities.set_message ('err_param_unknown_empty', { 1 == #empty_unknowns and '' or 's', utilities.make_sep_list (#empty_unknowns, empty_unknowns) }); end local non_url_param_t = {}; -- table of parameters and values that are not url-holding parameters local url_param_t = {}; -- table of url-holding paramters and their values for k, v in pairs (cite_args_t) do if 'string' == type (k) then -- don't evaluate positional parameters has_invisible_chars (k, v); -- look for invisible characters end has_extraneous_punc (k, v); -- look for extraneous terminal punctuation in parameter values missing_pipe_check (k, v); -- do we think that there is a parameter that is missing a pipe? cite_args_t[k] = inter_wiki_check (k, v); -- when language interwiki-linked parameter missing leading colon replace with wiki-link label if 'string' == type (k) then -- when parameter k is not positional if not cfg.url_skip[k] then -- and not in url skip table non_url_param_t[k] = v; -- make a parameter/value list for extraneous url check else -- and is in url skip table (a url-holding parameter) url_param_t[k] = v; -- make a parameter/value list to check for values that are The Wikipedia Library url end end end has_extraneous_url (non_url_param_t); -- look for url in parameter values where a url does not belong has_twl_url (url_param_t, cite_args_t); -- look for url-holding parameters that hold a The Wikipedia Library url return table.concat ({ frame:extensionTag ('templatestyles', '', {src='Module:Citation/CS1' .. sandbox .. '/styles.css'}), citation0 (config_t, cite_args_t) }); end --[[--------------------------< C I T A T I O N >-------------------------------------------------------------- Template entry point ]] local function citation (frame) local config_t = {}; -- table to store parameters from the module {{#invoke:}} local args_t = frame:getParent().args; -- get template's preset parameters for k, v in pairs (frame.args) do -- get parameters from the {{#invoke}} frame config_t[k] = v; -- args_t[k] = v; -- crude debug support that allows us to render a citation from module {{#invoke:}}; skips parameter validation; TODO: keep? end return _citation (frame, args_t, config_t) end --[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------ ]] return { citation = citation, -- template entry point _citation = _citation, -- module entry point } n8ax5wjn7gxgqkqtf80lxicvxqd470y 736729 736728 2025-09-02T13:27:48Z en>Trappist the monk 0 736729 Scribunto text/plain require ('strict'); --[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- each of these counts against the Lua upvalue limit ]] local validation; -- functions in Module:Citation/CS1/Date_validation local utilities; -- functions in Module:Citation/CS1/Utilities local z = {}; -- table of tables in Module:Citation/CS1/Utilities local identifiers; -- functions and tables in Module:Citation/CS1/Identifiers local metadata; -- functions in Module:Citation/CS1/COinS local cfg = {}; -- table of configuration tables that are defined in Module:Citation/CS1/Configuration local whitelist = {}; -- table of tables listing valid template parameter names; defined in Module:Citation/CS1/Whitelist --[[------------------< P A G E S C O P E V A R I A B L E S >--------------- declare variables here that have page-wide scope that are not brought in from other modules; that are created here and used here ]] local added_deprecated_cat; -- Boolean flag so that the category is added only once local added_vanc_errs; -- Boolean flag so we only emit one Vancouver error / category local added_generic_name_errs; -- Boolean flag so we only emit one generic name error / category and stop testing names once an error is encountered local added_numeric_name_errs; -- Boolean flag so we only emit one numeric name error / category and stop testing names once an error is encountered local added_numeric_name_maint; -- Boolean flag so we only emit one numeric name maint category and stop testing names once a category has been emitted local is_preview_mode; -- true when article is in preview mode; false when using 'Preview page with this template' (previewing the module) local is_sandbox; -- true when using sandbox modules to render citation --[[--------------------------< F I R S T _ S E T >------------------------------------------------------------ Locates and returns the first set value in a table of values where the order established in the table, left-to-right (or top-to-bottom), is the order in which the values are evaluated. Returns nil if none are set. This version replaces the original 'for _, val in pairs do' and a similar version that used ipairs. With the pairs version the order of evaluation could not be guaranteed. With the ipairs version, a nil value would terminate the for-loop before it reached the actual end of the list. ]] local function first_set (list, count) local i = 1; while i <= count do -- loop through all items in list if utilities.is_set( list[i] ) then return list[i]; -- return the first set list member end i = i + 1; -- point to next end end --[[--------------------------< A D D _ V A N C _ E R R O R >---------------------------------------------------- Adds a single Vancouver system error message to the template's output regardless of how many error actually exist. To prevent duplication, added_vanc_errs is nil until an error message is emitted. added_vanc_errs is a Boolean declared in page scope variables above ]] local function add_vanc_error (source, position) if added_vanc_errs then return end added_vanc_errs = true; -- note that we've added this category utilities.set_message ('err_vancouver', {source, position}); end --[[--------------------------< I S _ S C H E M E >------------------------------------------------------------ does this thing that purports to be a URI scheme seem to be a valid scheme? The scheme is checked to see if it is in agreement with http://tools.ietf.org/html/std66#section-3.1 which says: Scheme names consist of a sequence of characters beginning with a letter and followed by any combination of letters, digits, plus ("+"), period ("."), or hyphen ("-"). returns true if it does, else false ]] local function is_scheme (scheme) return scheme and scheme:match ('^%a[%a%d%+%.%-]*:'); -- true if scheme is set and matches the pattern end --[=[-------------------------< I S _ D O M A I N _ N A M E >-------------------------------------------------- Does this thing that purports to be a domain name seem to be a valid domain name? Syntax defined here: http://tools.ietf.org/html/rfc1034#section-3.5 BNF defined here: https://tools.ietf.org/html/rfc4234 Single character names are generally reserved; see https://tools.ietf.org/html/draft-ietf-dnsind-iana-dns-01#page-15; see also [[Single-letter second-level domain]] list of TLDs: https://www.iana.org/domains/root/db RFC 952 (modified by RFC 1123) requires the first and last character of a hostname to be a letter or a digit. Between the first and last characters the name may use letters, digits, and the hyphen. Also allowed are IPv4 addresses. IPv6 not supported domain is expected to be stripped of any path so that the last character in the last character of the TLD. tld is two or more alpha characters. Any preceding '//' (from splitting a URL with a scheme) will be stripped here. Perhaps not necessary but retained in case it is necessary for IPv4 dot decimal. There are several tests: the first character of the whole domain name including subdomains must be a letter or a digit internationalized domain name (ASCII characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the TLD) see https://tools.ietf.org/html/rfc3490 single-letter/digit second-level domains in the .org, .cash, and .today TLDs q, x, and z SL domains in the .com TLD i and q SL domains in the .net TLD single-letter SL domains in the ccTLDs (where the ccTLD is two letters) two-character SL domains in gTLDs (where the gTLD is two or more letters) three-plus-character SL domains in gTLDs (where the gTLD is two or more letters) IPv4 dot-decimal address format; TLD not allowed returns true if domain appears to be a proper name and TLD or IPv4 address, else false ]=] local function is_domain_name (domain) if not domain then return false; -- if not set, abandon end domain = domain:gsub ('^//', ''); -- strip '//' from domain name if present; done here so we only have to do it once if not domain:match ('^[%w]') then -- first character must be letter or digit return false; end if domain:match ('^%a+:') then -- hack to detect things that look like s:Page:Title where Page: is namespace at Wikisource return false; end local patterns = { -- patterns that look like URLs '%f[%w][%w][%w%-]+[%w]%.%a%a+$', -- three or more character hostname.hostname or hostname.tld '%f[%w][%w][%w%-]+[%w]%.xn%-%-[%w]+$', -- internationalized domain name with ACE prefix '%f[%a][qxz]%.com$', -- assigned one character .com hostname (x.com times out 2015-12-10) '%f[%a][iq]%.net$', -- assigned one character .net hostname (q.net registered but not active 2015-12-10) '%f[%w][%w]%.%a%a$', -- one character hostname and ccTLD (2 chars) '%f[%w][%w][%w]%.%a%a+$', -- two character hostname and TLD '^%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?', -- IPv4 address '[%a%d]+%:?' -- IPv6 address } for _, pattern in ipairs (patterns) do -- loop through the patterns list if domain:match (pattern) then return true; -- if a match then we think that this thing that purports to be a URL is a URL end end for _, d in ipairs (cfg.single_letter_2nd_lvl_domains_t) do -- look for single letter second level domain names for these top level domains if domain:match ('%f[%w][%w]%.' .. d) then return true end end return false; -- no matches, we don't know what this thing is end --[[--------------------------< I S _ U R L >------------------------------------------------------------------ returns true if the scheme and domain parts of a URL appear to be a valid URL; else false. This function is the last step in the validation process. This function is separate because there are cases that are not covered by split_url(), for example is_parameter_ext_wikilink() which is looking for bracketted external wikilinks. ]] local function is_url (scheme, domain) if utilities.is_set (scheme) then -- if scheme is set check it and domain return is_scheme (scheme) and is_domain_name (domain); else return is_domain_name (domain); -- scheme not set when URL is protocol-relative end end --[[--------------------------< S P L I T _ U R L >------------------------------------------------------------ Split a URL into a scheme, authority indicator, and domain. First remove Fully Qualified Domain Name terminator (a dot following TLD) (if any) and any path(/), query(?) or fragment(#). If protocol-relative URL, return nil scheme and domain else return nil for both scheme and domain. When not protocol-relative, get scheme, authority indicator, and domain. If there is an authority indicator (one or more '/' characters immediately following the scheme's colon), make sure that there are only 2. Any URL that does not have news: scheme must have authority indicator (//). TODO: are there other common schemes like news: that don't use authority indicator? Strip off any port and path; ]] local function split_url (url_str) local scheme, authority, domain; url_str = url_str:gsub ('([%a%d])%.?[/%?#].*$', '%1'); -- strip FQDN terminator and path(/), query(?), fragment (#) (the capture prevents false replacement of '//') if url_str:match ('^//%S*') then -- if there is what appears to be a protocol-relative URL domain = url_str:match ('^//(%S*)') elseif url_str:match ('%S-:/*%S+') then -- if there is what appears to be a scheme, optional authority indicator, and domain name scheme, authority, domain = url_str:match ('(%S-:)(/*)(%S+)'); -- extract the scheme, authority indicator, and domain portions if utilities.is_set (authority) then authority = authority:gsub ('//', '', 1); -- replace place 1 pair of '/' with nothing; if utilities.is_set(authority) then -- if anything left (1 or 3+ '/' where authority should be) then return scheme; -- return scheme only making domain nil which will cause an error message end else if not scheme:match ('^news:') then -- except for news:..., MediaWiki won't link URLs that do not have authority indicator; TODO: a better way to do this test? return scheme; -- return scheme only making domain nil which will cause an error message end end domain = domain:gsub ('(%a):%d+', '%1'); -- strip port number if present end return scheme, domain; end --[[--------------------------< L I N K _ P A R A M _ O K >--------------------------------------------------- checks the content of |title-link=, |series-link=, |author-link=, etc. for properly formatted content: no wikilinks, no URLs Link parameters are to hold the title of a Wikipedia article, so none of the WP:TITLESPECIALCHARACTERS are allowed: # < > [ ] | { } _ except the underscore which is used as a space in wiki URLs and # which is used for section links returns false when the value contains any of these characters. When there are no illegal characters, this function returns TRUE if value DOES NOT appear to be a valid URL (the |<param>-link= parameter is ok); else false when value appears to be a valid URL (the |<param>-link= parameter is NOT ok). ]] local function link_param_ok (value) local scheme, domain; if value:find ('[<>%[%]|{}]') then -- if any prohibited characters return false; end scheme, domain = split_url (value); -- get scheme or nil and domain or nil from URL; return not is_url (scheme, domain); -- return true if value DOES NOT appear to be a valid URL end --[[--------------------------< L I N K _ T I T L E _ O K >--------------------------------------------------- Use link_param_ok() to validate |<param>-link= value and its matching |<title>= value. |<title>= may be wiki-linked but not when |<param>-link= has a value. This function emits an error message when that condition exists check <link> for inter-language interwiki-link prefix. prefix must be a MediaWiki-recognized language code and must begin with a colon. ]] local function link_title_ok (link, lorig, title, torig) local orig; if utilities.is_set (link) then -- don't bother if <param>-link doesn't have a value if not link_param_ok (link) then -- check |<param>-link= markup orig = lorig; -- identify the failing link parameter elseif title:find ('%[%[') then -- check |title= for wikilink markup orig = torig; -- identify the failing |title= parameter elseif link:match ('^%a+:') then -- if the link is what looks like an interwiki local prefix = link:match ('^(%a+):'):lower(); -- get the interwiki prefix if cfg.inter_wiki_map[prefix] then -- if prefix is in the map, must have preceding colon orig = lorig; -- flag as error end end end if utilities.is_set (orig) then link = ''; -- unset utilities.set_message ('err_bad_paramlink', orig); -- URL or wikilink in |title= with |title-link=; end return link; -- link if ok, empty string else end --[[--------------------------< C H E C K _ U R L >------------------------------------------------------------ Determines whether a URL string appears to be valid. First we test for space characters. If any are found, return false. Then split the URL into scheme and domain portions, or for protocol-relative (//example.com) URLs, just the domain. Use is_url() to validate the two portions of the URL. If both are valid, or for protocol-relative if domain is valid, return true, else false. Because it is different from a standard URL, and because this module used external_link() to make external links that work for standard and news: links, we validate newsgroup names here. The specification for a newsgroup name is at https://tools.ietf.org/html/rfc5536#section-3.1.4 ]] local function check_url( url_str ) if nil == url_str:match ("^%S+$") then -- if there are any spaces in |url=value it can't be a proper URL return false; end local scheme, domain; scheme, domain = split_url (url_str); -- get scheme or nil and domain or nil from URL; if 'news:' == scheme then -- special case for newsgroups return domain:match('^[%a%d%+%-_]+%.[%a%d%+%-_%.]*[%a%d%+%-_]$'); end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[=[-------------------------< I S _ P A R A M E T E R _ E X T _ W I K I L I N K >---------------------------- Return true if a parameter value has a string that begins and ends with square brackets [ and ] and the first non-space characters following the opening bracket appear to be a URL. The test will also find external wikilinks that use protocol-relative URLs. Also finds bare URLs. The frontier pattern prevents a match on interwiki-links which are similar to scheme:path URLs. The tests that find bracketed URLs are required because the parameters that call this test (currently |title=, |chapter=, |work=, and |publisher=) may have wikilinks and there are articles or redirects like '//Hus' so, while uncommon, |title=[[//Hus]] is possible as might be [[en://Hus]]. ]=] local function is_parameter_ext_wikilink (value) local scheme, domain; if value:match ('%f[%[]%[%a%S*:%S+.*%]') then -- if ext. wikilink with scheme and domain: [xxxx://yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(%a%S*:%S+).*%]')); elseif value:match ('%f[%[]%[//%S+.*%]') then -- if protocol-relative ext. wikilink: [//yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(//%S+).*%]')); elseif value:match ('%a%S*:%S+') then -- if bare URL with scheme; may have leading or trailing plain text scheme, domain = split_url (value:match ('(%a%S*:%S+)')); elseif value:match ('^//%S+') or value:match ('%s//%S+') then -- if protocol-relative bare URL: //yyyyy.zzz; authority indicator (//) must be be preceded nothing or by whitespace scheme, domain = split_url (value:match ('(//%S+)')); -- what is left should be the domain else return false; -- didn't find anything that is obviously a URL end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[[-------------------------< C H E C K _ F O R _ U R L >----------------------------------------------------- loop through a list of parameters and their values. Look at the value and if it has an external link, emit an error message. ]] local function check_for_url (parameter_list, error_list) for k, v in pairs (parameter_list) do -- for each parameter in the list if is_parameter_ext_wikilink (v) then -- look at the value; if there is a URL add an error message table.insert (error_list, utilities.wrap_style ('parameter', k)); end end end --[[--------------------------< S A F E _ F O R _ U R L >------------------------------------------------------ Escape sequences for content that will be used for URL descriptions ]] local function safe_for_url( str ) if str:match( "%[%[.-%]%]" ) ~= nil then utilities.set_message ('err_wikilink_in_url', {}); end return str:gsub( '[%[%]\n]', { ['['] = '&#91;', [']'] = '&#93;', ['\n'] = ' ' } ); end --[[--------------------------< E X T E R N A L _ L I N K >---------------------------------------------------- Format an external link with error checking ]] local function external_link (URL, label, source, access) local err_msg = ''; local domain; local path; local base_url; if not utilities.is_set (label) then label = URL; if utilities.is_set (source) then utilities.set_message ('err_bare_url_missing_title', {utilities.wrap_style ('parameter', source)}); else error (cfg.messages["bare_url_no_origin"]); -- programmer error; valid parameter name does not have matching meta-parameter end end if not check_url (URL) then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); end domain, path = URL:match ('^([/%.%-%+:%a%d]+)([/%?#].*)$'); -- split the URL into scheme plus domain and path if path then -- if there is a path portion path = path:gsub ('[%[%]]', {['['] = '%5b', [']'] = '%5d'}); -- replace '[' and ']' with their percent-encoded values URL = table.concat ({domain, path}); -- and reassemble end base_url = table.concat ({ "[", URL, " ", safe_for_url (label), "]" }); -- assemble a wiki-markup URL if utilities.is_set (access) then -- access level (subscription, registration, limited) base_url = utilities.substitute (cfg.presentation['ext-link-access-signal'], {cfg.presentation[access].class, cfg.presentation[access].title, base_url}); -- add the appropriate icon end return base_url; end --[[--------------------------< D E P R E C A T E D _ P A R A M E T E R >-------------------------------------- Categorize and emit an error message when the citation contains one or more deprecated parameters. The function includes the offending parameter name to the error message. Only one error message is emitted regardless of the number of deprecated parameters in the citation. added_deprecated_cat is a Boolean declared in page scope variables above ]] local function deprecated_parameter(name) if not added_deprecated_cat then added_deprecated_cat = true; -- note that we've added this category utilities.set_message ('err_deprecated_params', {name}); -- add error message end end --[=[-------------------------< K E R N _ Q U O T E S >-------------------------------------------------------- Apply kerning to open the space between the quote mark provided by the module and a leading or trailing quote mark contained in a |title= or |chapter= parameter's value. This function will positive kern either single or double quotes: "'Unkerned title with leading and trailing single quote marks'" " 'Kerned title with leading and trailing single quote marks' " (in real life the kerning isn't as wide as this example) Double single quotes (italic or bold wiki-markup) are not kerned. Replaces Unicode quote marks in plain text or in the label portion of a [[L|D]] style wikilink with typewriter quote marks regardless of the need for kerning. Unicode quote marks are not replaced in simple [[D]] wikilinks. Call this function for chapter titles, for website titles, etc.; not for book titles. ]=] local function kern_quotes (str) local cap = ''; local wl_type, label, link; wl_type, label, link = utilities.is_wikilink (str); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] if 1 == wl_type then -- [[D]] simple wikilink with or without quote marks if mw.ustring.match (str, '%[%[[\"“”\'‘’].+[\"“”\'‘’]%]%]') then -- leading and trailing quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); str = utilities.substitute (cfg.presentation['kern-right'], str); elseif mw.ustring.match (str, '%[%[[\"“”\'‘’].+%]%]') then -- leading quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); elseif mw.ustring.match (str, '%[%[.+[\"“”\'‘’]%]%]') then -- trailing quote marks str = utilities.substitute (cfg.presentation['kern-right'], str); end else -- plain text or [[L|D]]; text in label variable label = mw.ustring.gsub (label, '[“”]', '\"'); -- replace “” (U+201C & U+201D) with " (typewriter double quote mark) label = mw.ustring.gsub (label, '[‘’]', '\''); -- replace ‘’ (U+2018 & U+2019) with ' (typewriter single quote mark) cap = mw.ustring.match (label, "^([\"\'][^\'].+)"); -- match leading double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-left'], cap); end cap = mw.ustring.match (label, "^(.+[^\'][\"\'])$") -- match trailing double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-right'], cap); end if 2 == wl_type then str = utilities.make_wikilink (link, label); -- reassemble the wikilink else str = label; end end return str; end --[[--------------------------< F O R M A T _ S C R I P T _ V A L U E >---------------------------------------- |script-title= holds title parameters that are not written in Latin-based scripts: Chinese, Japanese, Arabic, Hebrew, etc. These scripts should not be italicized and may be written right-to-left. The value supplied by |script-title= is concatenated onto Title after Title has been wrapped in italic markup. Regardless of language, all values provided by |script-title= are wrapped in <bdi>...</bdi> tags to isolate RTL languages from the English left to right. |script-title= provides a unique feature. The value in |script-title= may be prefixed with a two-character ISO 639-1 language code and a colon: |script-title=ja:*** *** (where * represents a Japanese character) Spaces between the two-character code and the colon and the colon and the first script character are allowed: |script-title=ja : *** *** |script-title=ja: *** *** |script-title=ja :*** *** Spaces preceding the prefix are allowed: |script-title = ja:*** *** The prefix is checked for validity. If it is a valid ISO 639-1 language code, the lang attribute (lang="ja") is added to the <bdi> tag so that browsers can know the language the tag contains. This may help the browser render the script more correctly. If the prefix is invalid, the lang attribute is not added. At this time there is no error message for this condition. Supports |script-title=, |script-chapter=, |script-<periodical>= ]] local function format_script_value (script_value, script_param) local lang=''; -- initialize to empty string local name; if script_value:match('^%l%l%l?%s*:') then -- if first 3 or 4 non-space characters are script language prefix lang = script_value:match('^(%l%l%l?)%s*:%s*%S.*'); -- get the language prefix or nil if there is no script if not utilities.is_set (lang) then utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing title part']}); -- prefix without 'title'; add error message return ''; -- script_value was just the prefix so return empty string end -- if we get this far we have prefix and script name = cfg.lang_tag_remap[lang] or mw.language.fetchLanguageName( lang, cfg.this_wiki_code ); -- get language name so that we can use it to categorize if utilities.is_set (name) then -- is prefix a proper ISO 639-1 language code? script_value = script_value:gsub ('^%l+%s*:%s*', ''); -- strip prefix from script -- is prefix one of these language codes? if utilities.in_array (lang, cfg.script_lang_codes) then utilities.add_prop_cat ('script', {name, lang}) else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['unknown language code']}); -- unknown script-language; add error message end lang = ' lang="' .. lang .. '" '; -- convert prefix into a lang attribute else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['invalid language code']}); -- invalid language code; add error message lang = ''; -- invalid so set lang to empty string end else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing prefix']}); -- no language code prefix; add error message end script_value = utilities.substitute (cfg.presentation['bdi'], {lang, script_value}); -- isolate in case script is RTL return script_value; end --[[--------------------------< S C R I P T _ C O N C A T E N A T E >------------------------------------------ Initially for |title= and |script-title=, this function concatenates those two parameter values after the script value has been wrapped in <bdi> tags. ]] local function script_concatenate (title, script, script_param) if utilities.is_set (script) then script = format_script_value (script, script_param); -- <bdi> tags, lang attribute, categorization, etc.; returns empty string on error if utilities.is_set (script) then title = title .. ' ' .. script; -- concatenate title and script title end end return title; end --[[--------------------------< W R A P _ M S G >-------------------------------------------------------------- Applies additional message text to various parameter values. Supplied string is wrapped using a message_list configuration taking one argument. Supports lower case text for {{citation}} templates. Additional text taken from citation_config.messages - the reason this function is similar to but separate from wrap_style(). ]] local function wrap_msg (key, str, lower) if not utilities.is_set ( str ) then return ""; end if true == lower then local msg; msg = cfg.messages[key]:lower(); -- set the message to lower case before return utilities.substitute ( msg, str ); -- including template text else return utilities.substitute ( cfg.messages[key], str ); end end --[[----------------< W I K I S O U R C E _ U R L _ M A K E >------------------- Makes a Wikisource URL from Wikisource interwiki-link. Returns the URL and appropriate label; nil else. str is the value assigned to |chapter= (or aliases) or |title= or |title-link= ]] local function wikisource_url_make (str) local wl_type, D, L; local ws_url, ws_label; local wikisource_prefix = table.concat ({'https://', cfg.this_wiki_code, '.wikisource.org/wiki/'}); wl_type, D, L = utilities.is_wikilink (str); -- wl_type is 0 (not a wikilink), 1 (simple wikilink), 2 (complex wikilink) if 0 == wl_type then -- not a wikilink; might be from |title-link= str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 1 == wl_type then -- simple wikilink: [[Wikisource:ws article]] str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 2 == wl_type then -- non-so-simple wikilink: [[Wikisource:ws article|displayed text]] ([[L|D]]) str = L:match ('^[Ww]ikisource:(.+)') or L:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_label = D; -- get ws article name from display portion of interwiki link ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title without namespace from link portion of wikilink }); end end if ws_url then ws_url = mw.uri.encode (ws_url, 'WIKI'); -- make a usable URL ws_url = ws_url:gsub ('%%23', '#'); -- undo percent-encoding of fragment marker end return ws_url, ws_label, L or D; -- return proper URL or nil and a label or nil end --[[----------------< F O R M A T _ P E R I O D I C A L >----------------------- Format the three periodical parameters: |script-<periodical>=, |<periodical>=, and |trans-<periodical>= into a single Periodical meta-parameter. ]] local function format_periodical (script_periodical, script_periodical_source, periodical, trans_periodical) if not utilities.is_set (periodical) then periodical = ''; -- to be safe for concatenation else periodical = utilities.wrap_style ('italic-title', periodical); -- style end periodical = script_concatenate (periodical, script_periodical, script_periodical_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (trans_periodical) then trans_periodical = utilities.wrap_style ('trans-italic-title', trans_periodical); if utilities.is_set (periodical) then periodical = periodical .. ' ' .. trans_periodical; else -- here when trans-periodical without periodical or script-periodical periodical = trans_periodical; utilities.set_message ('err_trans_missing_title', {'periodical'}); end end return periodical; end --[[------------------< F O R M A T _ C H A P T E R _ T I T L E >--------------- Format the four chapter parameters: |script-chapter=, |chapter=, |trans-chapter=, and |chapter-url= into a single chapter meta- parameter (chapter_url_source used for error messages). ]] local function format_chapter_title (script_chapter, script_chapter_source, chapter, chapter_source, trans_chapter, trans_chapter_source, chapter_url, chapter_url_source, no_quotes, access) local ws_url, ws_label, L = wikisource_url_make (chapter); -- make a wikisource URL and label from a wikisource interwiki link if ws_url then ws_label = ws_label:gsub ('_', ' '); -- replace underscore separators with space characters chapter = ws_label; end if not utilities.is_set (chapter) then chapter = ''; -- to be safe for concatenation else if false == no_quotes then chapter = kern_quotes (chapter); -- if necessary, separate chapter title's leading and trailing quote marks from module provided quote marks chapter = utilities.wrap_style ('quoted-title', chapter); end end chapter = script_concatenate (chapter, script_chapter, script_chapter_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (chapter_url) then chapter = external_link (chapter_url, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate elseif ws_url then chapter = external_link (ws_url, chapter .. '&nbsp;', 'ws link in chapter'); -- adds bare_url_missing_title error if appropriate; space char to move icon away from chap text; TODO: better way to do this? chapter = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, chapter}); end if utilities.is_set (trans_chapter) then trans_chapter = utilities.wrap_style ('trans-quoted-title', trans_chapter); if utilities.is_set (chapter) then chapter = chapter .. ' ' .. trans_chapter; else -- here when trans_chapter without chapter or script-chapter chapter = trans_chapter; chapter_source = trans_chapter_source:match ('trans%-?(.+)'); -- when no chapter, get matching name from trans-<param> utilities.set_message ('err_trans_missing_title', {chapter_source}); end end return chapter; end --[[----------------< H A S _ I N V I S I B L E _ C H A R S >------------------- This function searches a parameter's value for non-printable or invisible characters. The search stops at the first match. This function will detect the visible replacement character when it is part of the Wikisource. Detects but ignores nowiki and math stripmarkers. Also detects other named stripmarkers (gallery, math, pre, ref) and identifies them with a slightly different error message. See also coins_cleanup(). Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker that was detected along with its position (or, for multi-byte characters, the position of its first byte) in the parameter value. ]] local function has_invisible_chars (param, v) local position = ''; -- position of invisible char or starting position of stripmarker local capture; -- used by stripmarker detection to hold name of the stripmarker local stripmarker; -- boolean set true when a stripmarker is found capture = string.match (v, '[%w%p ]*'); -- test for values that are simple ASCII text and bypass other tests if true if capture == v then -- if same there are no Unicode characters return; end for _, invisible_char in ipairs (cfg.invisible_chars) do local char_name = invisible_char[1]; -- the character or group name local pattern = invisible_char[2]; -- the pattern used to find it position, _, capture = mw.ustring.find (v, pattern); -- see if the parameter value contains characters that match the pattern if position and (cfg.invisible_defs.zwj == capture) then -- if we found a zero-width joiner character if mw.ustring.find (v, cfg.indic_script) then -- it's ok if one of the Indic scripts position = nil; -- unset position elseif cfg.emoji_t[mw.ustring.codepoint (v, position+1)] then -- is zwj followed by a character listed in emoji{}? position = nil; -- unset position end end if position then if 'nowiki' == capture or 'math' == capture or -- nowiki and math stripmarkers (not an error condition) ('templatestyles' == capture and utilities.in_array (param, {'id', 'quote'})) then -- templatestyles stripmarker allowed in these parameters stripmarker = true; -- set a flag elseif true == stripmarker and cfg.invisible_defs.del == capture then -- because stripmakers begin and end with the delete char, assume that we've found one end of a stripmarker position = nil; -- unset else local err_msg; if capture and not (cfg.invisible_defs.del == capture or cfg.invisible_defs.zwj == capture) then err_msg = capture .. ' ' .. char_name; else err_msg = char_name .. ' ' .. 'character'; end utilities.set_message ('err_invisible_char', {err_msg, utilities.wrap_style ('parameter', param), position}); -- add error message return; -- and done with this parameter end end end end --[[-------------------< A R G U M E N T _ W R A P P E R >---------------------- Argument wrapper. This function provides support for argument mapping defined in the configuration file so that multiple names can be transparently aliased to single internal variable. ]] local function argument_wrapper ( args ) local origin = {}; return setmetatable({ ORIGIN = function ( self, k ) local dummy = self[k]; -- force the variable to be loaded. return origin[k]; end }, { __index = function ( tbl, k ) if origin[k] ~= nil then return nil; end local args, list, v = args, cfg.aliases[k]; if type( list ) == 'table' then v, origin[k] = utilities.select_one ( args, list, 'err_redundant_parameters' ); if origin[k] == nil then origin[k] = ''; -- Empty string, not nil end elseif list ~= nil then v, origin[k] = args[list], list; else -- maybe let through instead of raising an error? -- v, origin[k] = args[k], k; error( cfg.messages['unknown_argument_map'] .. ': ' .. k); end -- Empty strings, not nil; if v == nil then v = ''; origin[k] = ''; end tbl = rawset( tbl, k, v ); return v; end, }); end --[[--------------------------< N O W R A P _ D A T E >------------------------- When date is YYYY-MM-DD format wrap in nowrap span: <span ...>YYYY-MM-DD</span>. When date is DD MMMM YYYY or is MMMM DD, YYYY then wrap in nowrap span: <span ...>DD MMMM</span> YYYY or <span ...>MMMM DD,</span> YYYY DOES NOT yet support MMMM YYYY or any of the date ranges. ]] local function nowrap_date (date) local cap = ''; local cap2 = ''; if date:match("^%d%d%d%d%-%d%d%-%d%d$") then date = utilities.substitute (cfg.presentation['nowrap1'], date); elseif date:match("^%a+%s*%d%d?,%s+%d%d%d%d$") or date:match ("^%d%d?%s*%a+%s+%d%d%d%d$") then cap, cap2 = string.match (date, "^(.*)%s+(%d%d%d%d)$"); date = utilities.substitute (cfg.presentation['nowrap2'], {cap, cap2}); end return date; end --[[--------------------------< S E T _ T I T L E T Y P E >--------------------- This function sets default title types (equivalent to the citation including |type=<default value>) for those templates that have defaults. Also handles the special case where it is desirable to omit the title type from the rendered citation (|type=none). ]] local function set_titletype (cite_class, title_type) if utilities.is_set (title_type) then if 'none' == cfg.keywords_xlate[title_type] then title_type = ''; -- if |type=none then type parameter not displayed end return title_type; -- if |type= has been set to any other value use that value end return cfg.title_types [cite_class] or ''; -- set template's default title type; else empty string for concatenation end --[[--------------------------< S A F E _ J O I N >----------------------------- Joins a sequence of strings together while checking for duplicate separation characters. ]] local function safe_join( tbl, duplicate_char ) local f = {}; -- create a function table appropriate to type of 'duplicate character' if 1 == #duplicate_char then -- for single byte ASCII characters use the string library functions f.gsub = string.gsub f.match = string.match f.sub = string.sub else -- for multi-byte characters use the ustring library functions f.gsub = mw.ustring.gsub f.match = mw.ustring.match f.sub = mw.ustring.sub end local str = ''; -- the output string local comp = ''; -- what does 'comp' mean? local end_chr = ''; local trim; for _, value in ipairs( tbl ) do if value == nil then value = ''; end if str == '' then -- if output string is empty str = value; -- assign value to it (first time through the loop) elseif value ~= '' then if value:sub(1, 1) == '<' then -- special case of values enclosed in spans and other markup. comp = value:gsub( "%b<>", "" ); -- remove HTML markup (<span>string</span> -> string) else comp = value; end -- typically duplicate_char is sepc if f.sub(comp, 1, 1) == duplicate_char then -- is first character same as duplicate_char? why test first character? -- Because individual string segments often (always?) begin with terminal punct for the -- preceding segment: 'First element' .. 'sepc next element' .. etc.? trim = false; end_chr = f.sub(str, -1, -1); -- get the last character of the output string -- str = str .. "<HERE(enchr=" .. end_chr .. ")" -- debug stuff? if end_chr == duplicate_char then -- if same as separator str = f.sub(str, 1, -2); -- remove it elseif end_chr == "'" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "''" then -- if last three chars of str are sepc'' str = f.sub(str, 1, -4) .. "''"; -- remove them and add back '' elseif f.sub(str, -5, -1) == duplicate_char .. "]]''" then -- if last five chars of str are sepc]]'' trim = true; -- why? why do this and next differently from previous? elseif f.sub(str, -4, -1) == duplicate_char .. "]''" then -- if last four chars of str are sepc]'' trim = true; -- same question end elseif end_chr == "]" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "]]" then -- if last three chars of str are sepc]] wikilink trim = true; elseif f.sub(str, -3, -1) == duplicate_char .. '"]' then -- if last three chars of str are sepc"] quoted external link trim = true; elseif f.sub(str, -2, -1) == duplicate_char .. "]" then -- if last two chars of str are sepc] external link trim = true; elseif f.sub(str, -4, -1) == duplicate_char .. "'']" then -- normal case when |url=something & |title=Title. trim = true; end elseif end_chr == " " then -- if last char of output string is a space if f.sub(str, -2, -1) == duplicate_char .. " " then -- if last two chars of str are <sepc><space> str = f.sub(str, 1, -3); -- remove them both end end if trim then if value ~= comp then -- value does not equal comp when value contains HTML markup local dup2 = duplicate_char; if f.match(dup2, "%A" ) then dup2 = "%" .. dup2; end -- if duplicate_char not a letter then escape it value = f.gsub(value, "(%b<>)" .. dup2, "%1", 1 ) -- remove duplicate_char if it follows HTML markup else value = f.sub(value, 2, -1 ); -- remove duplicate_char when it is first character end end end str = str .. value; -- add it to the output string end end return str; end --[[--------------------------< I S _ S U F F I X >----------------------------- returns true if suffix is properly formed Jr, Sr, or ordinal in the range 1–9. Puncutation not allowed. ]] local function is_suffix (suffix) if utilities.in_array (suffix, {'Jr', 'Sr', 'Jnr', 'Snr', '1st', '2nd', '3rd'}) or suffix:match ('^%dth$') then return true; end return false; end --[[--------------------< I S _ G O O D _ V A N C _ N A M E >------------------- For Vancouver style, author/editor names are supposed to be rendered in Latin (read ASCII) characters. When a name uses characters that contain diacritical marks, those characters are to be converted to the corresponding Latin character. When a name is written using a non-Latin alphabet or logogram, that name is to be transliterated into Latin characters. The module doesn't do this so editors may/must. This test allows |first= and |last= names to contain any of the letters defined in the four Unicode Latin character sets [http://www.unicode.org/charts/PDF/U0000.pdf C0 Controls and Basic Latin] 0041–005A, 0061–007A [http://www.unicode.org/charts/PDF/U0080.pdf C1 Controls and Latin-1 Supplement] 00C0–00D6, 00D8–00F6, 00F8–00FF [http://www.unicode.org/charts/PDF/U0100.pdf Latin Extended-A] 0100–017F [http://www.unicode.org/charts/PDF/U0180.pdf Latin Extended-B] 0180–01BF, 01C4–024F |lastn= also allowed to contain hyphens, spaces, and apostrophes. (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) |firstn= also allowed to contain hyphens, spaces, apostrophes, and periods This original test: if nil == mw.ustring.find (last, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%'%.]+[2-6%a]*$") then was written outside of the code editor and pasted here because the code editor gets confused between character insertion point and cursor position. The test has been rewritten to use decimal character escape sequence for the individual bytes of the Unicode characters so that it is not necessary to use an external editor to maintain this code. \195\128-\195\150 – À-Ö (U+00C0–U+00D6 – C0 controls) \195\152-\195\182 – Ø-ö (U+00D8-U+00F6 – C0 controls) \195\184-\198\191 – ø-ƿ (U+00F8-U+01BF – C0 controls, Latin extended A & B) \199\132-\201\143 – DŽ-ɏ (U+01C4-U+024F – Latin extended B) ]] local function is_good_vanc_name (last, first, suffix, position) if not suffix then if first:find ('[,%s]') then -- when there is a space or comma, might be first name/initials + generational suffix first = first:match ('(.-)[,%s]+'); -- get name/initials suffix = first:match ('[,%s]+(.+)$'); -- get generational suffix end end if utilities.is_set (suffix) then if not is_suffix (suffix) then add_vanc_error (cfg.err_msg_supl.suffix, position); return false; -- not a name with an appropriate suffix end end if nil == mw.ustring.find (last, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%'%.]*$") then add_vanc_error (cfg.err_msg_supl['non-Latin char'], position); return false; -- not a string of Latin characters; Vancouver requires Romanization end; return true; end --[[--------------------------< R E D U C E _ T O _ I N I T I A L S >------------------------------------------ Attempts to convert names to initials in support of |name-list-style=vanc. Names in |firstn= may be separated by spaces or hyphens, or for initials, a period. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35062/. Vancouver style requires family rank designations (Jr, II, III, etc.) to be rendered as Jr, 2nd, 3rd, etc. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35085/. This code only accepts and understands generational suffix in the Vancouver format because Roman numerals look like, and can be mistaken for, initials. This function uses ustring functions because firstname initials may be any of the Unicode Latin characters accepted by is_good_vanc_name (). ]] local function reduce_to_initials (first, position) if first:find (',', 1, true) then return first; -- commas not allowed; abandon end local name, suffix = mw.ustring.match (first, "^(%u+) ([%dJS][%drndth]+)$"); if not name then -- if not initials and a suffix name = mw.ustring.match (first, "^(%u+)$"); -- is it just initials? end if name then -- if first is initials with or without suffix if 3 > mw.ustring.len (name) then -- if one or two initials if suffix then -- if there is a suffix if is_suffix (suffix) then -- is it legitimate? return first; -- one or two initials and a valid suffix so nothing to do else add_vanc_error (cfg.err_msg_supl.suffix, position); -- one or two initials with invalid suffix so error message return first; -- and return first unmolested end else return first; -- one or two initials without suffix; nothing to do end end end -- if here then name has 3 or more uppercase letters so treat them as a word local initials_t, names_t = {}, {}; -- tables to hold name parts and initials local i = 1; -- counter for number of initials names_t = mw.text.split (first, '[%s%-]+'); -- split into a sequence of names and possible suffix while names_t[i] do -- loop through the sequence if 1 < i and names_t[i]:match ('[%dJS][%drndth]+%.?$') then -- if not the first name, and looks like a suffix (may have trailing dot) names_t[i] = names_t[i]:gsub ('%.', ''); -- remove terminal dot if present if is_suffix (names_t[i]) then -- if a legitimate suffix table.insert (initials_t, ' ' .. names_t[i]); -- add a separator space, insert at end of initials sequence break; -- and done because suffix must fall at the end of a name end -- no error message if not a suffix; possibly because of Romanization end if 3 > i then table.insert (initials_t, mw.ustring.sub (names_t[i], 1, 1)); -- insert the initial at end of initials sequence end i = i + 1; -- bump the counter end return table.concat (initials_t); -- Vancouver format does not include spaces. end --[[--------------------------< I N T E R W I K I _ P R E F I X E N _ G E T >---------------------------------- extract interwiki prefixen from <value>. Returns two one or two values: false – no prefixen nil – prefix exists but not recognized project prefix, language prefix – when value has either of: :<project>:<language>:<article> :<language>:<project>:<article> project prefix, nil – when <value> has only a known single-letter prefix nil, language prefix – when <value> has only a known language prefix accepts single-letter project prefixen: 'd' (wikidata), 's' (wikisource), and 'w' (wikipedia) prefixes; at this writing, the other single-letter prefixen (b (wikibook), c (commons), m (meta), n (wikinews), q (wikiquote), and v (wikiversity)) are not supported. ]] local function interwiki_prefixen_get (value, is_link) if not value:find (':%l+:') then -- if no prefix return false; -- abandon; boolean here to distinguish from nil fail returns later end local prefix_patterns_linked_t = { -- sequence of valid interwiki and inter project prefixen '^%[%[:([dsw]):(%l%l+):', -- wikilinked; project and language prefixes '^%[%[:(%l%l+):([dsw]):', -- wikilinked; language and project prefixes '^%[%[:([dsw]):', -- wikilinked; project prefix '^%[%[:(%l%l+):', -- wikilinked; language prefix } local prefix_patterns_unlinked_t = { -- sequence of valid interwiki and inter project prefixen '^:([dsw]):(%l%l+):', -- project and language prefixes '^:(%l%l+):([dsw]):', -- language and project prefixes '^:([dsw]):', -- project prefix '^:(%l%l+):', -- language prefix } local cap1, cap2; for _, pattern in ipairs ((is_link and prefix_patterns_linked_t) or prefix_patterns_unlinked_t) do cap1, cap2 = value:match (pattern); if cap1 then break; -- found a match so stop looking end end if cap1 and cap2 then -- when both then :project:language: or :language:project: (both forms allowed) if 1 == #cap1 then -- length == 1 then :project:language: if cfg.inter_wiki_map[cap2] then -- is language prefix in the interwiki map? return cap1, cap2; -- return interwiki project and interwiki language end else -- here when :language:project: if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return cap2, cap1; -- return interwiki project and interwiki language end end return nil; -- unknown interwiki language elseif not (cap1 or cap2) then -- both are nil? return nil; -- we got something that looks like a project prefix but isn't; return fail elseif 1 == #cap1 then -- here when one capture return cap1, nil; -- length is 1 so return project, nil language else -- here when one capture and its length it more than 1 if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return nil, cap1; -- return nil project, language end end end --[[--------------------------< L I S T _ P E O P L E >-------------------------- Formats a list of people (authors, contributors, editors, interviewers, translators) names in the list will be linked when |<name>-link= has a value |<name>-mask- does NOT have a value; masked names are presumed to have been rendered previously so should have been linked there when |<name>-mask=0, the associated name is not rendered ]] local function list_people (control, people, etal) local sep; local namesep; local format = control.format; local maximum = control.maximum; local name_list = {}; if 'vanc' == format then -- Vancouver-like name styling? sep = cfg.presentation['sep_nl_vanc']; -- name-list separator between names is a comma namesep = cfg.presentation['sep_name_vanc']; -- last/first separator is a space else sep = cfg.presentation['sep_nl']; -- name-list separator between names is a semicolon namesep = cfg.presentation['sep_name']; -- last/first separator is <comma><space> end if sep:sub (-1, -1) ~= " " then sep = sep .. " " end if utilities.is_set (maximum) and maximum < 1 then return "", 0; end -- returned 0 is for EditorCount; not used for other names for i, person in ipairs (people) do if utilities.is_set (person.last) then local mask = person.mask; local one; local sep_one = sep; if utilities.is_set (maximum) and i > maximum then etal = true; break; end if mask then local n = tonumber (mask); -- convert to a number if it can be converted; nil else if n then one = 0 ~= n and string.rep("&mdash;", n) or nil; -- make a string of (n > 0) mdashes, nil else, to replace name person.link = nil; -- don't create link to name if name is replaces with mdash string or has been set nil else one = mask; -- replace name with mask text (must include name-list separator) sep_one = " "; -- modify name-list separator end else one = person.last; -- get surname local first = person.first -- get given name if utilities.is_set (first) then if ("vanc" == format) then -- if Vancouver format one = one:gsub ('%.', ''); -- remove periods from surnames (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) if not person.corporate and is_good_vanc_name (one, first, nil, i) then -- and name is all Latin characters; corporate authors not tested first = reduce_to_initials (first, i); -- attempt to convert first name(s) to initials end end one = one .. namesep .. first; end end if utilities.is_set (person.link) then one = utilities.make_wikilink (person.link, one); -- link author/editor end if one then -- if <one> has a value (name, mdash replacement, or mask text replacement) local proj, tag = interwiki_prefixen_get (one, true); -- get the interwiki prefixen if present if 'w' == proj and ('Wikipedia' == mw.site.namespaces.Project['name']) then proj = nil; -- for stuff like :w:de:<article>, :w is unnecessary TODO: maint cat? end if proj then local proj_name = ({['d'] = 'Wikidata', ['s'] = 'Wikisource', ['w'] = 'Wikipedia'})[proj]; -- :w (wikipedia) for linking from a non-wikipedia project if proj_name then one = one .. utilities.wrap_style ('interproj', proj_name); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interproj-linked-name', proj); -- categorize it; <proj> is sort key tag = nil; -- unset; don't do both project and language end end if tag == cfg.this_wiki_code then tag = nil; -- stuff like :en:<article> at en.wiki is pointless TODO: maint cat? end if tag then local lang = cfg.lang_tag_remap[tag] or cfg.mw_languages_by_tag_t[tag]; if lang then -- error messaging done in extract_names() where we know parameter names one = one .. utilities.wrap_style ('interwiki', lang); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interwiki-linked-name', tag); -- categorize it; <tag> is sort key end end table.insert (name_list, one); -- add it to the list of names table.insert (name_list, sep_one); -- add the proper name-list separator end end end local count = #name_list / 2; -- (number of names + number of separators) divided by 2 if 0 < count then if 1 < count and not etal then if 'amp' == format then name_list[#name_list-2] = " & "; -- replace last separator with ampersand text elseif 'and' == format then if 2 == count then name_list[#name_list-2] = cfg.presentation.sep_nl_and; -- replace last separator with 'and' text else name_list[#name_list-2] = cfg.presentation.sep_nl_end; -- replace last separator with '(sep) and' text end end end name_list[#name_list] = nil; -- erase the last separator end local result = table.concat (name_list); -- construct list if etal and utilities.is_set (result) then -- etal may be set by |display-authors=etal but we might not have a last-first list result = result .. sep .. cfg.messages['et al']; -- we've got a last-first list and etal so add et al. end return result, count; -- return name-list string and count of number of names (count used for editor names only) end --[[--------------------< M A K E _ C I T E R E F _ I D >----------------------- Generates a CITEREF anchor ID if we have at least one name or a date. Otherwise returns an empty string. namelist is one of the contributor-, author-, or editor-name lists chosen in that order. year is Year or anchor_year. ]] local function make_citeref_id (namelist, year) local names={}; -- a table for the one to four names and year for i,v in ipairs (namelist) do -- loop through the list and take up to the first four last names names[i] = v.last if i == 4 then break end -- if four then done end table.insert (names, year); -- add the year at the end local id = table.concat(names); -- concatenate names and year for CITEREF id if utilities.is_set (id) then -- if concatenation is not an empty string return "CITEREF" .. id; -- add the CITEREF portion else return ''; -- return an empty string; no reason to include CITEREF id in this citation end end --[[--------------------------< C I T E _ C L A S S _A T T R I B U T E _M A K E >------------------------------ construct <cite> tag class attribute for this citation. <cite_class> – config.CitationClass from calling template <mode> – value from |mode= parameter ]] local function cite_class_attribute_make (cite_class, mode) local class_t = {}; table.insert (class_t, 'citation'); -- required for blue highlight if 'citation' ~= cite_class then table.insert (class_t, cite_class); -- identify this template for user css table.insert (class_t, utilities.is_set (mode) and mode or 'cs1'); -- identify the citation style for user css or javascript else table.insert (class_t, utilities.is_set (mode) and mode or 'cs2'); -- identify the citation style for user css or javascript end for _, prop_key in ipairs (z.prop_keys_t) do table.insert (class_t, prop_key); -- identify various properties for user css or javascript end return table.concat (class_t, ' '); -- make a big string and done end --[[---------------------< N A M E _ H A S _ E T A L >-------------------------- Evaluates the content of name parameters (author, editor, etc.) for variations on the theme of et al. If found, the et al. is removed, a flag is set to true and the function returns the modified name and the flag. This function never sets the flag to false but returns its previous state because it may have been set by previous passes through this function or by the associated |display-<names>=etal parameter ]] local function name_has_etal (name, etal, nocat, param) if utilities.is_set (name) then -- name can be nil in which case just return local patterns = cfg.et_al_patterns; -- get patterns from configuration for _, pattern in ipairs (patterns) do -- loop through all of the patterns if name:match (pattern) then -- if this 'et al' pattern is found in name name = name:gsub (pattern, ''); -- remove the offending text etal = true; -- set flag (may have been set previously here or by |display-<names>=etal) if not nocat then -- no categorization for |vauthors= utilities.set_message ('err_etal', {param}); -- and set an error if not added end end end end return name, etal; end --[[---------------------< N A M E _ I S _ N U M E R I C >---------------------- Add an error message and category when <name> parameter value does not contain letters. Add a maintenance category when <name> parameter value has numeric characters mixed with characters that are not numeric characters; could be letters and/or punctuation characters. This function will only emit one error and one maint message for the current template. Does not emit both error and maint messages/categories for the same parameter value. returns nothing ]] local function name_is_numeric (name, name_alias, list_name) local patterns = { '^%D+%d', -- <name> must have digits preceded by other characters '^%D*%d+%D+', -- <name> must have digits followed by other characters } if not added_numeric_name_errs and mw.ustring.match (name, '^[%A]+$') then -- if we have not already set an error message and <name> does not have any alpha characters utilities.set_message ('err_numeric_names', name_alias); -- add an error message added_numeric_name_errs = true; -- set the flag so we emit only one error message return; -- when here no point in further testing; abandon end if not added_numeric_name_maint then -- if we have already set a maint message for _, pattern in ipairs (patterns) do -- spin through list of patterns if mw.ustring.match (name, pattern) then -- digits preceded or followed by anything but digits; %D+ includes punctuation utilities.set_message ('maint_numeric_names', cfg.special_case_translation [list_name]); -- add a maint cat for this template added_numeric_name_maint = true; -- set the flag so we emit only one maint message return; -- when here no point in further testing; abandon end end end end --[[-----------------< N A M E _ H A S _ M U L T _ N A M E S >------------------ Evaluates the content of last/surname (authors etc.) parameters for multiple names. Multiple names are indicated if there is more than one comma or any "unescaped" semicolons. Escaped semicolons are ones used as part of selected HTML entities. If the condition is met, the function adds the multiple name maintenance category. Same test for first except that commas should not appear in given names (MOS:JR says that the generational suffix does not take a separator character). Titles, degrees, postnominals, affiliations, all normally comma separated don't belong in a citation. <name> – name parameter value <list_name> – AuthorList, EditorList, etc <limit> – number of allowed commas; 1 (default) for surnames; 0 for given names returns nothing ]] local function name_has_mult_names (name, list_name, limit) local _, commas, semicolons, nbsps; limit = limit and limit or 1; if utilities.is_set (name) then _, commas = name:gsub (',', ''); -- count the number of commas _, semicolons = name:gsub (';', ''); -- count the number of semicolons -- nbsps probably should be its own separate count rather than merged in -- some way with semicolons because Lua patterns do not support the -- grouping operator that regex does, which means there is no way to add -- more entities to escape except by adding more counts with the new -- entities _, nbsps = name:gsub ('&nbsp;',''); -- count nbsps -- There is exactly 1 semicolon per &nbsp; entity, so subtract nbsps -- from semicolons to 'escape' them. If additional entities are added, -- they also can be subtracted. if limit < commas or 0 < (semicolons - nbsps) then utilities.set_message ('maint_mult_names', cfg.special_case_translation [list_name]); -- add a maint message end end end --[=[-------------------------< I S _ G E N E R I C >---------------------------------------------------------- Compares values assigned to various parameters according to the string provided as <item> in the function call. <item> can have on of two values: 'generic_names' – for name-holding parameters: |last=, |first=, |editor-last=, etc 'generic_titles' – for |title= There are two types of generic tests. The 'accept' tests look for a pattern that should not be rejected by the 'reject' test. For example, |author=[[John Smith (author)|Smith, John]] would be rejected by the 'author' reject test. But piped wikilinks with 'author' disambiguation should not be rejected so the 'accept' test prevents that from happening. Accept tests are always performed before reject tests. Each of the 'accept' and 'reject' sequence tables hold tables for en.wiki (['en']) and local.wiki (['local']) that each can hold a test sequence table The sequence table holds, at index [1], a test pattern, and, at index [2], a boolean control value. The control value tells string.find() or mw.ustring.find() to do plain-text search (true) or a pattern search (false). The intent of all this complexity is to make these searches as fast as possible so that we don't run out of processing time on very large articles. Returns true when a reject test finds the pattern or string false when an accept test finds the pattern or string nil else ]=] local function is_generic (item, value, wiki) local test_val; local str_lower = { -- use string.lower() for en.wiki (['en']) and use mw.ustring.lower() or local.wiki (['local']) ['en'] = string.lower, ['local'] = mw.ustring.lower, } local str_find = { -- use string.find() for en.wiki (['en']) and use mw.ustring.find() or local.wiki (['local']) ['en'] = string.find, ['local'] = mw.ustring.find, } local function test (val, test_t, wiki) -- local function to do the testing; <wiki> selects lower() and find() functions val = test_t[2] and str_lower[wiki](value) or val; -- when <test_t[2]> set to 'true', plaintext search using lowercase value return str_find[wiki] (val, test_t[1], 1, test_t[2]); -- return nil when not found or matched end local test_types_t = {'accept', 'reject'}; -- test accept patterns first, then reject patterns local wikis_t = {'en', 'local'}; -- do tests for each of these keys; en.wiki first, local.wiki second for _, test_type in ipairs (test_types_t) do -- for each test type for _, generic_value in pairs (cfg.special_case_translation[item][test_type]) do -- spin through the list of generic value fragments to accept or reject for _, wiki in ipairs (wikis_t) do if generic_value[wiki] then if test (value, generic_value[wiki], wiki) then -- go do the test return ('reject' == test_type); -- param value rejected, return true; false else end end end end end end --[[--------------------------< N A M E _ I S _ G E N E R I C >------------------------------------------------ calls is_generic() to determine if <name> is a 'generic name' listed in cfg.generic_names; <name_alias> is the parameter name used in error messaging ]] local function name_is_generic (name, name_alias) if not added_generic_name_errs and is_generic ('generic_names', name) then utilities.set_message ('err_generic_name', name_alias); -- set an error message added_generic_name_errs = true; end end --[[--------------------------< N A M E _ C H E C K S >-------------------------------------------------------- This function calls various name checking functions used to validate the content of the various name-holding parameters. ]] local function name_checks (last, first, list_name, last_alias, first_alias) local accept_name; if utilities.is_set (last) then last, accept_name = utilities.has_accept_as_written (last); -- remove accept-this-as-written markup when it wraps all of <last> if not accept_name then -- <last> not wrapped in accept-as-written markup name_has_mult_names (last, list_name); -- check for multiple names in the parameter name_is_numeric (last, last_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (last, last_alias); -- check for names found in the generic names list end end if utilities.is_set (first) then first, accept_name = utilities.has_accept_as_written (first); -- remove accept-this-as-written markup when it wraps all of <first> if not accept_name then -- <first> not wrapped in accept-as-written markup name_has_mult_names (first, list_name, 0); -- check for multiple names in the parameter; 0 is number of allowed commas in a given name name_is_numeric (first, first_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (first, first_alias); -- check for names found in the generic names list end local wl_type, D = utilities.is_wikilink (first); if 0 ~= wl_type then first = D; utilities.set_message ('err_bad_paramlink', first_alias); end end return last, first; -- done end --[[----------------------< E X T R A C T _ N A M E S >------------------------- Gets name list from the input arguments Searches through args in sequential order to find |lastn= and |firstn= parameters (or their aliases), and their matching link and mask parameters. Stops searching when both |lastn= and |firstn= are not found in args after two sequential attempts: found |last1=, |last2=, and |last3= but doesn't find |last4= and |last5= then the search is done. This function emits an error message when there is a |firstn= without a matching |lastn=. When there are 'holes' in the list of last names, |last1= and |last3= are present but |last2= is missing, an error message is emitted. |lastn= is not required to have a matching |firstn=. When an author or editor parameter contains some form of 'et al.', the 'et al.' is stripped from the parameter and a flag (etal) returned that will cause list_people() to add the static 'et al.' text from Module:Citation/CS1/Configuration. This keeps 'et al.' out of the template's metadata. When this occurs, an error is emitted. ]] local function extract_names(args, list_name) local names = {}; -- table of names local last; -- individual name components local first; local link; local mask; local i = 1; -- loop counter/indexer local n = 1; -- output table indexer local count = 0; -- used to count the number of times we haven't found a |last= (or alias for authors, |editor-last or alias for editors) local etal = false; -- return value set to true when we find some form of et al. in an author parameter local last_alias, first_alias, link_alias; -- selected parameter aliases used in error messaging while true do last, last_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'err_redundant_parameters', i ); -- search through args for name components beginning at 1 first, first_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'err_redundant_parameters', i ); link, link_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ); mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); if last then -- error check |lastn= alias for unknown interwiki link prefix; done here because this is where we have the parameter name local project, language = interwiki_prefixen_get (last, true); -- true because we expect interwiki links in |lastn= to be wikilinked if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', last_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? last = utilities.remove_wiki_link (last); -- remove wikilink markup; show display value only end end if link then -- error check |linkn= alias for unknown interwiki link prefix local project, language = interwiki_prefixen_get (link, false); -- false because wiki links in |author-linkn= is an error if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', link_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? link = nil; -- unset so we don't link link_alias = nil; end end last, etal = name_has_etal (last, etal, false, last_alias); -- find and remove variations on et al. first, etal = name_has_etal (first, etal, false, first_alias); -- find and remove variations on et al. last, first = name_checks (last, first, list_name, last_alias, first_alias); -- multiple names, extraneous annotation, etc. checks if first and not last then -- if there is a firstn without a matching lastn local alias = first_alias:find ('given', 1, true) and 'given' or 'first'; -- get first or given form of the alias utilities.set_message ('err_first_missing_last', { first_alias, -- param name of alias missing its mate first_alias:gsub (alias, {['first'] = 'last', ['given'] = 'surname'}), -- make param name appropriate to the alias form }); -- add this error message elseif not first and not last then -- if both firstn and lastn aren't found, are we done? count = count + 1; -- number of times we haven't found last and first if 2 <= count then -- two missing names and we give up break; -- normal exit or there is a two-name hole in the list; can't tell which end else -- we have last with or without a first local result; link = link_title_ok (link, link_alias, last, last_alias); -- check for improper wiki-markup if first then link = link_title_ok (link, link_alias, first, first_alias); -- check for improper wiki-markup end names[n] = {last = last, first = first, link = link, mask = mask, corporate = false}; -- add this name to our names list (corporate for |vauthors= only) n = n + 1; -- point to next location in the names table if 1 == count then -- if the previous name was missing utilities.set_message ('err_missing_name', {list_name:match ("(%w+)List"):lower(), i - 1}); -- add this error message end count = 0; -- reset the counter, we're looking for two consecutive missing names end i = i + 1; -- point to next args location end return names, etal; -- all done, return our list of names and the etal flag end --[[--------------------------< N A M E _ T A G _ G E T >------------------------------------------------------ attempt to decode |language=<lang_param> and return language name and matching tag; nil else. This function looks for: <lang_param> as a tag in cfg.lang_tag_remap{} <lang_param> as a name in cfg.lang_name_remap{} <lang_param> as a name in cfg.mw_languages_by_name_t <lang_param> as a tag in cfg.mw_languages_by_tag_t when those fail, presume that <lang_param> is an IETF-like tag that MediaWiki does not recognize. Strip all script, region, variant, whatever subtags from <lang_param> to leave just a two or three character language tag and look for the new <lang_param> in cfg.mw_languages_by_tag_t{} on success, returns name (in properly capitalized form) and matching tag (in lowercase); on failure returns nil ]] local function name_tag_get (lang_param) local lang_param_lc = mw.ustring.lower (lang_param); -- use lowercase as an index into the various tables local name; local tag; name = cfg.lang_tag_remap[lang_param_lc]; -- assume <lang_param_lc> is a tag; attempt to get remapped language name if name then -- when <name>, <lang_param> is a tag for a remapped language name if cfg.lang_name_remap[name:lower()][2] ~= lang_param_lc then utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added return name, cfg.lang_name_remap[name:lower()][2]; -- so return name and tag from lang_name_remap[name]; special case to xlate sr-ec and sr-el to sr-cyrl and sr-latn end return name, lang_param_lc; -- so return <name> from remap and <lang_param_lc> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- still assuming that <lang_param_lc> is a tag; strip script, region, variant subtags name = cfg.lang_tag_remap[tag]; -- attempt to get remapped language name with language subtag only if name then -- when <name>, <tag> is a tag for a remapped language name return name, tag; -- so return <name> from remap and <tag> end if cfg.lang_name_remap[lang_param_lc] then -- not a remapped tag, assume <lang_param_lc> is a name; attempt to get remapped language tag return cfg.lang_name_remap[lang_param_lc][1], cfg.lang_name_remap[lang_param_lc][2]; -- for this <lang_param_lc>, return a (possibly) new name and appropriate tag end name = cfg.mw_languages_by_tag_t[lang_param_lc]; -- assume that <lang_param_lc> is a tag; attempt to get its matching language name if name then return name, lang_param_lc; -- <lang_param_lc> is a tag so return it and <name> end tag = cfg.mw_languages_by_name_t[lang_param_lc]; -- assume that <lang_param_lc> is a language name; attempt to get its matching tag if tag then return cfg.mw_languages_by_tag_t[tag], tag; -- <lang_param_lc> is a name so return the name from the table and <tag> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- is <lang_param_lc> an IETF-like tag that MediaWiki doesn't recognize? <tag> gets the language subtag; nil else if tag then name = cfg.mw_languages_by_tag_t[tag]; -- attempt to get a language name using the shortened <tag> if name then return name, tag; -- <lang_param_lc> is an unrecognized IETF-like tag so return <name> and language subtag end end end --[[-------------------< L A N G U A G E _ P A R A M E T E R >------------------ Gets language name from a provided two- or three-character ISO 639 code. If a code is recognized by MediaWiki, use the returned name; if not, then use the value that was provided with the language parameter. When |language= contains a recognized language (either code or name), the page is assigned to the category for that code: Category:Norwegian-language sources (no). For valid three-character code languages, the page is assigned to the single category for '639-2' codes: Category:CS1 ISO 639-2 language sources. Languages that are the same as the local wiki are not categorized. MediaWiki does not recognize three-character equivalents of two-character codes: code 'ar' is recognized but code 'ara' is not. This function supports multiple languages in the form |language=nb, French, th where the language names or codes are separated from each other by commas with optional space characters. ]] local function language_parameter (lang) local tag; -- some form of IETF-like language tag; language subtag with optional region, sript, vatiant, etc subtags local lang_subtag; -- ve populates |language= with mostly unecessary region subtags the MediaWiki does not recognize; this is the base language subtag local name; -- the language name local language_list = {}; -- table of language names to be rendered local names_t = {}; -- table made from the value assigned to |language= local this_wiki_name = mw.language.fetchLanguageName (cfg.this_wiki_code, cfg.this_wiki_code); -- get this wiki's language name names_t = mw.text.split (lang, '%s*,%s*'); -- names should be a comma separated list for _, lang in ipairs (names_t) do -- reuse lang here because we don't yet know if lang is a language name or a language tag name, tag = name_tag_get (lang); -- attempt to get name/tag pair for <lang>; <name> has proper capitalization; <tag> is lowercase if utilities.is_set (tag) then lang_subtag = tag:gsub ('^(%a%a%a?)%-.*', '%1'); -- for categorization, strip any IETF-like tags from language tag if cfg.this_wiki_code ~= lang_subtag then -- when the language is not the same as this wiki's language if 2 == lang_subtag:len() then -- and is a two-character tag utilities.add_prop_cat ('foreign-lang-source', {name, tag}, lang_subtag); -- categorize it; tag appended to allow for multiple language categorization else -- or is a recognized language (but has a three-character tag) utilities.add_prop_cat ('foreign-lang-source-2', {lang_subtag}, lang_subtag); -- categorize it differently TODO: support multiple three-character tag categories per cs1|2 template? end elseif cfg.local_lang_cat_enable then -- when the language and this wiki's language are the same and categorization is enabled utilities.add_prop_cat ('local-lang-source', {name, lang_subtag}); -- categorize it end else name = lang; -- return whatever <lang> has so that we show something utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added end table.insert (language_list, name); name = ''; -- so we can reuse it end name = utilities.make_sep_list (#language_list, language_list); if (1 == #language_list) and (lang_subtag == cfg.this_wiki_code) then -- when only one language, find lang name in this wiki lang name; for |language=en-us, 'English' in 'American English' return ''; -- if one language and that language is this wiki's return an empty string (no annotation) end return (" " .. wrap_msg ('language', name)); -- otherwise wrap with '(in ...)' --[[ TODO: should only return blank or name rather than full list so we can clean up the bunched parenthetical elements Language, Type, Format ]] end --[[-----------------------< S E T _ C S _ S T Y L E >-------------------------- Gets the default CS style configuration for the given mode. Returns default separator and either postscript as passed in or the default. In CS1, the default postscript and separator are '.'. In CS2, the default postscript is the empty string and the default separator is ','. ]] local function set_cs_style (postscript, mode) if utilities.is_set(postscript) then -- emit a maintenance message if user postscript is the default cs1 postscript -- we catch the opposite case for cs2 in set_style if mode == 'cs1' and postscript == cfg.presentation['ps_' .. mode] then utilities.set_message ('maint_postscript'); end else postscript = cfg.presentation['ps_' .. mode]; end return cfg.presentation['sep_' .. mode], postscript; end --[[--------------------------< S E T _ S T Y L E >----------------------------- Sets the separator and postscript styles. Checks the |mode= first and the #invoke CitationClass second. Removes the postscript if postscript == none. ]] local function set_style (mode, postscript, cite_class) local sep; if 'cs2' == mode then sep, postscript = set_cs_style (postscript, 'cs2'); elseif 'cs1' == mode then sep, postscript = set_cs_style (postscript, 'cs1'); elseif 'citation' == cite_class then sep, postscript = set_cs_style (postscript, 'cs2'); else sep, postscript = set_cs_style (postscript, 'cs1'); end if cfg.keywords_xlate[postscript:lower()] == 'none' then -- emit a maintenance message if user postscript is the default cs2 postscript -- we catch the opposite case for cs1 in set_cs_style if 'cs2' == mode or ('cs1' ~= mode and 'citation' == cite_class) then -- {{citation |title=Title |mode=cs1 |postscript=none}} should not emit maint message utilities.set_message ('maint_postscript'); end postscript = ''; end return sep, postscript end --[=[-------------------------< I S _ P D F >----------------------------------- Determines if a URL has the file extension that is one of the PDF file extensions used by [[MediaWiki:Common.css]] when applying the PDF icon to external links. returns true if file extension is one of the recognized extensions, else false ]=] local function is_pdf (url) return url:match ('%.pdf$') or url:match ('%.PDF$') or url:match ('%.pdf[%?#]') or url:match ('%.PDF[%?#]') or url:match ('%.PDF&#035') or url:match ('%.pdf&#035'); end --[[--------------------------< S T Y L E _ F O R M A T >----------------------- Applies CSS style to |format=, |chapter-format=, etc. Also emits an error message if the format parameter does not have a matching URL parameter. If the format parameter is not set and the URL contains a file extension that is recognized as a PDF document by MediaWiki's commons.css, this code will set the format parameter to (PDF) with the appropriate styling. ]] local function style_format (format, url, fmt_param, url_param) if utilities.is_set (format) then format = utilities.wrap_style ('format', format); -- add leading space, parentheses, resize if not utilities.is_set (url) then utilities.set_message ('err_format_missing_url', {fmt_param, url_param}); -- add an error message end elseif is_pdf (url) then -- format is not set so if URL is a PDF file then format = utilities.wrap_style ('format', 'PDF'); -- set format to PDF else format = ''; -- empty string for concatenation end return format; end --[[---------------------< G E T _ D I S P L A Y _ N A M E S >------------------ Returns a number that defines the number of names displayed for author and editor name lists and a Boolean flag to indicate when et al. should be appended to the name list. When the value assigned to |display-xxxxors= is a number greater than or equal to zero, return the number and the previous state of the 'etal' flag (false by default but may have been set to true if the name list contains some variant of the text 'et al.'). When the value assigned to |display-xxxxors= is the keyword 'etal', return a number that is one greater than the number of authors in the list and set the 'etal' flag true. This will cause the list_people() to display all of the names in the name list followed by 'et al.' In all other cases, returns nil and the previous state of the 'etal' flag. inputs: max: A['DisplayAuthors'] or A['DisplayEditors'], etc; a number or some flavor of etal count: #a or #e list_name: 'authors' or 'editors' etal: author_etal or editor_etal This function sets an error message when |display-xxxxors= value greater than or equal to number of names but not when <max> comes from {{cs1 config}} global settings. When using global settings, <param> is set to the keyword 'cs1 config' which is used to supress the normal error. Error is suppressed because it is to be expected that some citations in an article will have the same or fewer names that the limit specified in {{cs1 config}}. ]] local function get_display_names (max, count, list_name, etal, param) if utilities.is_set (max) then if 'etal' == max:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings max = count + 1; -- number of authors + 1 so display all author name plus et al. etal = true; -- overrides value set by extract_names() elseif max:match ('^%d+$') then -- if is a string of numbers max = tonumber (max); -- make it a number if (max >= count) and ('cs1 config' ~= param) then -- error when local |display-xxxxors= value greater than or equal to number of names; not an error when using global setting utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; end else -- not a valid keyword or number utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; -- unset; as if |display-xxxxors= had not been set end end return max, etal; end --[[----------< E X T R A _ T E X T _ I N _ P A G E _ C H E C K >--------------- Adds error if |page=, |pages=, |quote-page=, |quote-pages= has what appears to be some form of p. or pp. abbreviation in the first characters of the parameter content. check page for extraneous p, p., pp, pp., pg, pg. at start of parameter value: good pattern: '^P[^%.P%l]' matches when page begins PX or P# but not Px where x and X are letters and # is a digit bad pattern: '^[Pp][PpGg]' matches when page begins pp, pP, Pp, PP, pg, pG, Pg, PG ]] local function extra_text_in_page_check (val, name) if not val:match (cfg.vol_iss_pg_patterns.good_ppattern) then for _, pattern in ipairs (cfg.vol_iss_pg_patterns.bad_ppatterns) do -- spin through the selected sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message ('err_extra_text_pages', name); -- add error message return; -- and done end end end end --[[--------------------------< E X T R A _ T E X T _ I N _ V O L _ I S S _ C H E C K >------------------------ Adds error if |volume= or |issue= has what appears to be some form of redundant 'type' indicator. Applies to both; this function looks for issue text in both |issue= and |volume= and looks for volume-like text in |voluem= and |issue=. For |volume=: 'V.', or 'Vol.' (with or without the dot) abbreviations or 'Volume' in the first characters of the parameter content (all case insensitive). 'V' and 'v' (without the dot) are presumed to be roman numerals so are allowed. For |issue=: 'No.', 'I.', 'Iss.' (with or without the dot) abbreviations, or 'Issue' in the first characters of the parameter content (all case insensitive); numero styling: 'n°' with degree sign U+00B0, and № precomposed numero sign U+2116. Single character values ('v', 'i', 'n') allowed when not followed by separator character ('.', ':', '=', or whitespace character) – param values are trimmed of whitespace by MediaWiki before delivered to the module. <val> is |volume= or |issue= parameter value <name> is |volume= or |issue= parameter name for error message <selector> is 'v' for |volume=, 'i' for |issue= sets error message on failure; returns nothing ]] local function extra_text_in_vol_iss_check (val, name, selector) if not utilities.is_set (val) then return; end local handler = 'v' == selector and 'err_extra_text_volume' or 'err_extra_text_issue'; val = val:lower(); -- force parameter value to lower case for _, pattern in ipairs (cfg.vol_iss_pg_patterns.vi_patterns_t) do -- spin through the sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message (handler, name); -- add error message return; -- and done end end end --[=[-------------------------< G E T _ V _ N A M E _ T A B L E >---------------------------------------------- split apart a |vauthors= or |veditors= parameter. This function allows for corporate names, wrapped in doubled parentheses to also have commas; in the old version of the code, the doubled parentheses were included in the rendered citation and in the metadata. Individual author names may be wikilinked |vauthors=Jones AB, [[E. B. White|White EB]], ((Black, Brown, and Co.)) ]=] local function get_v_name_table (vparam, output_table, output_link_table) local _, accept = utilities.has_accept_as_written (vparam); if accept then utilities.add_prop_cat ('vanc-accept'); -- add properties category end local name_table = mw.text.split(vparam, "%s*,%s*"); -- names are separated by commas local wl_type, label, link; -- wl_type not used here; just a placeholder local i = 1; while name_table[i] do if name_table[i]:match ('^%(%(.*[^%)][^%)]$') then -- first segment of corporate with one or more commas; this segment has the opening doubled parentheses local name = name_table[i]; i = i + 1; -- bump indexer to next segment while name_table[i] do name = name .. ', ' .. name_table[i]; -- concatenate with previous segments if name_table[i]:match ('^.*%)%)$') then -- if this table member has the closing doubled parentheses break; -- and done reassembling so end i = i + 1; -- bump indexer end table.insert (output_table, name); -- and add corporate name to the output table table.insert (output_link_table, ''); -- no wikilink else wl_type, label, link = utilities.is_wikilink (name_table[i]); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] table.insert (output_table, label); -- add this name if 1 == wl_type then table.insert (output_link_table, label); -- simple wikilink [[D]] else table.insert (output_link_table, link); -- no wikilink or [[L|D]]; add this link if there is one, else empty string end end i = i + 1; end return output_table; end --[[--------------------------< P A R S E _ V A U T H O R S _ V E D I T O R S >-------------------------------- This function extracts author / editor names from |vauthors= or |veditors= and finds matching |xxxxor-maskn= and |xxxxor-linkn= in args. It then returns a table of assembled names just as extract_names() does. Author / editor names in |vauthors= or |veditors= must be in Vancouver system style. Corporate or institutional names may sometimes be required and because such names will often fail the is_good_vanc_name() and other format compliance tests, are wrapped in doubled parentheses ((corporate name)) to suppress the format tests. Supports generational suffixes Jr, 2nd, 3rd, 4th–6th. This function sets the Vancouver error when a required comma is missing and when there is a space between an author's initials. ]] local function parse_vauthors_veditors (args, vparam, list_name) local names = {}; -- table of names assembled from |vauthors=, |author-maskn=, |author-linkn= local v_name_table = {}; local v_link_table = {}; -- when name is wikilinked, targets go in this table local etal = false; -- return value set to true when we find some form of et al. vauthors parameter local last, first, link, mask, suffix; local corporate = false; vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period) v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); -- names are separated by commas for i, v_name in ipairs(v_name_table) do first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor local accept_name; v_name, accept_name = utilities.has_accept_as_written (v_name); -- remove accept-this-as-written markup when it wraps all of <v_name> if accept_name then last = v_name; corporate = true; -- flag used in list_people() elseif string.find(v_name, "%s") then if v_name:find('[;%.]') then -- look for commonly occurring punctuation characters; add_vanc_error (cfg.err_msg_supl.punctuation, i); end local lastfirstTable = {} lastfirstTable = mw.text.split(v_name, "%s+") first = table.remove(lastfirstTable); -- removes and returns value of last element in table which should be initials or generational suffix if not mw.ustring.match (first, '^%u+$') then -- mw.ustring here so that later we will catch non-Latin characters suffix = first; -- not initials so assume that whatever we got is a generational suffix first = table.remove(lastfirstTable); -- get what should be the initials from the table end last = table.concat(lastfirstTable, ' ') -- returns a string that is the concatenation of all other names that are not initials and generational suffix if not utilities.is_set (last) then first = ''; -- unset last = v_name; -- last empty because something wrong with first add_vanc_error (cfg.err_msg_supl.name, i); end if mw.ustring.match (last, '%a+%s+%u+%s+%a+') then add_vanc_error (cfg.err_msg_supl['missing comma'], i); -- matches last II last; the case when a comma is missing end if mw.ustring.match (v_name, ' %u %u$') then -- this test is in the wrong place TODO: move or replace with a more appropriate test add_vanc_error (cfg.err_msg_supl.initials, i); -- matches a space between two initials end else last = v_name; -- last name or single corporate name? Doesn't support multiword corporate names? do we need this? end if utilities.is_set (first) then if not mw.ustring.match (first, "^%u?%u$") then -- first shall contain one or two upper-case letters, nothing else add_vanc_error (cfg.err_msg_supl.initials, i); -- too many initials; mixed case initials (which may be ok Romanization); hyphenated initials end is_good_vanc_name (last, first, suffix, i); -- check first and last before restoring the suffix which may have a non-Latin digit if utilities.is_set (suffix) then first = first .. ' ' .. suffix; -- if there was a suffix concatenate with the initials suffix = ''; -- unset so we don't add this suffix to all subsequent names end else if not corporate then is_good_vanc_name (last, '', nil, i); end end link = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ) or v_link_table[i]; mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); names[i] = {last = last, first = first, link = link, mask = mask, corporate = corporate}; -- add this assembled name to our names list end return names, etal; -- all done, return our list of names end --[[--------------------------< S E L E C T _ A U T H O R _ E D I T O R _ S O U R C E >------------------------ Select one of |authors=, |authorn= / |lastn / firstn=, or |vauthors= as the source of the author name list or select one of |editorn= / editor-lastn= / |editor-firstn= or |veditors= as the source of the editor name list. Only one of these appropriate three will be used. The hierarchy is: |authorn= (and aliases) highest and |authors= lowest; |editorn= (and aliases) highest and |veditors= lowest (support for |editors= withdrawn) When looking for |authorn= / |editorn= parameters, test |xxxxor1= and |xxxxor2= (and all of their aliases); stops after the second test which mimicks the test used in extract_names() when looking for a hole in the author name list. There may be a better way to do this, I just haven't discovered what that way is. Emits an error message when more than one xxxxor name source is provided. In this function, vxxxxors = vauthors or veditors; xxxxors = authors as appropriate. ]] local function select_author_editor_source (vxxxxors, xxxxors, args, list_name) local lastfirst = false; if utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 1 ) or -- do this twice in case we have a |first1= without a |last1=; this ... utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 1 ) or -- ... also catches the case where |first= is used with |vauthors= utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 2 ) or utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 2 ) then lastfirst = true; end if (utilities.is_set (vxxxxors) and true == lastfirst) or -- these are the three error conditions (utilities.is_set (vxxxxors) and utilities.is_set (xxxxors)) or (true == lastfirst and utilities.is_set (xxxxors)) then local err_name; if 'AuthorList' == list_name then -- figure out which name should be used in error message err_name = 'author'; else err_name = 'editor'; end utilities.set_message ('err_redundant_parameters', err_name .. '-name-list parameters'); -- add error message end if true == lastfirst then return 1 end; -- return a number indicating which author name source to use if utilities.is_set (vxxxxors) then return 2 end; if utilities.is_set (xxxxors) then return 3 end; return 1; -- no authors so return 1; this allows missing author name test to run in case there is a first without last end --[[--------------------------< I S _ V A L I D _ P A R A M E T E R _ V A L U E >------------------------------ This function is used to validate a parameter's assigned value for those parameters that have only a limited number of allowable values (yes, y, true, live, dead, etc.). When the parameter value has not been assigned a value (missing or empty in the source template) the function returns the value specified by ret_val. If the parameter value is one of the list of allowed values returns the translated value; else, emits an error message and returns the value specified by ret_val. TODO: explain <invert> ]] local function is_valid_parameter_value (value, name, possible, ret_val, invert) if not utilities.is_set (value) then return ret_val; -- an empty parameter is ok end if (not invert and utilities.in_array (value, possible)) then -- normal; <value> is in <possible> table return cfg.keywords_xlate[value]; -- return translation of parameter keyword elseif invert and not utilities.in_array (value, possible) then -- invert; <value> is not in <possible> table return value; -- return <value> as it is else utilities.set_message ('err_invalid_param_val', {name, value}); -- not an allowed value so add error message return ret_val; end end --[[--------------------------< T E R M I N A T E _ N A M E _ L I S T >---------------------------------------- This function terminates a name list (author, contributor, editor) with a separator character (sepc) and a space when the last character is not a sepc character or when the last three characters are not sepc followed by two closing square brackets (close of a wikilink). When either of these is true, the name_list is terminated with a single space character. ]] local function terminate_name_list (name_list, sepc) if (string.sub (name_list, -3, -1) == sepc .. '. ') then -- if already properly terminated return name_list; -- just return the name list elseif (string.sub (name_list, -1, -1) == sepc) or (string.sub (name_list, -3, -1) == sepc .. ']]') then -- if last name in list ends with sepc char return name_list .. " "; -- don't add another else return name_list .. sepc .. ' '; -- otherwise terminate the name list end end --[[-------------------------< F O R M A T _ V O L U M E _ I S S U E >----------------------------------------- returns the concatenation of the formatted volume and issue (or journal article number) parameters as a single string; or formatted volume or formatted issue, or an empty string if neither are set. ]] local function format_volume_issue (volume, issue, article, cite_class, origin, sepc, lower) if not utilities.is_set (volume) and not utilities.is_set (issue) and not utilities.is_set (article) then return ''; end -- same condition as in format_pages_sheets() local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); local is_numeric_vol = volume and (volume:match ('^[MDCLXVI]+$') or volume:match ('^%d+$')); -- is only uppercase roman numerals or only digits? local is_long_vol = volume and (4 < mw.ustring.len(volume)); -- is |volume= value longer than 4 characters? if volume and (not is_numeric_vol and is_long_vol) then -- when not all digits or Roman numerals, is |volume= longer than 4 characters? utilities.add_prop_cat ('long-vol'); -- yes, add properties cat end if is_journal then -- journal-style formatting local vol = ''; if utilities.is_set (volume) then if is_numeric_vol then -- |volume= value all digits or all uppercase Roman numerals? vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, volume}); -- render in bold face elseif is_long_vol then -- not all digits or Roman numerals; longer than 4 characters? vol = utilities.substitute (cfg.messages['j-vol'], {sepc, utilities.hyphen_to_dash (volume)}); -- not bold else -- four or fewer characters vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, utilities.hyphen_to_dash (volume)}); -- bold end end vol = vol .. (utilities.is_set (issue) and utilities.substitute (cfg.messages['j-issue'], issue) or '') vol = vol .. (utilities.is_set (article) and utilities.substitute (cfg.messages['j-article-num'], article) or '') return vol; end if 'podcast' == cite_class and utilities.is_set (issue) then return wrap_msg ('issue', {sepc, issue}, lower); end if 'conference' == cite_class and utilities.is_set (article) then -- |article-number= supported only in journal and conference cites if utilities.is_set (volume) and utilities.is_set (article) then -- both volume and article number return wrap_msg ('vol-art', {sepc, utilities.hyphen_to_dash (volume), article}, lower); elseif utilities.is_set (article) then -- article number alone; when volume alone, handled below return wrap_msg ('art', {sepc, article}, lower); end end -- all other types of citation if utilities.is_set (volume) and utilities.is_set (issue) then return wrap_msg ('vol-no', {sepc, utilities.hyphen_to_dash (volume), issue}, lower); elseif utilities.is_set (volume) then return wrap_msg ('vol', {sepc, utilities.hyphen_to_dash (volume)}, lower); else return wrap_msg ('issue', {sepc, issue}, lower); end end --[[-------------------------< F O R M A T _ P A G E S _ S H E E T S >----------------------------------------- adds static text to one of |page(s)= or |sheet(s)= values and returns it with all of the others set to empty strings. The return order is: page, pages, sheet, sheets Singular has priority over plural when both are provided. ]] local function format_pages_sheets (page, pages, sheet, sheets, cite_class, origin, sepc, nopp, lower) if 'map' == cite_class then -- only cite map supports sheet(s) as in-source locators if utilities.is_set (sheet) then if 'journal' == origin then return '', '', wrap_msg ('j-sheet', sheet, lower), ''; else return '', '', wrap_msg ('sheet', {sepc, sheet}, lower), ''; end elseif utilities.is_set (sheets) then if 'journal' == origin then return '', '', '', wrap_msg ('j-sheets', sheets, lower); else return '', '', '', wrap_msg ('sheets', {sepc, sheets}, lower); end end end local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); if utilities.is_set (page) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], page), '', '', ''; elseif not nopp then return utilities.substitute (cfg.messages['p-prefix'], {sepc, page}), '', '', ''; else return utilities.substitute (cfg.messages['nopp'], {sepc, page}), '', '', ''; end elseif utilities.is_set (pages) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], pages), '', '', ''; elseif tonumber(pages) ~= nil and not nopp then -- if pages is only digits, assume a single page number return '', utilities.substitute (cfg.messages['p-prefix'], {sepc, pages}), '', ''; elseif not nopp then return '', utilities.substitute (cfg.messages['pp-prefix'], {sepc, pages}), '', ''; else return '', utilities.substitute (cfg.messages['nopp'], {sepc, pages}), '', ''; end end return '', '', '', ''; -- return empty strings end --[[--------------------------< I N S O U R C E _ L O C _ G E T >---------------------------------------------- returns one of the in-source locators: page, pages, or at. If any of these are interwiki links to Wikisource, returns the label portion of the interwiki-link as plain text for use in COinS. This COinS thing is done because here we convert an interwiki-link to an external link and add an icon span around that; get_coins_pages() doesn't know about the span. TODO: should it? TODO: add support for sheet and sheets?; streamline; TODO: make it so that this function returns only one of the three as the single in-source (the return value assigned to a new name)? ]] local function insource_loc_get (page, page_orig, pages, pages_orig, at) local ws_url, ws_label, coins_pages, L; -- for Wikisource interwiki-links; TODO: this corrupts page metadata (span remains in place after cleanup; fix there?) if utilities.is_set (page) then if utilities.is_set (pages) or utilities.is_set (at) then pages = ''; -- unset the others at = ''; end extra_text_in_page_check (page, page_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (page); -- make ws URL from |page= interwiki link; link portion L becomes tooltip label if ws_url then page = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in page'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? page = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, page}); coins_pages = ws_label; end elseif utilities.is_set (pages) then if utilities.is_set (at) then at = ''; -- unset end extra_text_in_page_check (pages, pages_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (pages); -- make ws URL from |pages= interwiki link; link portion L becomes tooltip label if ws_url then pages = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in pages'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? pages = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, pages}); coins_pages = ws_label; end elseif utilities.is_set (at) then ws_url, ws_label, L = wikisource_url_make (at); -- make ws URL from |at= interwiki link; link portion L becomes tooltip label if ws_url then at = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in at'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? at = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, at}); coins_pages = ws_label; end end return page, pages, at, coins_pages; end --[[--------------------------< I S _ U N I Q U E _ A R C H I V E _ U R L >------------------------------------ add error message when |archive-url= value is same as |url= or chapter-url= (or alias...) value ]] local function is_unique_archive_url (archive, url, c_url, source, date) if utilities.is_set (archive) then if archive == url or archive == c_url then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); -- add error message return '', ''; -- unset |archive-url= and |archive-date= because same as |url= or |chapter-url= end end return archive, date; end --[=[-------------------------< A R C H I V E _ U R L _ C H E C K >-------------------------------------------- Check archive.org URLs to make sure they at least look like they are pointing at valid archives and not to the save snapshot URL or to calendar pages. When the archive URL is 'https://web.archive.org/save/' (or http://...) archive.org saves a snapshot of the target page in the URL. That is something that Wikipedia should not allow unwitting readers to do. When the archive.org URL does not have a complete timestamp, archive.org chooses a snapshot according to its own algorithm or provides a calendar 'search' result. [[WP:ELNO]] discourages links to search results. This function looks at the value assigned to |archive-url= and returns empty strings for |archive-url= and |archive-date= and an error message when: |archive-url= holds an archive.org save command URL |archive-url= is an archive.org URL that does not have a complete timestamp (YYYYMMDDhhmmss 14 digits) in the correct place otherwise returns |archive-url= and |archive-date= There are two mostly compatible archive.org URLs: //web.archive.org/<timestamp>... -- the old form //web.archive.org/web/<timestamp>... -- the new form The old form does not support or map to the new form when it contains a display flag. There are four identified flags ('id_', 'js_', 'cs_', 'im_') but since archive.org ignores others following the same form (two letters and an underscore) we don't check for these specific flags but we do check the form. This function supports a preview mode. When the article is rendered in preview mode, this function may return a modified archive URL: for save command errors, return undated wildcard (/*/) for timestamp errors when the timestamp has a wildcard, return the URL unmodified for timestamp errors when the timestamp does not have a wildcard, return with timestamp limited to six digits plus wildcard (/yyyymm*/) A secondary function is to return an archive-url timestamp from those urls that have them (archive.org and archive.today). The timestamp is used by validation.archive_date_check() to see if the value in |archive-date= matches the timestamp in the archive url. ]=] local function archive_url_check (url, date) local err_msg = ''; -- start with the error message empty local path, timestamp, flag; -- portions of the archive.org URL timestamp = url:match ('//archive.today/(%d%d%d%d%d%d%d%d%d%d%d%d%d%d)/') or -- get timestamp from archive.today urls url:match ('//archive.today/(%d%d%d%d%.%d%d%.%d%d%-%d%d%d%d%d%d)/'); -- this timestamp needs cleanup if timestamp then -- if this was an archive.today url ... return url, date, timestamp:gsub ('[%.%-]', ''); -- return ArchiveURL, ArchiveDate, and timestamp (dots and dashes removed) from |archive-url=, and done end -- here for archive.org urls if (not url:match('//web%.archive%.org/')) and (not url:match('//liveweb%.archive%.org/')) then -- also deprecated liveweb Wayback machine URL return url, date; -- not an archive.org archive, return ArchiveURL and ArchiveDate end if url:match('//web%.archive%.org/save/') then -- if a save command URL, we don't want to allow saving of the target page err_msg = cfg.err_msg_supl.save; url = url:gsub ('(//web%.archive%.org)/save/', '%1/*/', 1); -- for preview mode: modify ArchiveURL elseif url:match('//liveweb%.archive%.org/') then err_msg = cfg.err_msg_supl.liveweb; else path, timestamp, flag = url:match('//web%.archive%.org/([^%d]*)(%d+)([^/]*)/'); -- split out some of the URL parts for evaluation if not path then -- malformed in some way; pattern did not match err_msg = cfg.err_msg_supl.timestamp; elseif 14 ~= timestamp:len() then -- path and flag optional, must have 14-digit timestamp here err_msg = cfg.err_msg_supl.timestamp; if '*' ~= flag then local replacement = timestamp:match ('^%d%d%d%d%d%d') or timestamp:match ('^%d%d%d%d'); -- get the first 6 (YYYYMM) or first 4 digits (YYYY) if replacement then -- nil if there aren't at least 4 digits (year) replacement = replacement .. string.rep ('0', 14 - replacement:len()); -- year or yearmo (4 or 6 digits) zero-fill to make 14-digit timestamp url=url:gsub ('(//web%.archive%.org/[^%d]*)%d[^/]*', '%1' .. replacement .. '*', 1) -- for preview, modify ts to 14 digits plus splat for calendar display end end elseif utilities.is_set (path) and 'web/' ~= path then -- older archive URLs do not have the extra 'web/' path element err_msg = cfg.err_msg_supl.path; elseif utilities.is_set (flag) and not utilities.is_set (path) then -- flag not allowed with the old form URL (without the 'web/' path element) err_msg = cfg.err_msg_supl.flag; elseif utilities.is_set (flag) and not flag:match ('%a%a_') then -- flag if present must be two alpha characters and underscore (requires 'web/' path element) err_msg = cfg.err_msg_supl.flag; else return url, date, timestamp; -- return ArchiveURL, ArchiveDate, and timestamp from |archive-url= end end -- if here, something not right so utilities.set_message ('err_archive_url', {err_msg}); -- add error message and if is_preview_mode then return url, date, timestamp; -- preview mode so return ArchiveURL, ArchiveDate, and timestamp from |archive-url= else return '', ''; -- return empty strings for ArchiveURL and ArchiveDate end end --[[--------------------------< P L A C E _ C H E C K >-------------------------------------------------------- check |place=, |publication-place=, |location= to see if these params include digits. This function added because many editors misuse location to specify the in-source location (|page(s)= and |at= are supposed to do that) returns the original parameter value without modification; added maint cat when parameter value contains digits ]] local function place_check (param_val) if not utilities.is_set (param_val) then -- parameter empty or omitted return param_val; -- return that empty state end if mw.ustring.find (param_val, '%d') then -- not empty, are there digits in the parameter value utilities.set_message ('maint_location'); -- yep, add maint cat end return param_val; -- and done end --[[--------------------------< I S _ A R C H I V E D _ C O P Y >---------------------------------------------- compares |title= to 'Archived copy' (placeholder added by bots that can't find proper title); if matches, return true; nil else ]] local function is_archived_copy (title) title = mw.ustring.lower(title); -- switch title to lower case if title:find (cfg.special_case_translation.archived_copy.en) then -- if title is 'Archived copy' return true; elseif cfg.special_case_translation.archived_copy['local'] then if mw.ustring.find (title, cfg.special_case_translation.archived_copy['local']) then -- mw.ustring() because might not be Latin script return true; end end end --[[--------------------------< D I S P L A Y _ N A M E S _ S E L E C T >-------------------------------------- for any of the |display-authors=, |display-editors=, etc parameters, select either the local or global setting. When both are present, look at <local_display_names> value. When the value is some sort of 'et al.'string, special handling is required. When {{cs1 config}} has |display-<namelist>= AND this template has |display-<namelist>=etal AND: the number of names specified by <number_of_names> is: greater than the number specified in the global |display-<namelist>= parameter (<global_display_names>) use global |display-<namelist>= parameter value set overridden maint category less than or equal to the number specified in the global |display-<namelist>= parameter use local |display-<namelist>= parameter value The purpose of this function is to prevent categorizing a template that has fewer names than the global setting to keep the etal annotation specified by <local_display_names>. ]] local function display_names_select (global_display_names, local_display_names, param_name, number_of_names, test) if global_display_names and utilities.is_set (local_display_names) then -- when both if 'etal' == local_display_names:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings number_of_names = tonumber (number_of_names); -- convert these to numbers for comparison local global_display_names_num = tonumber (global_display_names); -- <global_display_names> not set when parameter value is not digits if number_of_names > global_display_names_num then -- template has more names than global config allows to be displayed? utilities.set_message ('maint_overridden_setting'); -- set a maint message because global is overriding local |display-<namelist>=etal return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local because fewer names so let <local_display_names> control end end -- here when <global_display_names> and <local_display_names> both numbers; <global_display_names> controls utilities.set_message ('maint_overridden_setting'); -- set a maint message return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) end -- here when only one of <global_display_names> or <local_display_names> set if global_display_names then return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local end end --[[--------------------------< M O D E _ S E T >-------------------------------------------------------------- fetch global mode setting from {{cs1 config}} (if present) or from |mode= (if present); global setting overrides local |mode= parameter value. When both are present, emit maintenance message ]] local function mode_set (Mode, Mode_origin) local mode; if cfg.global_cs1_config_t['Mode'] then -- global setting in {{cs1 config}}; nil when empty or assigned value invalid mode = is_valid_parameter_value (cfg.global_cs1_config_t['Mode'], 'cs1 config: mode', cfg.keywords_lists['mode'], ''); -- error messaging 'param' here is a hoax else mode = is_valid_parameter_value (Mode, Mode_origin, cfg.keywords_lists['mode'], ''); end if cfg.global_cs1_config_t['Mode'] and utilities.is_set (Mode) then -- when template has |mode=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end return mode; end --[[--------------------------< Q U O T E _ M A K E >---------------------------------------------------------- create quotation from |quote=, |trans-quote=, and/or script-quote= with or without |quote-page= or |quote-pages= when any of those three quote parameters are set, this function unsets <PostScript>. When none of those parameters are set, |quote-page= and |quote-pages= are unset to nil so that they are not included in the template's metadata ]] local function quote_make (quote, trans_quote, script_quote, quote_page, quote_pages, nopp, sepc, postscript) if utilities.is_set (quote) or utilities.is_set (trans_quote) or utilities.is_set (script_quote) then if utilities.is_set (quote) then if quote:sub(1, 1) == '"' and quote:sub(-1, -1) == '"' then -- if first and last characters of quote are quote marks quote = quote:sub(2, -2); -- strip them off end end quote = kern_quotes (quote); -- kern if needed quote = utilities.wrap_style ('quoted-text', quote ); -- wrap in <q>...</q> tags if utilities.is_set (script_quote) then quote = script_concatenate (quote, script_quote, 'script-quote'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after quote is wrapped end if utilities.is_set (trans_quote) then if trans_quote:sub(1, 1) == '"' and trans_quote:sub(-1, -1) == '"' then -- if first and last characters of |trans-quote are quote marks trans_quote = trans_quote:sub(2, -2); -- strip them off end quote = quote .. " " .. utilities.wrap_style ('trans-quoted-title', trans_quote ); end if utilities.is_set (quote_page) or utilities.is_set (quote_pages) then -- add page prefix local quote_prefix = ''; if utilities.is_set (quote_page) then extra_text_in_page_check (quote_page, 'quote-page'); -- add to maint cat if |quote-page= value begins with what looks like p., pp., etc. if not nopp then quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_page}), '', '', ''; else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_page}), '', '', ''; end elseif utilities.is_set (quote_pages) then extra_text_in_page_check (quote_pages, 'quote-pages'); -- add to maint cat if |quote-pages= value begins with what looks like p., pp., etc. if tonumber(quote_pages) ~= nil and not nopp then -- if only digits, assume single page quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_pages}), '', ''; elseif not nopp then quote_prefix = utilities.substitute (cfg.messages['pp-prefix'], {sepc, quote_pages}), '', ''; else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_pages}), '', ''; end end quote = quote_prefix .. ": " .. quote; else quote = sepc .. " " .. quote; end postscript = ""; -- cs1|2 does not supply terminal punctuation when |quote= is set elseif utilities.is_set (quote_page) or utilities.is_set (quote_pages) then quote_page = nil; -- unset; these require |quote=; TODO: error message? quote_pages = nil; end return quote, quote_page, quote_pages, postscript; end --[[--------------------------< C H E C K _ P U B L I S H E R _ N A M E >-------------------------------------- look for variations of '<text>: <text>' that might be '<location>: <publisher>' in |publisher= parameter value. when found, emit a maintenance message; return nil else <publisher> is the value assigned to |publisher= or |institution= ]] local function check_publisher_name (publisher) local patterns_t = { '^[%w%s]+%s*:%s*[%w%s]+$', -- plain text <location>: <publisher> '^%[+[%w%s:|]+%]+%s*:%s*[%w%s]+$', -- partially wikilinked [[<location>]]: <publisher> '^[%w%s]+%s*:%s*%[+[%w%s:|]+%]+$', -- partially wikilinked <location>: [[<publisher>]] '^%[+[%w%s:|]+%]+%s*:%s*%[+[%w%s:|]+%]+$', -- wikilinked [[<location>]]: [[<publisher>]] } for _, pattern in ipairs (patterns_t) do -- spin through the patterns_t sequence if mw.ustring.match (publisher, pattern) then -- does this pattern match? utilities.set_message ('maint_publisher_location'); -- set a maint message return; -- and done end end end --[[--------------------------< I S _ P A G E _ A R T _ N U M >------------------------------------------------ compare the trailing (rightmost) characters of the |doi= value against the whole value assigned to |page(s)=. return boolean true when: |page(s)= has exactly 8 digits and a dot between the fourth and fifth digits matches the trailing 9 characters of the |doi= value: |page=12345678 → |page=1234.5678 matches |doi=10.xxxx/yyyy1234.5678 |page(s)= is 5 or more characters and matches |doi= values's trailing characters |page(s)= begins with a lowercase 'e' and |page(s)= without the 'e' matches |doi= values's trailing characters: |page=e12345 → |page=12345 matches |doi=10.xxxx/yyyy12345 |page(s)= begins with a uppercase 'CD' followed by (typically) six digits matches |doi= values that ends with 'CDxxxxxx.pubx' (where 'x' is any single digit) return nil when |page(s)= values: are ranges separated by underscore, hyphen, emdash, endash, figure dash, or minus character are comma- or semicolon-separated lists of pages have external urls (has text 'http') are digit-only values less than 10000 do not match |doi= values's trailing characters ]] local function is_page_art_num (page, doi) if not (utilities.is_set (page) and utilities.is_set (doi)) then -- both required return; -- abandon; nothing to do end if page:match ('[,;_−–—‒%-]') then -- when |page(s)= might be a page range or a separated list of pages return; -- abandon end page = page:lower(); -- because doi names are case insensitive doi = doi:lower(); -- force these to lowercase for testing if page:match ('http') then -- when |page(s)= appears to hold a url return; -- abandon end if tonumber (page) then -- is |page(s)= digits only if 10000 > tonumber (page) then -- when |page(s)= less than 10000 return; -- abandon end if doi:match (page .. '$') then -- digits only page number match the last digits in |doi=? return true; end if 8 == page:len() then -- special case when |page(s)= is exactly 8 digits local dot_page = page:gsub ('(%d%d%d%d)(%d%d%d%d)', '%1.%2'); -- make a |page=xxxx.yyyy version commonly used in |doi= if doi:match (dot_page .. '$') then -- 8-digit dotted page number match the last characters in |doi=? return true; end end else -- here when |page(s)= is alpha-numeric if 4 < page:len() then -- when |page(s)= is five or more characters if doi:match (page .. '$') then -- alpha-numeric page match the last characters in |doi=? return true; end local epage = page:match ('^e([%w]+)$'); -- if first character of |page= is 'e', remove it if epage and doi:match (epage .. '$') then -- page number match the last characters in |doi=? return true; end local cdpage = page:match ('^cd%d+$'); -- if first characters of |page= are 'CD' and last characters are digits (typically 6 digits) if cdpage and doi:match (cdpage .. '%.pub%d$') then -- page number matches doi 'CDxxxxxx.pubx' where 'x' is a digit return true; end end end end --[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------ This is the main function doing the majority of the citation formatting. ]] local function citation0( config, args ) --[[ Load Input Parameters The argument_wrapper facilitates the mapping of multiple aliases to single internal variable. ]] local A = argument_wrapper ( args ); local i -- Pick out the relevant fields from the arguments. Different citation templates -- define different field names for the same underlying things. local author_etal; local a = {}; -- authors list from |lastn= / |firstn= pairs or |vauthors= local Authors; local NameListStyle; if cfg.global_cs1_config_t['NameListStyle'] then -- global setting in {{cs1 config}} overrides local |name-list-style= parameter value; nil when empty or assigned value invalid NameListStyle = is_valid_parameter_value (cfg.global_cs1_config_t['NameListStyle'], 'cs1 config: name-list-style', cfg.keywords_lists['name-list-style'], ''); -- error messaging 'param' here is a hoax else NameListStyle = is_valid_parameter_value (A['NameListStyle'], A:ORIGIN('NameListStyle'), cfg.keywords_lists['name-list-style'], ''); end if cfg.global_cs1_config_t['NameListStyle'] and utilities.is_set (A['NameListStyle']) then -- when template has |name-list-style=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end local Collaboration = A['Collaboration']; do -- to limit scope of selected local selected = select_author_editor_source (A['Vauthors'], A['Authors'], args, 'AuthorList'); if 1 == selected then a, author_etal = extract_names (args, 'AuthorList'); -- fetch author list from |authorn= / |lastn= / |firstn=, |author-linkn=, and |author-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be a, author_etal = parse_vauthors_veditors (args, A['Vauthors'], 'AuthorList'); -- fetch author list from |vauthors=, |author-linkn=, and |author-maskn= elseif 3 == selected then Authors = A['Authors']; -- use content of |people= or |credits=; |authors= is deprecated; TODO: constrain |people= and |credits= to cite av media, episode, serial? end if utilities.is_set (Collaboration) then author_etal = true; -- so that |display-authors=etal not required end end local editor_etal; local e = {}; -- editors list from |editor-lastn= / |editor-firstn= pairs or |veditors= do -- to limit scope of selected local selected = select_author_editor_source (A['Veditors'], nil, args, 'EditorList'); -- support for |editors= withdrawn if 1 == selected then e, editor_etal = extract_names (args, 'EditorList'); -- fetch editor list from |editorn= / |editor-lastn= / |editor-firstn=, |editor-linkn=, and |editor-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be e, editor_etal = parse_vauthors_veditors (args, args.veditors, 'EditorList'); -- fetch editor list from |veditors=, |editor-linkn=, and |editor-maskn= end end local Chapter = A['Chapter']; -- done here so that we have access to |contribution= from |chapter= aliases local Chapter_origin = A:ORIGIN ('Chapter'); local Contribution; -- because contribution is required for contributor(s) if 'contribution' == Chapter_origin then Contribution = Chapter; -- get the name of the contribution end local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (A['Periodical']) then -- |contributor= and |contribution= only supported in book cites c = extract_names (args, 'ContributorList'); -- fetch contributor list from |contributorn= / |contributor-lastn=, -firstn=, -linkn=, -maskn= if 0 < #c then if not utilities.is_set (Contribution) then -- |contributor= requires |contribution= utilities.set_message ('err_contributor_missing_required_param', 'contribution'); -- add missing contribution error message c = {}; -- blank the contributors' table; it is used as a flag later end if 0 == #a then -- |contributor= requires |author= utilities.set_message ('err_contributor_missing_required_param', 'author'); -- add missing author error message c = {}; -- blank the contributors' table; it is used as a flag later end end else -- if not a book cite if utilities.select_one (args, cfg.aliases['ContributorList-Last'], 'err_redundant_parameters', 1 ) then -- are there contributor name list parameters? utilities.set_message ('err_contributor_ignored'); -- add contributor ignored error message end Contribution = nil; -- unset end local Title = A['Title']; local TitleLink = A['TitleLink']; local auto_select = ''; -- default is auto local accept_link; TitleLink, accept_link = utilities.has_accept_as_written (TitleLink, true); -- test for accept-this-as-written markup if (not accept_link) and utilities.in_array (TitleLink, {'none', 'pmc', 'doi'}) then -- check for special keywords auto_select = TitleLink; -- remember selection for later TitleLink = ''; -- treat as if |title-link= would have been empty end TitleLink = link_title_ok (TitleLink, A:ORIGIN ('TitleLink'), Title, 'title'); -- check for wiki-markup in |title-link= or wiki-markup in |title= when |title-link= is set local Section = ''; -- {{cite map}} only; preset to empty string for concatenation if not used if 'map' == config.CitationClass and 'section' == Chapter_origin then Section = A['Chapter']; -- get |section= from |chapter= alias list; |chapter= and the other aliases not supported in {{cite map}} Chapter = ''; -- unset for now; will be reset later from |map= if present end local Periodical = A['Periodical']; local Periodical_origin = A:ORIGIN('Periodical'); local ScriptPeriodical = A['ScriptPeriodical']; local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical'); local TransPeriodical = A['TransPeriodical']; local TransPeriodical_origin = A:ORIGIN ('TransPeriodical'); if (utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical))) then local param; if utilities.is_set (Periodical) then -- get a parameter name from one of these periodical related meta-parameters Periodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = Periodical_origin -- get parameter name for error messaging elseif utilities.is_set (TransPeriodical) then TransPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = TransPeriodical_origin; -- get parameter name for error messaging elseif utilities.is_set (ScriptPeriodical) then ScriptPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = ScriptPeriodical_origin; -- get parameter name for error messaging end if utilities.is_set (param) then -- if we found one utilities.set_message ('err_periodical_ignored', {param}); -- emit an error message end end if utilities.is_set (Periodical) then local i; Periodical, i = utilities.strip_apostrophe_markup (Periodical); -- strip apostrophe markup so that metadata isn't contaminated if i then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {Periodical_origin}); end end if 'mailinglist' == config.CitationClass then -- special case for {{cite mailing list}} if utilities.is_set (Periodical) and utilities.is_set (A ['MailingList']) then -- both set emit an error TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', Periodical_origin) .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'mailinglist')}); end Periodical = A ['MailingList']; -- error or no, set Periodical to |mailinglist= value because this template is {{cite mailing list}} Periodical_origin = A:ORIGIN('MailingList'); end -- web and news not tested for now because of -- Wikipedia:Administrators%27_noticeboard#Is_there_a_semi-automated_tool_that_could_fix_these_annoying_"Cite_Web"_errors? if not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) then -- 'periodical' templates require periodical parameter -- local p = {['journal'] = 'journal', ['magazine'] = 'magazine', ['news'] = 'newspaper', ['web'] = 'website'}; -- for error message local p = {['journal'] = 'journal', ['magazine'] = 'magazine'}; -- for error message if p[config.CitationClass] then utilities.set_message ('err_missing_periodical', {config.CitationClass, p[config.CitationClass]}); end end local Volume; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) then if not utilities.in_array (Periodical_origin, cfg.citation_no_volume_t) then -- {{citation}} does not render |volume= when these parameters are used Volume = A['Volume']; -- but does for all other 'periodicals' end elseif utilities.is_set (ScriptPeriodical) then if 'script-website' ~= ScriptPeriodical_origin then -- {{citation}} does not render volume for |script-website= Volume = A['Volume']; -- but does for all other 'periodicals' end else Volume = A['Volume']; -- and does for non-'periodical' cites end elseif utilities.in_array (config.CitationClass, cfg.templates_using_volume) then -- render |volume= for cs1 according to the configuration settings Volume = A['Volume']; end extra_text_in_vol_iss_check (Volume, A:ORIGIN ('Volume'), 'v'); local Issue; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) and utilities.in_array (Periodical_origin, cfg.citation_issue_t) then -- {{citation}} may render |issue= when these parameters are used Issue = utilities.hyphen_to_dash (A['Issue']); end elseif utilities.in_array (config.CitationClass, cfg.templates_using_issue) then -- conference & map books do not support issue; {{citation}} listed here because included in settings table if not (utilities.in_array (config.CitationClass, {'conference', 'map', 'citation'}) and not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical))) then Issue = utilities.hyphen_to_dash (A['Issue']); end end local ArticleNumber; if utilities.in_array (config.CitationClass, {'journal', 'conference'}) or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then ArticleNumber = A['ArticleNumber']; end extra_text_in_vol_iss_check (Issue, A:ORIGIN ('Issue'), 'i'); local Page; local Pages; local At; local QuotePage; local QuotePages; if not utilities.in_array (config.CitationClass, cfg.templates_not_using_page) then -- TODO: rewrite to emit ignored parameter error message? Page = A['Page']; Pages = utilities.hyphen_to_dash (A['Pages']); At = A['At']; QuotePage = A['QuotePage']; QuotePages = utilities.hyphen_to_dash (A['QuotePages']); end local NoPP = is_valid_parameter_value (A['NoPP'], A:ORIGIN('NoPP'), cfg.keywords_lists['yes_true_y'], nil); local Mode = mode_set (A['Mode'], A:ORIGIN('Mode')); -- separator character and postscript local sepc, PostScript = set_style (Mode:lower(), A['PostScript'], config.CitationClass); local Quote; Quote, QuotePage, QuotePages, PostScript = quote_make (A['Quote'], A['TransQuote'], A['ScriptQuote'], QuotePage, QuotePages, NoPP, sepc, PostScript); local Edition = A['Edition']; local PublicationPlace = place_check (A['PublicationPlace'], A:ORIGIN('PublicationPlace')); local Place = place_check (A['Place'], A:ORIGIN('Place')); local PublisherName = A['PublisherName']; local PublisherName_origin = A:ORIGIN('PublisherName'); if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then local i = 0; PublisherName, i = utilities.strip_apostrophe_markup (PublisherName); -- strip apostrophe markup so that metadata isn't contaminated; publisher is never italicized if i and (0 < i) then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {PublisherName_origin}); end end if ('document' == config.CitationClass) and not utilities.is_set (PublisherName) then utilities.set_message ('err_missing_publisher', {config.CitationClass, 'publisher'}); end local Newsgroup = A['Newsgroup']; -- TODO: strip apostrophe markup? local Newsgroup_origin = A:ORIGIN('Newsgroup'); if 'newsgroup' == config.CitationClass then if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then -- general use parameter |publisher= not allowed in cite newsgroup utilities.set_message ('err_parameter_ignored', {PublisherName_origin}); end PublisherName = nil; -- ensure that this parameter is unset for the time being; will be used again after COinS end if 'book' == config.CitationClass or 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then local accept; PublisherName, accept = utilities.has_accept_as_written (PublisherName); -- check for and remove accept-as-written markup from |publisher= wrapped if not accept then -- when no accept-as-written markup check_publisher_name (PublisherName); -- emit maint message when |publisher= might be prefixed with publisher's location end end local URL = A['URL']; -- TODO: better way to do this for URL, ChapterURL, and MapURL? local UrlAccess = is_valid_parameter_value (A['UrlAccess'], A:ORIGIN('UrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (URL) and utilities.is_set (UrlAccess) then UrlAccess = nil; utilities.set_message ('err_param_access_requires_param', 'url'); end local ChapterURL = A['ChapterURL']; local ChapterUrlAccess = is_valid_parameter_value (A['ChapterUrlAccess'], A:ORIGIN('ChapterUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (ChapterURL) and utilities.is_set (ChapterUrlAccess) then ChapterUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {A:ORIGIN('ChapterUrlAccess'):gsub ('%-access', '')}); end local MapUrlAccess = is_valid_parameter_value (A['MapUrlAccess'], A:ORIGIN('MapUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (A['MapURL']) and utilities.is_set (MapUrlAccess) then MapUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {'map-url'}); end local this_page = mw.title.getCurrentTitle(); -- also used for COinS and for language local no_tracking_cats = is_valid_parameter_value (A['NoTracking'], A:ORIGIN('NoTracking'), cfg.keywords_lists['yes_true_y'], nil); -- check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories if not utilities.is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page if cfg.uncategorized_namespaces[this_page.namespace] then -- is this page's namespace id one of the uncategorized namespace ids? no_tracking_cats = "true"; -- set no_tracking_cats end for _, v in ipairs (cfg.uncategorized_subpages) do -- cycle through page name patterns if this_page.text:match (v) then -- test page name against each pattern no_tracking_cats = "true"; -- set no_tracking_cats break; -- bail out if one is found end end end -- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it) utilities.select_one (args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'err_redundant_parameters'); -- this is a dummy call simply to get the error message and category local coins_pages; Page, Pages, At, coins_pages = insource_loc_get (Page, A:ORIGIN('Page'), Pages, A:ORIGIN('Pages'), At); if utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- both |publication-place= and |place= (|location=) allowed if different utilities.add_prop_cat ('location-test'); -- add property cat to evaluate how often PublicationPlace and Place are used together if PublicationPlace == Place then Place = ''; -- unset; don't need both if they are the same end elseif not utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- when only |place= (|location=) is set ... PublicationPlace = Place; -- promote |place= (|location=) to |publication-place end if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same local URL_origin = A:ORIGIN('URL'); -- get name of parameter that holds URL local ChapterURL_origin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL local ScriptChapter = A['ScriptChapter']; local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); local Format = A['Format']; local ChapterFormat = A['ChapterFormat']; local TransChapter = A['TransChapter']; local TransChapter_origin = A:ORIGIN ('TransChapter'); local TransTitle = A['TransTitle']; local ScriptTitle = A['ScriptTitle']; --[[ Parameter remapping for cite encyclopedia: When the citation has these parameters: |encyclopedia= and |title= then map |title= to |article= and |encyclopedia= to |title= for rendering |encyclopedia= and |article= then map |encyclopedia= to |title= for rendering |trans-title= maps to |trans-chapter= when |title= is re-mapped |url= maps to |chapter-url= when |title= is remapped All other combinations of |encyclopedia=, |title=, and |article= are not modified ]] local Encyclopedia = A['Encyclopedia']; -- used as a flag by this module and by ~/COinS local ScriptEncyclopedia = A['ScriptEncyclopedia']; local TransEncyclopedia = A['TransEncyclopedia']; if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then -- emit error message when Encyclopedia set but template is other than {{cite encyclopedia}} or {{citation}} if 'encyclopaedia' ~= config.CitationClass and 'citation' ~= config.CitationClass then if utilities.is_set (Encyclopedia) then utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('Encyclopedia')}); else utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('ScriptEncyclopedia')}); end Encyclopedia = nil; -- unset these because not supported by this template ScriptEncyclopedia = nil; TransEncyclopedia = nil; end elseif utilities.is_set (TransEncyclopedia) then utilities.set_message ('err_trans_missing_title', {'encyclopedia'}); end if ('encyclopaedia' == config.CitationClass) or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Periodical) and utilities.is_set (Encyclopedia) then -- when both parameters set emit an error message; {{citation}} only; Periodical not allowed in {{cite encyclopedia}} utilities.set_message ('err_periodical_ignored', {Periodical_origin}); end if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then Periodical = Encyclopedia; -- error or no, set Periodical to Encyclopedia for rendering; {{citation}} could (not legitimately) have both; use Encyclopedia Periodical_origin = A:ORIGIN ('Encyclopedia'); ScriptPeriodical = ScriptEncyclopedia; ScriptPeriodical_origin = A:ORIGIN ('ScriptEncyclopedia'); if utilities.is_set (Title) or utilities.is_set (ScriptTitle) then if not utilities.is_set (Chapter) then Chapter = Title; -- |encyclopedia= and |title= are set so map |title= params to |article= params for rendering ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle') TransChapter = TransTitle; ChapterURL = URL; ChapterURL_origin = URL_origin; ChapterUrlAccess = UrlAccess; ChapterFormat = Format; if not utilities.is_set (ChapterURL) and utilities.is_set (TitleLink) then Chapter = utilities.make_wikilink (TitleLink, Chapter); end Title = Periodical; -- now map |encyclopedia= params to |title= params for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; URL = ''; Format = ''; TitleLink = ''; end elseif utilities.is_set (Chapter) or utilities.is_set (ScriptChapter) then -- |title= not set Title = Periodical; -- |encyclopedia= set and |article= set so map |encyclopedia= to |title= for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; end end end -- special case for cite techreport. local ID = A['ID']; if (config.CitationClass == "techreport") then -- special case for cite techreport if utilities.is_set (A['Number']) then -- cite techreport uses 'number', which other citations alias to 'issue' if not utilities.is_set (ID) then -- can we use ID for the "number"? ID = A['Number']; -- yes, use it else -- ID has a value so emit error message utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'id') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'number')}); end end end -- Account for the oddity that is {{cite conference}}, before generation of COinS data. local ChapterLink -- = A['ChapterLink']; -- deprecated as a parameter but still used internally by cite episode local Conference = A['Conference']; local BookTitle = A['BookTitle']; local TransTitle_origin = A:ORIGIN ('TransTitle'); if 'conference' == config.CitationClass then if utilities.is_set (BookTitle) then Chapter = Title; Chapter_origin = 'title'; -- ChapterLink = TitleLink; -- |chapter-link= is deprecated ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; URL_origin = ''; ChapterFormat = Format; TransChapter = TransTitle; TransChapter_origin = TransTitle_origin; Title = BookTitle; Format = ''; -- TitleLink = ''; TransTitle = ''; URL = ''; end elseif 'speech' ~= config.CitationClass then Conference = ''; -- not cite conference or cite speech so make sure this is empty string end local use_lowercase = ( sepc == ',' ); -- controls capitalization of certain static text -- cite map oddities local Cartography = ""; local Scale = ""; local Sheet = A['Sheet'] or ''; local Sheets = A['Sheets'] or ''; if config.CitationClass == "map" then if utilities.is_set (Chapter) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'map') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', Chapter_origin)}); -- add error message end Chapter = A['Map']; Chapter_origin = A:ORIGIN('Map'); ChapterURL = A['MapURL']; ChapterURL_origin = A:ORIGIN('MapURL'); TransChapter = A['TransMap']; ScriptChapter = A['ScriptMap'] ScriptChapter_origin = A:ORIGIN('ScriptMap') ChapterUrlAccess = MapUrlAccess; ChapterFormat = A['MapFormat']; Cartography = A['Cartography']; if utilities.is_set ( Cartography ) then Cartography = sepc .. " " .. wrap_msg ('cartography', Cartography, use_lowercase); end Scale = A['Scale']; if utilities.is_set ( Scale ) then Scale = sepc .. " " .. Scale; end end -- Account for the oddities that are {{cite episode}} and {{cite serial}}, before generation of COinS data. local Series = A['Series']; if 'episode' == config.CitationClass or 'serial' == config.CitationClass then local SeriesLink = A['SeriesLink']; SeriesLink = link_title_ok (SeriesLink, A:ORIGIN ('SeriesLink'), Series, 'series'); -- check for wiki-markup in |series-link= or wiki-markup in |series= when |series-link= is set local Network = A['Network']; local Station = A['Station']; local s, n = {}, {}; -- do common parameters first if utilities.is_set (Network) then table.insert(n, Network); end if utilities.is_set (Station) then table.insert(n, Station); end ID = table.concat(n, sepc .. ' '); if 'episode' == config.CitationClass then -- handle the oddities that are strictly {{cite episode}} local Season = A['Season']; local SeriesNumber = A['SeriesNumber']; if utilities.is_set (Season) and utilities.is_set (SeriesNumber) then -- these are mutually exclusive so if both are set TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'season') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'seriesno')}); -- add error message SeriesNumber = ''; -- unset; prefer |season= over |seriesno= end -- assemble a table of parts concatenated later into Series if utilities.is_set (Season) then table.insert(s, wrap_msg ('season', Season, use_lowercase)); end if utilities.is_set (SeriesNumber) then table.insert(s, wrap_msg ('seriesnum', SeriesNumber, use_lowercase)); end if utilities.is_set (Issue) then table.insert(s, wrap_msg ('episode', Issue, use_lowercase)); end Issue = ''; -- unset because this is not a unique parameter Chapter = Title; -- promote title parameters to chapter ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle'); ChapterLink = TitleLink; -- alias |episode-link= TransChapter = TransTitle; ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; ChapterFormat = Format; Title = Series; -- promote series to title TitleLink = SeriesLink; Series = table.concat(s, sepc .. ' '); -- this is concatenation of season, seriesno, episode number if utilities.is_set (ChapterLink) and not utilities.is_set (ChapterURL) then -- link but not URL Chapter = utilities.make_wikilink (ChapterLink, Chapter); elseif utilities.is_set (ChapterLink) and utilities.is_set (ChapterURL) then -- if both are set, URL links episode; Series = utilities.make_wikilink (ChapterLink, Series); end URL = ''; -- unset TransTitle = ''; ScriptTitle = ''; Format = ''; else -- now oddities that are cite serial Issue = ''; -- unset because this parameter no longer supported by the citation/core version of cite serial Chapter = A['Episode']; -- TODO: make |episode= available to cite episode someday? if utilities.is_set (Series) and utilities.is_set (SeriesLink) then Series = utilities.make_wikilink (SeriesLink, Series); end Series = utilities.wrap_style ('italic-title', Series); -- series is italicized end end -- end of {{cite episode}} stuff -- handle type parameter for those CS1 citations that have default values local TitleType = A['TitleType']; local Degree = A['Degree']; if utilities.in_array (config.CitationClass, {'AV-media-notes', 'document', 'interview', 'mailinglist', 'map', 'podcast', 'pressrelease', 'report', 'speech', 'techreport', 'thesis'}) then TitleType = set_titletype (config.CitationClass, TitleType); if utilities.is_set (Degree) and "Thesis" == TitleType then -- special case for cite thesis TitleType = Degree .. ' ' .. cfg.title_types ['thesis']:lower(); end end if utilities.is_set (TitleType) then -- if type parameter is specified TitleType = utilities.substitute ( cfg.messages['type'], TitleType); -- display it in parentheses -- TODO: Hack on TitleType to fix bunched parentheses problem end -- legacy: promote PublicationDate to Date if neither Date nor Year are set. local Date = A['Date']; local Date_origin; -- to hold the name of parameter promoted to Date; required for date error messaging local PublicationDate = A['PublicationDate']; local Year = A['Year']; if utilities.is_set (Year) then validation.year_check (Year); -- returns nothing; emits maint message when |year= doesn't hold a 'year' value end if not utilities.is_set (Date) then Date = Year; -- promote Year to Date Year = nil; -- make nil so Year as empty string isn't used for CITEREF if not utilities.is_set (Date) and utilities.is_set (PublicationDate) then -- use PublicationDate when |date= and |year= are not set Date = PublicationDate; -- promote PublicationDate to Date PublicationDate = ''; -- unset, no longer needed Date_origin = A:ORIGIN('PublicationDate'); -- save the name of the promoted parameter else Date_origin = A:ORIGIN('Year'); -- save the name of the promoted parameter end else Date_origin = A:ORIGIN('Date'); -- not a promotion; name required for error messaging end if PublicationDate == Date then PublicationDate = ''; end -- if PublicationDate is same as Date, don't display in rendered citation --[[ Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates. This must be done before we do COinS because here is where we get the date used in the metadata. Date validation supporting code is in Module:Citation/CS1/Date_validation ]] local DF = is_valid_parameter_value (A['DF'], A:ORIGIN('DF'), cfg.keywords_lists['df'], ''); if not utilities.is_set (DF) then DF = cfg.global_df; -- local |df= if present overrides global df set by {{use xxx date}} template end local ArchiveURL; local ArchiveDate; local ArchiveFormat = A['ArchiveFormat']; local archive_url_timestamp; -- timestamp from wayback machine url ArchiveURL, ArchiveDate, archive_url_timestamp = archive_url_check (A['ArchiveURL'], A['ArchiveDate']) ArchiveFormat = style_format (ArchiveFormat, ArchiveURL, 'archive-format', 'archive-url'); ArchiveURL, ArchiveDate = is_unique_archive_url (ArchiveURL, URL, ChapterURL, A:ORIGIN('ArchiveURL'), ArchiveDate); -- add error message when URL or ChapterURL == ArchiveURL local AccessDate = A['AccessDate']; local COinS_date = {}; -- holds date info extracted from |date= for the COinS metadata by Module:Date verification local DoiBroken = A['DoiBroken']; local Embargo = A['Embargo']; local anchor_year; -- used in the CITEREF identifier do -- create defined block to contain local variables error_message, date_parameters_list, mismatch local error_message = ''; -- AirDate has been promoted to Date so not necessary to check it local date_parameters_list = { ['access-date'] = {val = AccessDate, name = A:ORIGIN ('AccessDate')}, ['archive-date'] = {val = ArchiveDate, name = A:ORIGIN ('ArchiveDate')}, ['date'] = {val = Date, name = Date_origin}, ['doi-broken-date'] = {val = DoiBroken, name = A:ORIGIN ('DoiBroken')}, ['pmc-embargo-date'] = {val = Embargo, name = A:ORIGIN ('Embargo')}, ['publication-date'] = {val = PublicationDate, name = A:ORIGIN ('PublicationDate')}, ['year'] = {val = Year, name = A:ORIGIN ('Year')}, }; local error_list = {}; anchor_year, Embargo = validation.dates(date_parameters_list, COinS_date, error_list); if utilities.is_set (Year) and utilities.is_set (Date) then -- both |date= and |year= not normally needed; validation.year_date_check (Year, A:ORIGIN ('Year'), Date, A:ORIGIN ('Date'), error_list); end if 0 == #error_list then -- error free dates only; 0 when error_list is empty local modified = false; -- flag if utilities.is_set (DF) then -- if we need to reformat dates modified = validation.reformat_dates (date_parameters_list, DF); -- reformat to DF format, use long month names if appropriate end if true == validation.date_hyphen_to_dash (date_parameters_list) then -- convert hyphens to dashes where appropriate modified = true; utilities.set_message ('maint_date_format'); -- hyphens were converted so add maint category end -- for those wikis that can and want to have English date names translated to the local language; not supported at en.wiki if cfg.date_name_auto_xlate_enable and validation.date_name_xlate (date_parameters_list, cfg.date_digit_auto_xlate_enable ) then utilities.set_message ('maint_date_auto_xlated'); -- add maint cat modified = true; end if modified then -- if the date_parameters_list values were modified AccessDate = date_parameters_list['access-date'].val; -- overwrite date holding parameters with modified values ArchiveDate = date_parameters_list['archive-date'].val; Date = date_parameters_list['date'].val; DoiBroken = date_parameters_list['doi-broken-date'].val; PublicationDate = date_parameters_list['publication-date'].val; end if archive_url_timestamp and utilities.is_set (ArchiveDate) then validation.archive_date_check (ArchiveDate, archive_url_timestamp, DF); -- does YYYYMMDD in archive_url_timestamp match date in ArchiveDate end else utilities.set_message ('err_bad_date', {utilities.make_sep_list (#error_list, error_list)}); -- add this error message end end -- end of do if utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) or -- {{cite book}}, {{cite encyclopedia}}; TODO: {{cite conference}} and others? ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) or -- {{citation}} as an encylopedia citation ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then -- {{citation}} as a book citation if utilities.is_set (PublicationPlace) then if not utilities.is_set (PublisherName) then local date = COinS_date.rftdate and tonumber (COinS_date.rftdate:match ('%d%d%d%d')); -- get year portion of COinS date (because in Arabic numerals); convert string to number if date and (1850 <= date) then -- location has no publisher; if date is 1850 or later utilities.set_message ('maint_location_no_publisher'); -- add maint cat end else -- PublisherName has a value if cfg.keywords_xlate['none'] == PublisherName then -- if that value is 'none' (only for book and encyclopedia citations) PublisherName = ''; -- unset end end end end local ID_list = {}; -- sequence table of rendered identifiers local ID_list_coins = {}; -- table of identifiers and their values from args; key is same as cfg.id_handlers's key local Class = A['Class']; -- arxiv class identifier local ID_support = { {A['ASINTLD'], 'ASIN', 'err_asintld_missing_asin', A:ORIGIN ('ASINTLD')}, {DoiBroken, 'DOI', 'err_doibroken_missing_doi', A:ORIGIN ('DoiBroken')}, {Embargo, 'PMC', 'err_embargo_missing_pmc', A:ORIGIN ('Embargo')}, } ID_list, ID_list_coins = identifiers.identifier_lists_get (args, { DoiBroken = DoiBroken, -- for |doi= ASINTLD = A['ASINTLD'], -- for |asin= Embargo = Embargo, -- for |pmc= Class = Class, -- for |arxiv= CitationClass = config.CitationClass, -- for |arxiv= Year=anchor_year, -- for |isbn= }, ID_support); -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, {{cite ssrn}}, before generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv=, |citeseerx=, |medrxiv=, |ssrn= required for their templates if not (args[cfg.id_handlers[config.CitationClass:upper()].parameters[1]] or -- can't use ID_list_coins k/v table here because invalid parameters omitted args[cfg.id_handlers[config.CitationClass:upper()].parameters[2]]) then -- which causes unexpected parameter missing error message utilities.set_message ('err_' .. config.CitationClass .. '_missing'); -- add error message end Periodical = ({['arxiv'] = 'arXiv', ['biorxiv'] = 'bioRxiv', ['citeseerx'] = 'CiteSeerX', ['medrxiv'] = 'medRxiv', ['ssrn'] = 'Social Science Research Network'})[config.CitationClass]; end -- Link the title of the work if no |url= was provided, but we have a |pmc= or a |doi= with |doi-access=free if config.CitationClass == "journal" and not utilities.is_set (URL) and not utilities.is_set (TitleLink) and not utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) then -- TODO: remove 'none' once existing citations have been switched to 'off', so 'none' can be used as token for "no title" instead if 'none' ~= cfg.keywords_xlate[auto_select] then -- if auto-linking not disabled if identifiers.auto_link_urls[auto_select] then -- manual selection URL = identifiers.auto_link_urls[auto_select]; -- set URL to be the same as identifier's external link URL_origin = cfg.id_handlers[auto_select:upper()].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['pmc'] then -- auto-select PMC URL = identifiers.auto_link_urls['pmc']; -- set URL to be the same as the PMC external link if not embargoed URL_origin = cfg.id_handlers['PMC'].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['doi'] then -- auto-select DOI URL = identifiers.auto_link_urls['doi']; URL_origin = cfg.id_handlers['DOI'].parameters[1]; end end if utilities.is_set (URL) then -- set when using an identifier-created URL if utilities.is_set (AccessDate) then -- |access-date= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_accessdate_missing_url'); -- add an error message AccessDate = ''; -- unset end if utilities.is_set (ArchiveURL) then -- |archive-url= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_archive_missing_url'); -- add an error message ArchiveURL = ''; -- unset end end end -- At this point fields may be nil if they weren't specified in the template use. We can use that fact. -- Test if citation has no title if not utilities.is_set (Title) and not utilities.is_set (TransTitle) and not utilities.is_set (ScriptTitle) then -- has special case for cite episode utilities.set_message ('err_citation_missing_title', {'episode' == config.CitationClass and 'series' or 'title'}); end if utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) and utilities.in_array (config.CitationClass, {'journal', 'citation'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and ('journal' == Periodical_origin or 'script-journal' == ScriptPeriodical_origin) then -- special case for journal cites Title = ''; -- set title to empty string utilities.set_message ('maint_untitled'); -- add maint cat end if 'journal' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then if is_page_art_num (((utilities.is_set (Page) and Page) or (utilities.is_set (Pages) and Pages)) or nil, ID_list_coins['DOI']) then -- does |page(s)= look like it holds an article number utilities.set_message ('maint_page_art_num'); -- add maint cat end end -- COinS metadata (see <http://ocoins.info/>) for automated parsing of citation information. -- handle the oddity that is cite encyclopedia and {{citation |encyclopedia=something}}. Here we presume that -- when Periodical, Title, and Chapter are all set, then Periodical is the book (encyclopedia) title, Title -- is the article title, and Chapter is a section within the article. So, we remap local coins_chapter = Chapter; -- default assuming that remapping not required local coins_title = Title; -- et tu if 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Chapter) and utilities.is_set (Title) and utilities.is_set (Periodical) then -- if all are used then coins_chapter = Title; -- remap coins_title = Periodical; end end local coins_author = a; -- default for coins rft.au if 0 < #c then -- but if contributor list coins_author = c; -- use that instead end -- this is the function call to COinS() local OCinSoutput = metadata.COinS({ ['Periodical'] = utilities.strip_apostrophe_markup (Periodical), -- no markup in the metadata ['Encyclopedia'] = Encyclopedia, -- just a flag; content ignored by ~/COinS ['Chapter'] = metadata.make_coins_title (coins_chapter, ScriptChapter), -- Chapter and ScriptChapter stripped of bold / italic / accept-as-written markup ['Degree'] = Degree; -- cite thesis only ['Title'] = metadata.make_coins_title (coins_title, ScriptTitle), -- Title and ScriptTitle stripped of bold / italic / accept-as-written markup ['PublicationPlace'] = PublicationPlace, ['Date'] = COinS_date.rftdate, -- COinS_date.* has correctly formatted date values if Date is valid; ['Season'] = COinS_date.rftssn, ['Quarter'] = COinS_date.rftquarter, ['Chron'] = COinS_date.rftchron, ['Series'] = Series, ['Volume'] = Volume, ['Issue'] = Issue, ['ArticleNumber'] = ArticleNumber, ['Pages'] = coins_pages or metadata.get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At, QuotePage, QuotePages}, 7)), -- pages stripped of external links ['Edition'] = Edition, ['PublisherName'] = PublisherName or Newsgroup, -- any apostrophe markup already removed from PublisherName ['URL'] = first_set ({ChapterURL, URL}, 2), ['Authors'] = coins_author, ['ID_list'] = ID_list_coins, ['RawPage'] = this_page.prefixedText, }, config.CitationClass); -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, and {{cite ssrn}} AFTER generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- we have set rft.jtitle in COinS to arXiv, bioRxiv, CiteSeerX, medRxiv, or ssrn now unset so it isn't displayed Periodical = ''; -- periodical not allowed in these templates; if article has been published, use cite journal end -- special case for cite newsgroup. Do this after COinS because we are modifying Publishername to include some static text if 'newsgroup' == config.CitationClass and utilities.is_set (Newsgroup) then PublisherName = utilities.substitute (cfg.messages['newsgroup'], external_link( 'news:' .. Newsgroup, Newsgroup, Newsgroup_origin, nil )); end local Editors; local EditorCount; -- used only for choosing {ed.) or (eds.) annotation at end of editor name-list local Contributors; -- assembled contributors name list local contributor_etal; local Translators; -- assembled translators name list local translator_etal; local t = {}; -- translators list from |translator-lastn= / translator-firstn= pairs t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= local Interviewers; local interviewers_list = {}; interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters local interviewer_etal; -- Now perform various field substitutions. -- We also add leading spaces and surrounding markup and punctuation to the -- various parts of the citation, but only when they are non-nil. do local last_first_list; local control = { format = NameListStyle, -- empty string, '&', 'amp', 'and', or 'vanc' maximum = nil, -- as if display-authors or display-editors not set mode = Mode }; do -- do editor name list first because the now unsupported coauthors used to modify control table local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayEditors'], A['DisplayEditors'], A:ORIGIN ('DisplayEditors'), #e); control.maximum, editor_etal = get_display_names (display_names, #e, 'editors', editor_etal, param); Editors, EditorCount = list_people (control, e, editor_etal); if 1 == EditorCount and (true == editor_etal or 1 < #e) then -- only one editor displayed but includes etal then EditorCount = 2; -- spoof to display (eds.) annotation end end do -- now do interviewers local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayInterviewers'], A['DisplayInterviewers'], A:ORIGIN ('DisplayInterviewers'), #interviewers_list); control.maximum, interviewer_etal = get_display_names (display_names, #interviewers_list, 'interviewers', interviewer_etal, param); Interviewers = list_people (control, interviewers_list, interviewer_etal); end do -- now do translators local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayTranslators'], A['DisplayTranslators'], A:ORIGIN ('DisplayTranslators'), #t); control.maximum, translator_etal = get_display_names (display_names, #t, 'translators', translator_etal, param); Translators = list_people (control, t, translator_etal); end do -- now do contributors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayContributors'], A['DisplayContributors'], A:ORIGIN ('DisplayContributors'), #c); control.maximum, contributor_etal = get_display_names (display_names, #c, 'contributors', contributor_etal, param); Contributors = list_people (control, c, contributor_etal); end do -- now do authors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayAuthors'], A['DisplayAuthors'], A:ORIGIN ('DisplayAuthors'), #a, author_etal); control.maximum, author_etal = get_display_names (display_names, #a, 'authors', author_etal, param); last_first_list = list_people (control, a, author_etal); if utilities.is_set (Authors) then Authors, author_etal = name_has_etal (Authors, author_etal, false, 'authors'); -- find and remove variations on et al. if author_etal then Authors = Authors .. ' ' .. cfg.messages['et al']; -- add et al. to authors parameter end else Authors = last_first_list; -- either an author name list or an empty string end end -- end of do if utilities.is_set (Authors) and utilities.is_set (Collaboration) then Authors = Authors .. ' (' .. Collaboration .. ')'; -- add collaboration after et al. end end local ConferenceFormat = A['ConferenceFormat']; local ConferenceURL = A['ConferenceURL']; ConferenceFormat = style_format (ConferenceFormat, ConferenceURL, 'conference-format', 'conference-url'); Format = style_format (Format, URL, 'format', 'url'); -- special case for chapter format so no error message or cat when chapter not supported if not (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia))) then ChapterFormat = style_format (ChapterFormat, ChapterURL, 'chapter-format', 'chapter-url'); end if not utilities.is_set (URL) then if utilities.in_array (config.CitationClass, {"web", "podcast", "mailinglist"}) or -- |url= required for cite web, cite podcast, and cite mailinglist ('citation' == config.CitationClass and ('website' == Periodical_origin or 'script-website' == ScriptPeriodical_origin)) then -- and required for {{citation}} with |website= or |script-website= utilities.set_message ('err_cite_web_url'); end -- do we have |accessdate= without either |url= or |chapter-url=? if utilities.is_set (AccessDate) and not utilities.is_set (ChapterURL) then -- ChapterURL may be set when URL is not set; utilities.set_message ('err_accessdate_missing_url'); AccessDate = ''; end end local UrlStatus = is_valid_parameter_value (A['UrlStatus'], A:ORIGIN('UrlStatus'), cfg.keywords_lists['url-status'], ''); local OriginalURL local OriginalURL_origin local OriginalFormat local OriginalAccess; UrlStatus = UrlStatus:lower(); -- used later when assembling archived text if utilities.is_set ( ArchiveURL ) then if utilities.is_set (ChapterURL) then -- if chapter-url= is set apply archive url to it OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text OriginalURL_origin = ChapterURL_origin; -- name of |chapter-url= parameter for error messages OriginalFormat = ChapterFormat; -- and original |chapter-format= if 'live' ~= UrlStatus then ChapterURL = ArchiveURL -- swap-in the archive's URL ChapterURL_origin = A:ORIGIN('ArchiveURL') -- name of |archive-url= parameter for error messages ChapterFormat = ArchiveFormat or ''; -- swap in archive's format ChapterUrlAccess = nil; -- restricted access levels do not make sense for archived URLs end elseif utilities.is_set (URL) then OriginalURL = URL; -- save copy of original source URL OriginalURL_origin = URL_origin; -- name of URL parameter for error messages OriginalFormat = Format; -- and original |format= OriginalAccess = UrlAccess; if 'live' ~= UrlStatus then -- if URL set then |archive-url= applies to it URL = ArchiveURL -- swap-in the archive's URL URL_origin = A:ORIGIN('ArchiveURL') -- name of archive URL parameter for error messages Format = ArchiveFormat or ''; -- swap in archive's format UrlAccess = nil; -- restricted access levels do not make sense for archived URLs end end elseif utilities.is_set (UrlStatus) then -- if |url-status= is set when |archive-url= is not set utilities.set_message ('maint_url_status'); -- add maint cat end if utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or -- if any of the 'periodical' cites except encyclopedia ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) then local chap_param; if utilities.is_set (Chapter) then -- get a parameter name from one of these chapter related meta-parameters chap_param = A:ORIGIN ('Chapter') elseif utilities.is_set (TransChapter) then chap_param = A:ORIGIN ('TransChapter') elseif utilities.is_set (ChapterURL) then chap_param = A:ORIGIN ('ChapterURL') elseif utilities.is_set (ScriptChapter) then chap_param = ScriptChapter_origin; else utilities.is_set (ChapterFormat) chap_param = A:ORIGIN ('ChapterFormat') end if utilities.is_set (chap_param) then -- if we found one utilities.set_message ('err_chapter_ignored', {chap_param}); -- add error message Chapter = ''; -- and set them to empty string to be safe with concatenation TransChapter = ''; ChapterURL = ''; ScriptChapter = ''; ChapterFormat = ''; end else -- otherwise, format chapter / article title local no_quotes = false; -- default assume that we will be quoting the chapter parameter value if utilities.is_set (Contribution) and 0 < #c then -- if this is a contribution with contributor(s) if utilities.in_array (Contribution:lower(), cfg.keywords_lists.contribution) then -- and a generic contribution title no_quotes = true; -- then render it unquoted end end Chapter = format_chapter_title (ScriptChapter, ScriptChapter_origin, Chapter, Chapter_origin, TransChapter, TransChapter_origin, ChapterURL, ChapterURL_origin, no_quotes, ChapterUrlAccess); -- Contribution is also in Chapter if utilities.is_set (Chapter) then Chapter = Chapter .. ChapterFormat ; if 'map' == config.CitationClass and utilities.is_set (TitleType) then Chapter = Chapter .. ' ' .. TitleType; -- map annotation here; not after title end Chapter = Chapter .. sepc .. ' '; elseif utilities.is_set (ChapterFormat) then -- |chapter= not set but |chapter-format= is so ... Chapter = ChapterFormat .. sepc .. ' '; -- ... ChapterFormat has error message, we want to see it end end -- Format main title local plain_title = false; local accept_title; Title, accept_title = utilities.has_accept_as_written (Title, true); -- remove accept-this-as-written markup when it wraps all of <Title> if accept_title and ('' == Title) then -- only support forced empty for now "(())" Title = cfg.messages['notitle']; -- replace by predefined "No title" message -- TODO: utilities.set_message ( 'err_redundant_parameters', ...); -- issue proper error message instead of muting ScriptTitle = ''; -- just mute for now TransTitle = ''; -- just mute for now plain_title = true; -- suppress text decoration for descriptive title utilities.set_message ('maint_untitled'); -- add maint cat end if not accept_title then -- <Title> not wrapped in accept-as-written markup if '...' == Title:sub (-3) then -- if ellipsis is the last three characters of |title= Title = Title:gsub ('(%.%.%.)%.+$', '%1'); -- limit the number of dots to three elseif not mw.ustring.find (Title, '%.%s*%a%.$') and -- end of title is not a 'dot-(optional space-)letter-dot' initialism ... not mw.ustring.find (Title, '%s+%a%.$') then -- ...and not a 'space-letter-dot' initial (''Allium canadense'' L.) Title = mw.ustring.gsub(Title, '%' .. sepc .. '$', ''); -- remove any trailing separator character; sepc and ms.ustring() here for languages that use multibyte separator characters end if utilities.is_set (ArchiveURL) and is_archived_copy (Title) then utilities.set_message ('maint_archived_copy'); -- add maintenance category before we modify the content of Title end if is_generic ('generic_titles', Title) then utilities.set_message ('err_generic_title'); -- set an error message end end if (not plain_title) and (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'document', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) or ('map' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)))) then -- special case for cite map when the map is in a periodical treat as an article Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from module provided quote marks Title = utilities.wrap_style ('quoted-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); elseif plain_title or ('report' == config.CitationClass) then -- no styling for cite report and descriptive titles (otherwise same as above) Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); -- for cite report, use this form for trans-title else Title = utilities.wrap_style ('italic-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-italic-title', TransTitle); end if utilities.is_set (TransTitle) then if utilities.is_set (Title) then TransTitle = " " .. TransTitle; else utilities.set_message ('err_trans_missing_title', {'title'}); end end if utilities.is_set (Title) then -- TODO: is this the right place to be making Wikisource URLs? if utilities.is_set (TitleLink) and utilities.is_set (URL) then utilities.set_message ('err_wikilink_in_url'); -- set an error message because we can't have both TitleLink = ''; -- unset end if not utilities.is_set (TitleLink) and utilities.is_set (URL) then Title = external_link (URL, Title, URL_origin, UrlAccess) .. TransTitle .. Format; URL = ''; -- unset these because no longer needed Format = ""; elseif utilities.is_set (TitleLink) and not utilities.is_set (URL) then local ws_url; ws_url = wikisource_url_make (TitleLink); -- ignore ws_label return; not used here if ws_url then Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title-link'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], TitleLink, Title}); Title = Title .. TransTitle; else Title = utilities.make_wikilink (TitleLink, Title) .. TransTitle; end else local ws_url, ws_label, L; -- Title has italic or quote markup by the time we get here which causes is_wikilink() to return 0 (not a wikilink) ws_url, ws_label, L = wikisource_url_make (Title:gsub('^[\'"]*(.-)[\'"]*$', '%1')); -- make ws URL from |title= interwiki link (strip italic or quote markup); link portion L becomes tooltip label if ws_url then Title = Title:gsub ('%b[]', ws_label); -- replace interwiki link with ws_label to retain markup Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, Title}); Title = Title .. TransTitle; else Title = Title .. TransTitle; end end else Title = TransTitle; end if utilities.is_set (Place) then Place = " " .. wrap_msg ('written', Place, use_lowercase) .. sepc .. " "; end local ConferenceURL_origin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL if utilities.is_set (Conference) then if utilities.is_set (ConferenceURL) then Conference = external_link( ConferenceURL, Conference, ConferenceURL_origin, nil ); end Conference = sepc .. " " .. Conference .. ConferenceFormat; elseif utilities.is_set (ConferenceURL) then Conference = sepc .. " " .. external_link( ConferenceURL, nil, ConferenceURL_origin, nil ); end local Position = ''; if not utilities.is_set (Position) then local Minutes = A['Minutes']; local Time = A['Time']; if utilities.is_set (Minutes) then if utilities.is_set (Time) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'minutes') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'time')}); end Position = " " .. Minutes .. " " .. cfg.messages['minutes']; else if utilities.is_set (Time) then local TimeCaption = A['TimeCaption'] if not utilities.is_set (TimeCaption) then TimeCaption = cfg.messages['event']; if sepc ~= '.' then TimeCaption = TimeCaption:lower(); end end Position = " " .. TimeCaption .. " " .. Time; end end else Position = " " .. Position; At = ''; end Page, Pages, Sheet, Sheets = format_pages_sheets (Page, Pages, Sheet, Sheets, config.CitationClass, Periodical_origin, sepc, NoPP, use_lowercase); At = utilities.is_set (At) and (sepc .. " " .. At) or ""; Position = utilities.is_set (Position) and (sepc .. " " .. Position) or ""; if config.CitationClass == 'map' then local Sections = A['Sections']; -- Section (singular) is an alias of Chapter so set earlier local Inset = A['Inset']; if utilities.is_set ( Inset ) then Inset = sepc .. " " .. wrap_msg ('inset', Inset, use_lowercase); end if utilities.is_set ( Sections ) then Section = sepc .. " " .. wrap_msg ('sections', Sections, use_lowercase); elseif utilities.is_set ( Section ) then Section = sepc .. " " .. wrap_msg ('section', Section, use_lowercase); end At = At .. Inset .. Section; end local Others = A['Others']; if utilities.is_set (Others) and 0 == #a and 0 == #e then -- add maint cat when |others= has value and used without |author=, |editor= if config.CitationClass == "AV-media-notes" or config.CitationClass == "audio-visual" then -- special maint for AV/M which has a lot of 'false' positives right now utilities.set_message ('maint_others_avm') else utilities.set_message ('maint_others'); end end Others = utilities.is_set (Others) and (sepc .. " " .. Others) or ""; if utilities.is_set (Translators) then Others = safe_join ({sepc .. ' ', wrap_msg ('translated', Translators, use_lowercase), Others}, sepc); end if utilities.is_set (Interviewers) then Others = safe_join ({sepc .. ' ', wrap_msg ('interview', Interviewers, use_lowercase), Others}, sepc); end local TitleNote = A['TitleNote']; TitleNote = utilities.is_set (TitleNote) and (sepc .. " " .. TitleNote) or ""; if utilities.is_set (Edition) then if Edition:match ('%f[%a][Ee]d%n?%.?$') or Edition:match ('%f[%a][Ee]dition$') then -- Ed, ed, Ed., ed., Edn, edn, Edn., edn. utilities.set_message ('err_extra_text_edition'); -- add error message end Edition = " " .. wrap_msg ('edition', Edition); else Edition = ''; end Series = utilities.is_set (Series) and wrap_msg ('series', {sepc, Series}) or ""; -- not the same as SeriesNum local Agency = A['Agency'] or ''; -- |agency= is supported by {{cite magazine}}, {{cite news}}, {{cite press release}}, {{cite web}}, and certain {{citation}} templates if utilities.is_set (Agency) then -- this testing done here because {{citation}} supports 'news' citations if utilities.in_array (config.CitationClass, {'magazine', 'news', 'pressrelease', 'web'}) or ('citation' == config.CitationClass and utilities.in_array (Periodical_origin, {"magazine", "newspaper", "work"})) then Agency = wrap_msg ('agency', {sepc, Agency}); -- format for rendering else Agency = ''; -- unset; not supported utilities.set_message ('err_parameter_ignored', {'agency'}); -- add error message end end Volume = format_volume_issue (Volume, Issue, ArticleNumber, config.CitationClass, Periodical_origin, sepc, use_lowercase); if utilities.is_set (AccessDate) then local retrv_text = " " .. cfg.messages['retrieved'] AccessDate = nowrap_date (AccessDate); -- wrap in nowrap span if date in appropriate format if (sepc ~= ".") then retrv_text = retrv_text:lower() end -- if mode is cs2, lower case AccessDate = utilities.substitute (retrv_text, AccessDate); -- add retrieved text AccessDate = utilities.substitute (cfg.presentation['accessdate'], {sepc, AccessDate}); -- allow editors to hide accessdates end if utilities.is_set (ID) then ID = sepc .. " " .. ID; end local Docket = A['Docket']; if "thesis" == config.CitationClass and utilities.is_set (Docket) then ID = sepc .. " Docket " .. Docket .. ID; end if "report" == config.CitationClass and utilities.is_set (Docket) then -- for cite report when |docket= is set ID = sepc .. ' ' .. Docket; -- overwrite ID even if |id= is set end if utilities.is_set (URL) then URL = " " .. external_link( URL, nil, URL_origin, UrlAccess ); end -- We check length of PostScript here because it will have been nuked by -- the quote parameters. We'd otherwise emit a message even if there wasn't -- a displayed postscript. -- TODO: Should the max size (1) be configurable? -- TODO: Should we check a specific pattern? if utilities.is_set(PostScript) and mw.ustring.len(PostScript) > 1 then utilities.set_message ('maint_postscript') end local Archived; if utilities.is_set (ArchiveURL) then if not utilities.is_set (ArchiveDate) then -- ArchiveURL set but ArchiveDate not set utilities.set_message ('err_archive_missing_date'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end else if utilities.is_set (ArchiveDate) then -- ArchiveURL not set but ArchiveDate is set utilities.set_message ('err_archive_date_missing_url'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end end if utilities.is_set (ArchiveURL) then local arch_text; if "live" == UrlStatus then arch_text = cfg.messages['archived']; if sepc ~= "." then arch_text = arch_text:lower() end if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cfg.messages['archived-live'], {external_link( ArchiveURL, arch_text, A:ORIGIN('ArchiveURL'), nil) .. ArchiveFormat, ArchiveDate } ); else Archived = ''; end if not utilities.is_set (OriginalURL) then utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (OriginalURL) then -- UrlStatus is empty, 'dead', 'unfit', 'usurped', 'bot: unknown' if utilities.in_array (UrlStatus, {'unfit', 'usurped', 'bot: unknown'}) then arch_text = cfg.messages['archived-unfit']; if sepc ~= "." then arch_text = arch_text:lower() end Archived = sepc .. ' ' .. arch_text .. ArchiveDate; -- format already styled if 'bot: unknown' == UrlStatus then utilities.set_message ('maint_bot_unknown'); -- and add a category if not already added else utilities.add_prop_cat ('unfit'); -- and add a category if not already added end else -- UrlStatus is empty, 'dead' arch_text = cfg.messages['archived-dead']; if sepc ~= "." then arch_text = arch_text:lower() end if utilities.is_set (ArchiveDate) then Archived = sepc .. " " .. utilities.substitute ( arch_text, { external_link( OriginalURL, cfg.messages['original'], OriginalURL_origin, OriginalAccess ) .. OriginalFormat, ArchiveDate } ); -- format already styled else Archived = ''; -- unset for concatenation end end else -- OriginalUrl not set utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (ArchiveFormat) then Archived = ArchiveFormat; -- if set and ArchiveURL not set ArchiveFormat has error message else Archived = ''; end local TranscriptURL = A['TranscriptURL'] local TranscriptFormat = A['TranscriptFormat']; TranscriptFormat = style_format (TranscriptFormat, TranscriptURL, 'transcript-format', 'transcripturl'); local Transcript = A['Transcript']; local TranscriptURL_origin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL if utilities.is_set (Transcript) then if utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, Transcript, TranscriptURL_origin, nil ); end Transcript = sepc .. ' ' .. Transcript .. TranscriptFormat; elseif utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, nil, TranscriptURL_origin, nil ); end local Publisher; if utilities.is_set (PublicationDate) then PublicationDate = wrap_msg ('published', PublicationDate); end if utilities.is_set (PublisherName) then if utilities.is_set (PublicationPlace) then Publisher = sepc .. " " .. PublicationPlace .. ": " .. PublisherName .. PublicationDate; else Publisher = sepc .. " " .. PublisherName .. PublicationDate; end elseif utilities.is_set (PublicationPlace) then Publisher= sepc .. " " .. PublicationPlace .. PublicationDate; else Publisher = PublicationDate; end -- Several of the above rely upon detecting this as nil, so do it last. if (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical)) then if utilities.is_set (Title) or utilities.is_set (TitleNote) then Periodical = sepc .. " " .. format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); else Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); end end local Language = A['Language']; if utilities.is_set (Language) then Language = language_parameter (Language); -- format, categories, name from ISO639-1, etc. else Language=''; -- language not specified so make sure this is an empty string; --[[ TODO: need to extract the wrap_msg from language_parameter so that we can solve parentheses bunching problem with Format/Language/TitleType ]] end --[[ Handle the oddity that is cite speech. This code overrides whatever may be the value assigned to TitleNote (through |department=) and forces it to be " (Speech)" so that the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided). ]] if "speech" == config.CitationClass then -- cite speech only TitleNote = TitleType; -- move TitleType to TitleNote so that it renders ahead of |event= TitleType = ''; -- and unset if utilities.is_set (Periodical) then -- if Periodical, perhaps because of an included |website= or |journal= parameter if utilities.is_set (Conference) then -- and if |event= is set Conference = Conference .. sepc .. " "; -- then add appropriate punctuation to the end of the Conference variable before rendering end end end -- Piece all bits together at last. Here, all should be non-nil. -- We build things this way because it is more efficient in LUA -- not to keep reassigning to the same string variable over and over. local tcommon; local tcommon2; -- used for book cite when |contributor= is set if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (Periodical) then -- special cases for book cites if utilities.is_set (Contributors) then -- when we are citing foreword, preface, introduction, etc. tcommon = safe_join ({Title, TitleNote}, sepc); -- author and other stuff will come after this and before tcommon2 tcommon2 = safe_join ({TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); else tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); end elseif 'map' == config.CitationClass then -- special cases for cite map if utilities.is_set (Chapter) then -- map in a book; TitleType is part of Chapter tcommon = safe_join ({Title, Edition, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); elseif utilities.is_set (Periodical) then -- map in a periodical tcommon = safe_join ({Title, TitleType, Periodical, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); else -- a sheet or stand-alone map tcommon = safe_join ({Title, TitleType, Edition, Scale, Series, Language, Cartography, Others, Publisher}, sepc); end elseif 'episode' == config.CitationClass then -- special case for cite episode tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Edition, Publisher}, sepc); else -- all other CS1 templates tcommon = safe_join ({Title, TitleNote, Conference, Periodical, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc); end if #ID_list > 0 then ID_list = safe_join( { sepc .. " ", table.concat( ID_list, sepc .. " " ), ID }, sepc ); else ID_list = ID; end local Via = A['Via']; Via = utilities.is_set (Via) and wrap_msg ('via', Via) or ''; local idcommon; if 'audio-visual' == config.CitationClass or 'episode' == config.CitationClass then -- special case for cite AV media & cite episode position transcript idcommon = safe_join( { ID_list, URL, Archived, Transcript, AccessDate, Via, Quote }, sepc ); else idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, Quote }, sepc ); end local text; local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; local OrigDate = A['OrigDate']; OrigDate = utilities.is_set (OrigDate) and wrap_msg ('origdate', OrigDate) or ''; if utilities.is_set (Date) then if utilities.is_set (Authors) or utilities.is_set (Editors) then -- date follows authors or editors when authors not set Date = " (" .. Date .. ")" .. OrigDate .. sepc .. " "; -- in parentheses else -- neither of authors and editors set if (string.sub(tcommon, -1, -1) == sepc) then -- if the last character of tcommon is sepc Date = " " .. Date .. OrigDate; -- Date does not begin with sepc else Date = sepc .. " " .. Date .. OrigDate; -- Date begins with sepc end end end if utilities.is_set (Authors) then if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Authors termination Authors = terminate_name_list (Authors, sepc); -- when no date, terminate with 0 or 1 sepc and a space end if utilities.is_set (Editors) then local in_text = ''; local post_text = ''; if utilities.is_set (Chapter) and 0 == #c then in_text = cfg.messages['in'] .. ' '; if (sepc ~= '.') then in_text = in_text:lower(); -- lowercase for cs2 end end if EditorCount <= 1 then post_text = ' (' .. cfg.messages['editor'] .. ')'; -- be consistent with no-author, no-date case else post_text = ' (' .. cfg.messages['editors'] .. ')'; end Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space end if utilities.is_set (Contributors) then -- book cite and we're citing the intro, preface, etc. local by_text = sepc .. ' ' .. cfg.messages['by'] .. ' '; if (sepc ~= '.') then by_text = by_text:lower() end -- lowercase for cs2 Authors = by_text .. Authors; -- author follows title so tweak it here if utilities.is_set (Editors) and utilities.is_set (Date) then -- when Editors make sure that Authors gets terminated Authors = terminate_name_list (Authors, sepc); -- terminate with 0 or 1 sepc and a space end if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Contributors termination Contributors = terminate_name_list (Contributors, sepc); -- terminate with 0 or 1 sepc and a space end text = safe_join( {Contributors, Date, Chapter, tcommon, Authors, Place, Editors, tcommon2, pgtext, idcommon }, sepc ); else text = safe_join( {Authors, Date, Chapter, Place, Editors, tcommon, pgtext, idcommon }, sepc ); end elseif utilities.is_set (Editors) then if utilities.is_set (Date) then if EditorCount <= 1 then Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editor']; else Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editors']; end else if EditorCount <= 1 then Editors = Editors .. " (" .. cfg.messages['editor'] .. ")" .. sepc .. " " else Editors = Editors .. " (" .. cfg.messages['editors'] .. ")" .. sepc .. " " end end text = safe_join( {Editors, Date, Chapter, Place, tcommon, pgtext, idcommon}, sepc ); else if utilities.in_array (config.CitationClass, {"journal", "citation"}) and utilities.is_set (Periodical) then text = safe_join( {Chapter, Place, tcommon, pgtext, Date, idcommon}, sepc ); else text = safe_join( {Chapter, Place, tcommon, Date, pgtext, idcommon}, sepc ); end end if utilities.is_set (PostScript) and PostScript ~= sepc then text = safe_join( {text, sepc}, sepc ); -- Deals with italics, spaces, etc. if '.' == sepc then -- remove final seperator if present text = text:gsub ('%' .. sepc .. '$', ''); -- dot must be escaped here else text = mw.ustring.gsub (text, sepc .. '$', ''); -- using ustring for non-dot sepc (likely a non-Latin character) end end text = safe_join( {text, PostScript}, sepc ); -- Now enclose the whole thing in a <cite> element local options_t = {}; options_t.class = cite_class_attribute_make (config.CitationClass, Mode); local Ref = is_valid_parameter_value (A['Ref'], A:ORIGIN('Ref'), cfg.keywords_lists['ref'], nil, true); -- nil when |ref=harv; A['Ref'] else if 'none' ~= cfg.keywords_xlate[(Ref and Ref:lower()) or ''] then local namelist_t = {}; -- holds selected contributor, author, editor name list local year = first_set ({Year, anchor_year}, 2); -- Year first for legacy citations and for YMD dates that require disambiguation if #c > 0 then -- if there is a contributor list namelist_t = c; -- select it elseif #a > 0 then -- or an author list namelist_t = a; elseif #e > 0 then -- or an editor list namelist_t = e; end local citeref_id; if #namelist_t > 0 then -- if there are names in namelist_t citeref_id = make_citeref_id (namelist_t, year); -- go make the CITEREF anchor if mw.uri.anchorEncode (citeref_id) == ((Ref and mw.uri.anchorEncode (Ref)) or '') then -- Ref may already be encoded (by {{sfnref}}) so citeref_id must be encoded before comparison utilities.set_message ('maint_ref_duplicates_default'); end else citeref_id = ''; -- unset end options_t.id = Ref or citeref_id; end if string.len (text:gsub('%b<>', '')) <= 2 then -- remove html and html-like tags; then get length of what remains; z.error_cats_t = {}; -- blank the categories list z.error_msgs_t = {}; -- blank the error messages list OCinSoutput = nil; -- blank the metadata string text = ''; -- blank the the citation utilities.set_message ('err_empty_citation'); -- set empty citation message and category end local render_t = {}; -- here we collect the final bits for concatenation into the rendered citation if utilities.is_set (options_t.id) then -- here we wrap the rendered citation in <cite ...>...</cite> tags table.insert (render_t, utilities.substitute (cfg.presentation['cite-id'], {mw.uri.anchorEncode(options_t.id), mw.text.nowiki(options_t.class), text})); -- when |ref= is set or when there is a namelist else table.insert (render_t, utilities.substitute (cfg.presentation['cite'], {mw.text.nowiki(options_t.class), text})); -- when |ref=none or when namelist_t empty and |ref= is missing or is empty end if OCinSoutput then -- blanked when citation is 'empty' so don't bother to add boilerplate metadata span table.insert (render_t, utilities.substitute (cfg.presentation['ocins'], OCinSoutput)); -- format and append metadata to the citation end local template_name = ('citation' == config.CitationClass) and 'citation' or 'cite ' .. (cfg.citation_class_map_t[config.CitationClass] or config.CitationClass); local template_link = '[[Template:' .. template_name .. '|' .. template_name .. ']]'; local msg_prefix = '<code class="cs1-code">{{' .. template_link .. '}}</code>: '; if 0 ~= #z.error_msgs_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_e, template_link)); table.insert (render_t, ' '); -- insert a space between citation and its error messages table.sort (z.error_msgs_t); -- sort the error messages list; sorting includes wrapping <span> and <code> tags; hidden-error sorts ahead of visible-error local hidden = true; -- presume that the only error messages emited by this template are hidden for _, v in ipairs (z.error_msgs_t) do -- spin through the list of error messages if v:find ('cs1-visible-error', 1, true) then -- look for the visible error class name hidden = false; -- found one; so don't hide the error message prefix break; -- and done because no need to look further end end z.error_msgs_t[1] = table.concat ({utilities.error_comment (msg_prefix, hidden), z.error_msgs_t[1]}); -- add error message prefix to first error message to prevent extraneous punctuation table.insert (render_t, table.concat (z.error_msgs_t, '; ')); -- make a big string of error messages and add it to the rendering end if 0 ~= #z.maint_cats_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_m, template_link)); table.sort (z.maint_cats_t); -- sort the maintenance messages list local maint_msgs_t = {}; -- here we collect all of the maint messages if 0 == #z.error_msgs_t then -- if no error messages table.insert (maint_msgs_t, msg_prefix); -- insert message prefix in maint message livery end for _, v in ipairs( z.maint_cats_t ) do -- append maintenance categories table.insert (maint_msgs_t, -- assemble new maint message and add it to the maint_msgs_t table table.concat ({v, ' (', utilities.substitute (cfg.messages[':cat wikilink'], v), ')'}) ); end table.insert (render_t, utilities.substitute (cfg.presentation['hidden-maint'], table.concat (maint_msgs_t, ' '))); -- wrap the group of maint messages with proper presentation and save end if not no_tracking_cats then local sort_key; local cat_wikilink = 'cat wikilink'; if cfg.enable_sort_keys then -- when namespace sort keys enabled local namespace_number = mw.title.getCurrentTitle().namespace; -- get namespace number for this wikitext sort_key = (0 ~= namespace_number and (cfg.name_space_sort_keys[namespace_number] or cfg.name_space_sort_keys.other)) or nil; -- get sort key character; nil for mainspace cat_wikilink = (not sort_key and 'cat wikilink') or 'cat wikilink sk'; -- make <cfg.messages> key end for _, v in ipairs (z.error_cats_t) do -- append error categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end if cfg.id_limits_data_load_fail then -- boolean true when load failed utilities.set_message ('maint_id_limit_load_fail'); -- done here because this maint cat emits no message end for _, v in ipairs (z.maint_cats_t) do -- append maintenance categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end for _, v in ipairs (z.prop_cats_t) do -- append properties categories table.insert (render_t, utilities.substitute (cfg.messages['cat wikilink'], v)); -- no sort keys end end return table.concat (render_t); -- make a big string and done end --[[--------------------------< V A L I D A T E >-------------------------------------------------------------- Looks for a parameter's name in one of several whitelists. Parameters in the whitelist can have three values: true - active, supported parameters false - deprecated, supported parameters nil - unsupported parameters ]] local function validate (name, cite_class, empty) local name = tostring (name); local enum_name; -- parameter name with enumerator (if any) replaced with '#' local state; local function state_test (state, name) -- local function to do testing of state values if true == state then return true; end -- valid actively supported parameter if false == state then if empty then return nil; end -- empty deprecated parameters are treated as unknowns deprecated_parameter (name); -- parameter is deprecated but still supported return true; end if 'tracked' == state then local base_name = name:gsub ('%d', ''); -- strip enumerators from parameter names that have them to get the base name utilities.add_prop_cat ('tracked-param', {base_name}, base_name); -- add a properties category; <base_name> modifies <key> return true; end return nil; end if name:find ('#') then -- # is a cs1|2 reserved character so parameters with # not permitted return nil; end -- replace enumerator digit(s) with # (|last25= becomes |last#=) (mw.ustring because non-Western 'local' digits) enum_name = mw.ustring.gsub (name, '%d+$', '#'); -- where enumerator is last charaters in parameter name (these to protect |s2cid=) enum_name = mw.ustring.gsub (enum_name, '%d+([%-l])', '#%1'); -- where enumerator is in the middle of the parameter name; |author#link= is the oddity if 'document' == cite_class then -- special case for {{cite document}} state = whitelist.document_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end return false; end if utilities.in_array (cite_class, whitelist.preprint_template_list_t) then -- limited parameter sets allowed for these templates state = whitelist.limited_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end state = whitelist.preprint_arguments_t[cite_class][name]; -- look in the parameter-list for the template identified by cite_class if true == state_test (state, name) then return true; end return false; -- not supported because not found or name is set to nil end -- end limited parameter-set templates if utilities.in_array (cite_class, whitelist.unique_param_template_list_t) then -- template-specific parameters for templates that accept parameters from the basic argument list state = whitelist.unique_arguments_t[cite_class][name]; -- look in the template-specific parameter-lists for the template identified by cite_class if true == state_test (state, name) then return true; end end -- if here, fall into general validation state = whitelist.common_parameters_t[enum_name]; -- all other templates; all normal parameters allowed; this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end return false; -- not supported because not found or name is set to nil end --[=[-------------------------< I N T E R _ W I K I _ C H E C K >---------------------------------------------- check <value> for inter-language interwiki-link markup. <prefix> must be a MediaWiki-recognized language code. when these values have the form (without leading colon): [[<prefix>:link|label]] return label as plain-text [[<prefix>:link]] return <prefix>:link as plain-text return value as is else ]=] local function inter_wiki_check (parameter, value) local prefix = value:match ('%[%[(%a+):'); -- get an interwiki prefix if one exists local _; if prefix and cfg.inter_wiki_map[prefix:lower()] then -- if prefix is in the map, needs preceding colon so utilities.set_message ('err_bad_paramlink', parameter); -- emit an error message _, value, _ = utilities.is_wikilink (value); -- extract label portion from wikilink end return value; end --[[--------------------------< M I S S I N G _ P I P E _ C H E C K >------------------------------------------ Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal sign, compare the alphanumeric string to the list of cs1|2 parameters. If found, then the string is possibly a parameter that is missing its pipe. There are two tests made: {{cite ... |title=Title access-date=2016-03-17}} -- the first parameter has a value and whitespace separates that value from the missing pipe parameter name {{cite ... |title=access-date=2016-03-17}} -- the first parameter has no value (whitespace after the first = is trimmed by MediaWiki) cs1|2 shares some parameter names with XML/HTML attributes: class=, title=, etc. To prevent false positives XML/HTML tags are removed before the search. If a missing pipe is detected, this function adds the missing pipe maintenance category. ]] local function missing_pipe_check (parameter, value) local capture; value = value:gsub ('%b<>', ''); -- remove XML/HTML tags because attributes: class=, title=, etc. capture = value:match ('%s+(%a[%w%-]+)%s*=') or value:match ('^(%a[%w%-]+)%s*='); -- find and categorize parameters with possible missing pipes if capture and validate (capture) then -- if the capture is a valid parameter name utilities.set_message ('err_missing_pipe', parameter); end end --[[--------------------------< H A S _ E X T R A N E O U S _ P U N C T >-------------------------------------- look for extraneous terminal punctuation in most parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_punc (param, value) if 'number' == type (param) then return; end param = param:gsub ('%d+', '#'); -- enumerated name-list mask params allow terminal punct; normalize if cfg.punct_skip[param] then return; -- parameter name found in the skip table so done end if value:match ('[,;:]$') then utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end if value:match ('^=') then -- sometimes an extraneous '=' character appears ... utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end end --[[--------------------------< H A S _ T W L _ U R L >-------------------------------------------------------- look for The Wikipedia Library urls in url-holding parameters. TWL urls are accessible only for readers who are active extended confirmed Wikipedia editors. This function sets an error message when such urls are discovered and when appropriate, sets the |<param>-url-access=subscription. returns nothing. looks for: '.wikipedialibrary.idm.oclc.org' ]] local function has_twl_url (url_params_t, cite_args_t) local url_error_t = {}; -- sequence of url-holding parameters that have a TWL url for param, value in pairs (url_params_t) do if value:find ('%.wikipedialibrary%.idm%.oclc%.org') then -- has the TWL base url? table.insert (url_error_t, param); -- add parameter name to the error list end end if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); -- sor for error messaging for i, param in ipairs (url_error_t) do if cfg.url_access_map_t[param] then -- if <param> has a matching -access parameter cite_args_t[cfg.url_access_map_t[param]] = cfg.keywords_xlate.subscription; -- set |<param>-url-access=subscription end url_error_t[i] = utilities.wrap_style ('parameter', param); -- make the parameter pretty for error message end utilities.set_message ('err_param_has_twl_url', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< H A S _ E X T R A N E O U S _ U R L >------------------------------------------ look for extraneous url parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_url (non_url_param_t) local url_error_t = {}; check_for_url (non_url_param_t, url_error_t); -- extraneous url check if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); utilities.set_message ('err_param_has_ext_link', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< _ C I T A T I O N >------------------------------------------------------------ Module entry point frame – from template call (citation()); may be nil when called from another module args_t – table of all cs1|2 parameters in the template (the parent frame) config_t – table of template-supplied parameter (the #invoke frame) ]] local function _citation (frame, args_t, config_t) -- save a copy in case we need to display an error message in preview mode if not frame then frame = mw.getCurrentFrame(); -- if called from another module, get a frame for frame-provided functions end -- i18n: set the name that your wiki uses to identify sandbox subpages from sandbox template invoke (or can be set here) local sandbox = ((config_t.SandboxPath and '' ~= config_t.SandboxPath) and config_t.SandboxPath) or '/sandbox'; -- sandbox path from {{#invoke:Citation/CS1/sandbox|citation|SandboxPath=/...}} is_sandbox = nil ~= string.find (frame:getTitle(), sandbox, 1, true); -- is this invoke the sandbox module? sandbox = is_sandbox and sandbox or ''; -- use i18n sandbox to load sandbox modules when this module is the sandox; live modules else cfg = mw.loadData ('Module:Citation/CS1/Configuration' .. sandbox); -- load sandbox versions of support modules when {{#invoke:Citation/CS1/sandbox|...}}; live modules else whitelist = mw.loadData ('Module:Citation/CS1/Whitelist' .. sandbox); utilities = require ('Module:Citation/CS1/Utilities' .. sandbox); validation = require ('Module:Citation/CS1/Date_validation' .. sandbox); identifiers = require ('Module:Citation/CS1/Identifiers' .. sandbox); metadata = require ('Module:Citation/CS1/COinS' .. sandbox); utilities.set_selected_modules (cfg); -- so that functions in Utilities can see the selected cfg tables identifiers.set_selected_modules (cfg, utilities); -- so that functions in Identifiers can see the selected cfg tables and selected Utilities module validation.set_selected_modules (cfg, utilities); -- so that functions in Date validataion can see selected cfg tables and the selected Utilities module metadata.set_selected_modules (cfg, utilities); -- so that functions in COinS can see the selected cfg tables and selected Utilities module z = utilities.z; -- table of error and category tables in Module:Citation/CS1/Utilities local cite_args_t = {}; -- because args_t is the parent (template) frame args (which cannot be modified); params and their values will be placed here is_preview_mode = not utilities.is_set (frame:preprocess ('{{REVISIONID}}')); local suggestions = {}; -- table where we store suggestions if we need to loadData them local error_text; -- used as a flag local capture; -- the single supported capture when matching unknown parameters using patterns local empty_unknowns = {}; -- sequence table to hold empty unknown params for error message listing for k, v in pairs (args_t) do -- get parameters from the parent (template) frame v = mw.ustring.gsub (v, '^%s*(.-)%s*$', '%1'); -- trim leading/trailing whitespace; when v is only whitespace, becomes empty string if v ~= '' then if ('string' == type (k)) then k = mw.ustring.gsub (k, '%d', cfg.date_names.local_digits); -- for enumerated parameters, translate 'local' digits to Western 0-9 end if not validate( k, config_t.CitationClass ) then if type (k) ~= 'string' then -- exclude empty numbered parameters if v:match("%S+") ~= nil then error_text = utilities.set_message ('err_text_ignored', {v}); end elseif validate (k:lower(), config_t.CitationClass) then error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, k:lower()}); -- suggest the lowercase version of the parameter else if nil == suggestions.suggestions then -- if this table is nil then we need to load it suggestions = mw.loadData ('Module:Citation/CS1/Suggestions' .. sandbox); --load sandbox version of suggestion module when {{#invoke:Citation/CS1/sandbox|...}}; live module else end for pattern, param in pairs (suggestions.patterns) do -- loop through the patterns to see if we can suggest a proper parameter capture = k:match (pattern); -- the whole match if no capture in pattern else the capture if a match if capture then -- if the pattern matches param = utilities.substitute (param, capture); -- add the capture to the suggested parameter (typically the enumerator) if validate (param, config_t.CitationClass) then -- validate the suggestion to make sure that the suggestion is supported by this template (necessary for limited parameter lists) error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, param}); -- set the suggestion error message else error_text = utilities.set_message ('err_parameter_ignored', {k}); -- suggested param not supported by this template v = ''; -- unset end end end if not utilities.is_set (error_text) then -- couldn't match with a pattern, is there an explicit suggestion? if (suggestions.suggestions[ k:lower() ] ~= nil) and validate (suggestions.suggestions[ k:lower() ], config_t.CitationClass) then utilities.set_message ('err_parameter_ignored_suggest', {k, suggestions.suggestions[ k:lower() ]}); else utilities.set_message ('err_parameter_ignored', {k}); v = ''; -- unset value assigned to unrecognized parameters (this for the limited parameter lists) end end end end cite_args_t[k] = v; -- save this parameter and its value elseif not utilities.is_set (v) then -- for empty parameters if not validate (k, config_t.CitationClass, true) then -- is this empty parameter a valid parameter k = ('' == k) and '(empty string)' or k; -- when k is empty string (or was space(s) trimmed to empty string), replace with descriptive text table.insert (empty_unknowns, utilities.wrap_style ('parameter', k)); -- format for error message and add to the list end end end if 0 ~= #empty_unknowns then -- create empty unknown error message utilities.set_message ('err_param_unknown_empty', { 1 == #empty_unknowns and '' or 's', utilities.make_sep_list (#empty_unknowns, empty_unknowns) }); end local non_url_param_t = {}; -- table of parameters and values that are not url-holding parameters local url_param_t = {}; -- table of url-holding paramters and their values for k, v in pairs (cite_args_t) do if 'string' == type (k) then -- don't evaluate positional parameters has_invisible_chars (k, v); -- look for invisible characters end has_extraneous_punc (k, v); -- look for extraneous terminal punctuation in parameter values missing_pipe_check (k, v); -- do we think that there is a parameter that is missing a pipe? cite_args_t[k] = inter_wiki_check (k, v); -- when language interwiki-linked parameter missing leading colon replace with wiki-link label if 'string' == type (k) then -- when parameter k is not positional if not cfg.url_skip[k] then -- and not in url skip table non_url_param_t[k] = v; -- make a parameter/value list for extraneous url check else -- and is in url skip table (a url-holding parameter) url_param_t[k] = v; -- make a parameter/value list to check for values that are The Wikipedia Library url end end end has_extraneous_url (non_url_param_t); -- look for url in parameter values where a url does not belong has_twl_url (url_param_t, cite_args_t); -- look for url-holding parameters that hold a The Wikipedia Library url return table.concat ({ frame:extensionTag ('templatestyles', '', {src='Module:Citation/CS1' .. sandbox .. '/styles.css'}), citation0 (config_t, cite_args_t) }); end --[[--------------------------< C I T A T I O N >-------------------------------------------------------------- Template entry point ]] local function citation (frame) local config_t = {}; -- table to store parameters from the module {{#invoke:}} local args_t = frame:getParent().args; -- get template's preset parameters for k, v in pairs (frame.args) do -- get parameters from the {{#invoke}} frame config_t[k] = v; -- args_t[k] = v; -- crude debug support that allows us to render a citation from module {{#invoke:}}; skips parameter validation; TODO: keep? end return _citation (frame, args_t, config_t) end --[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------ ]] return { citation = citation, -- template entry point _citation = _citation, -- module entry point } 857bxt7ggh49ge4boheoz4pcyfdwqbh 736730 736729 2026-01-17T19:25:19Z en>Trappist the monk 0 synch from sandbox; 736730 Scribunto text/plain require ('strict'); --[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- each of these counts against the Lua upvalue limit ]] local validation; -- functions in Module:Citation/CS1/Date_validation local utilities; -- functions in Module:Citation/CS1/Utilities local z = {}; -- table of tables in Module:Citation/CS1/Utilities local identifiers; -- functions and tables in Module:Citation/CS1/Identifiers local metadata; -- functions in Module:Citation/CS1/COinS local cfg = {}; -- table of configuration tables that are defined in Module:Citation/CS1/Configuration local whitelist = {}; -- table of tables listing valid template parameter names; defined in Module:Citation/CS1/Whitelist --[[------------------< P A G E S C O P E V A R I A B L E S >--------------- declare variables here that have page-wide scope that are not brought in from other modules; that are created here and used here ]] local added_deprecated_cat; -- Boolean flag so that the category is added only once local added_vanc_errs; -- Boolean flag so we only emit one Vancouver error / category local added_generic_name_errs; -- Boolean flag so we only emit one generic name error / category and stop testing names once an error is encountered local added_numeric_name_errs; -- Boolean flag so we only emit one numeric name error / category and stop testing names once an error is encountered local added_numeric_name_maint; -- Boolean flag so we only emit one numeric name maint category and stop testing names once a category has been emitted local is_preview_mode; -- true when article is in preview mode; false when using 'Preview page with this template' (previewing the module) local is_sandbox; -- true when using sandbox modules to render citation --[[--------------------------< F I R S T _ S E T >------------------------------------------------------------ Locates and returns the first set value in a table of values where the order established in the table, left-to-right (or top-to-bottom), is the order in which the values are evaluated. Returns nil if none are set. This version replaces the original 'for _, val in pairs do' and a similar version that used ipairs. With the pairs version the order of evaluation could not be guaranteed. With the ipairs version, a nil value would terminate the for-loop before it reached the actual end of the list. ]] local function first_set (list, count) local i = 1; while i <= count do -- loop through all items in list if utilities.is_set( list[i] ) then return list[i]; -- return the first set list member end i = i + 1; -- point to next end end --[[--------------------------< A D D _ V A N C _ E R R O R >---------------------------------------------------- Adds a single Vancouver system error message to the template's output regardless of how many error actually exist. To prevent duplication, added_vanc_errs is nil until an error message is emitted. added_vanc_errs is a Boolean declared in page scope variables above ]] local function add_vanc_error (source, position) if added_vanc_errs then return end added_vanc_errs = true; -- note that we've added this category utilities.set_message ('err_vancouver', {source, position}); end --[[--------------------------< I S _ S C H E M E >------------------------------------------------------------ does this thing that purports to be a URI scheme seem to be a valid scheme? The scheme is checked to see if it is in agreement with http://tools.ietf.org/html/std66#section-3.1 which says: Scheme names consist of a sequence of characters beginning with a letter and followed by any combination of letters, digits, plus ("+"), period ("."), or hyphen ("-"). returns true if it does, else false ]] local function is_scheme (scheme) return scheme and scheme:match ('^%a[%a%d%+%.%-]*:'); -- true if scheme is set and matches the pattern end --[=[-------------------------< I S _ D O M A I N _ N A M E >-------------------------------------------------- Does this thing that purports to be a domain name seem to be a valid domain name? Syntax defined here: http://tools.ietf.org/html/rfc1034#section-3.5 BNF defined here: https://tools.ietf.org/html/rfc4234 Single character names are generally reserved; see https://tools.ietf.org/html/draft-ietf-dnsind-iana-dns-01#page-15; see also [[Single-letter second-level domain]] list of TLDs: https://www.iana.org/domains/root/db RFC 952 (modified by RFC 1123) requires the first and last character of a hostname to be a letter or a digit. Between the first and last characters the name may use letters, digits, and the hyphen. Also allowed are IPv4 addresses. IPv6 not supported domain is expected to be stripped of any path so that the last character in the last character of the TLD. tld is two or more alpha characters. Any preceding '//' (from splitting a URL with a scheme) will be stripped here. Perhaps not necessary but retained in case it is necessary for IPv4 dot decimal. There are several tests: the first character of the whole domain name including subdomains must be a letter or a digit internationalized domain name (ASCII characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the TLD) see https://tools.ietf.org/html/rfc3490 single-letter/digit second-level domains in the .org, .cash, and .today TLDs q, x, and z SL domains in the .com TLD i and q SL domains in the .net TLD single-letter SL domains in the ccTLDs (where the ccTLD is two letters) two-character SL domains in gTLDs (where the gTLD is two or more letters) three-plus-character SL domains in gTLDs (where the gTLD is two or more letters) IPv4 dot-decimal address format; TLD not allowed returns true if domain appears to be a proper name and TLD or IPv4 address, else false ]=] local function is_domain_name (domain) if not domain then return false; -- if not set, abandon end domain = domain:gsub ('^//', ''); -- strip '//' from domain name if present; done here so we only have to do it once if not domain:match ('^[%w]') then -- first character must be letter or digit return false; end if domain:match ('^%a+:') then -- hack to detect things that look like s:Page:Title where Page: is namespace at Wikisource return false; end local patterns = { -- patterns that look like URLs '%f[%w][%w][%w%-]+[%w]%.%a%a+$', -- three or more character hostname.hostname or hostname.tld '%f[%w][%w][%w%-]+[%w]%.xn%-%-[%w]+$', -- internationalized domain name with ACE prefix '%f[%a][qxz]%.com$', -- assigned one character .com hostname (x.com times out 2015-12-10) '%f[%a][iq]%.net$', -- assigned one character .net hostname (q.net registered but not active 2015-12-10) '%f[%w][%w]%.%a%a$', -- one character hostname and ccTLD (2 chars) '%f[%w][%w][%w]%.%a%a+$', -- two character hostname and TLD '^%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?', -- IPv4 address '[%a%d]+%:?' -- IPv6 address } for _, pattern in ipairs (patterns) do -- loop through the patterns list if domain:match (pattern) then return true; -- if a match then we think that this thing that purports to be a URL is a URL end end for _, d in ipairs (cfg.single_letter_2nd_lvl_domains_t) do -- look for single letter second level domain names for these top level domains if domain:match ('%f[%w][%w]%.' .. d) then return true end end return false; -- no matches, we don't know what this thing is end --[[--------------------------< I S _ U R L >------------------------------------------------------------------ returns true if the scheme and domain parts of a URL appear to be a valid URL; else false. This function is the last step in the validation process. This function is separate because there are cases that are not covered by split_url(), for example is_parameter_ext_wikilink() which is looking for bracketted external wikilinks. ]] local function is_url (scheme, domain) if utilities.is_set (scheme) then -- if scheme is set check it and domain return is_scheme (scheme) and is_domain_name (domain); else return is_domain_name (domain); -- scheme not set when URL is protocol-relative end end --[[--------------------------< S P L I T _ U R L >------------------------------------------------------------ Split a URL into a scheme, authority indicator, and domain. First remove Fully Qualified Domain Name terminator (a dot following TLD) (if any) and any path(/), query(?) or fragment(#). If protocol-relative URL, return nil scheme and domain else return nil for both scheme and domain. When not protocol-relative, get scheme, authority indicator, and domain. If there is an authority indicator (one or more '/' characters immediately following the scheme's colon), make sure that there are only 2. Any URL that does not have news: scheme must have authority indicator (//). TODO: are there other common schemes like news: that don't use authority indicator? Strip off any port and path; ]] local function split_url (url_str) local scheme, authority, domain; url_str = url_str:gsub ('([%a%d])%.?[/%?#].*$', '%1'); -- strip FQDN terminator and path(/), query(?), fragment (#) (the capture prevents false replacement of '//') if url_str:match ('^//%S*') then -- if there is what appears to be a protocol-relative URL domain = url_str:match ('^//(%S*)') elseif url_str:match ('%S-:/*%S+') then -- if there is what appears to be a scheme, optional authority indicator, and domain name scheme, authority, domain = url_str:match ('(%S-:)(/*)(%S+)'); -- extract the scheme, authority indicator, and domain portions if utilities.is_set (authority) then authority = authority:gsub ('//', '', 1); -- replace place 1 pair of '/' with nothing; if utilities.is_set(authority) then -- if anything left (1 or 3+ '/' where authority should be) then return scheme; -- return scheme only making domain nil which will cause an error message end else if not scheme:match ('^news:') then -- except for news:..., MediaWiki won't link URLs that do not have authority indicator; TODO: a better way to do this test? return scheme; -- return scheme only making domain nil which will cause an error message end end domain = domain:gsub ('(%a):%d+', '%1'); -- strip port number if present end return scheme, domain; end --[[--------------------------< L I N K _ P A R A M _ O K >--------------------------------------------------- checks the content of |title-link=, |series-link=, |author-link=, etc. for properly formatted content: no wikilinks, no URLs Link parameters are to hold the title of a Wikipedia article, so none of the WP:TITLESPECIALCHARACTERS are allowed: # < > [ ] | { } _ except the underscore which is used as a space in wiki URLs and # which is used for section links returns false when the value contains any of these characters. When there are no illegal characters, this function returns TRUE if value DOES NOT appear to be a valid URL (the |<param>-link= parameter is ok); else false when value appears to be a valid URL (the |<param>-link= parameter is NOT ok). ]] local function link_param_ok (value) local scheme, domain; if value:find ('[<>%[%]|{}]') then -- if any prohibited characters return false; end scheme, domain = split_url (value); -- get scheme or nil and domain or nil from URL; return not is_url (scheme, domain); -- return true if value DOES NOT appear to be a valid URL end --[[--------------------------< L I N K _ T I T L E _ O K >--------------------------------------------------- Use link_param_ok() to validate |<param>-link= value and its matching |<title>= value. |<title>= may be wiki-linked but not when |<param>-link= has a value. This function emits an error message when that condition exists check <link> for inter-language interwiki-link prefix. prefix must be a MediaWiki-recognized language code and must begin with a colon. ]] local function link_title_ok (link, lorig, title, torig) local orig; if utilities.is_set (link) then -- don't bother if <param>-link doesn't have a value if not link_param_ok (link) then -- check |<param>-link= markup orig = lorig; -- identify the failing link parameter elseif title:find ('%[%[') then -- check |title= for wikilink markup orig = torig; -- identify the failing |title= parameter elseif link:match ('^%a+:') then -- if the link is what looks like an interwiki local prefix = link:match ('^(%a+):'):lower(); -- get the interwiki prefix if cfg.inter_wiki_map[prefix] then -- if prefix is in the map, must have preceding colon orig = lorig; -- flag as error end end end if utilities.is_set (orig) then link = ''; -- unset utilities.set_message ('err_bad_paramlink', orig); -- URL or wikilink in |title= with |title-link=; end return link; -- link if ok, empty string else end --[[--------------------------< C H E C K _ U R L >------------------------------------------------------------ Determines whether a URL string appears to be valid. First we test for space characters. If any are found, return false. Then split the URL into scheme and domain portions, or for protocol-relative (//example.com) URLs, just the domain. Use is_url() to validate the two portions of the URL. If both are valid, or for protocol-relative if domain is valid, return true, else false. Because it is different from a standard URL, and because this module used external_link() to make external links that work for standard and news: links, we validate newsgroup names here. The specification for a newsgroup name is at https://tools.ietf.org/html/rfc5536#section-3.1.4 ]] local function check_url( url_str ) if nil == url_str:match ("^%S+$") then -- if there are any spaces in |url=value it can't be a proper URL return false; end local scheme, domain; scheme, domain = split_url (url_str); -- get scheme or nil and domain or nil from URL; if 'news:' == scheme then -- special case for newsgroups return domain:match('^[%a%d%+%-_]+%.[%a%d%+%-_%.]*[%a%d%+%-_]$'); end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[=[-------------------------< I S _ P A R A M E T E R _ E X T _ W I K I L I N K >---------------------------- Return true if a parameter value has a string that begins and ends with square brackets [ and ] and the first non-space characters following the opening bracket appear to be a URL. The test will also find external wikilinks that use protocol-relative URLs. Also finds bare URLs. The frontier pattern prevents a match on interwiki-links which are similar to scheme:path URLs. The tests that find bracketed URLs are required because the parameters that call this test (currently |title=, |chapter=, |work=, and |publisher=) may have wikilinks and there are articles or redirects like '//Hus' so, while uncommon, |title=[[//Hus]] is possible as might be [[en://Hus]]. ]=] local function is_parameter_ext_wikilink (value) local scheme, domain; if value:match ('%f[%[]%[%a%S*:%S+.*%]') then -- if ext. wikilink with scheme and domain: [xxxx://yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(%a%S*:%S+).*%]')); elseif value:match ('%f[%[]%[//%S+.*%]') then -- if protocol-relative ext. wikilink: [//yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(//%S+).*%]')); elseif value:match ('%a%S*:%S+') then -- if bare URL with scheme; may have leading or trailing plain text scheme, domain = split_url (value:match ('(%a%S*:%S+)')); elseif value:match ('^//%S+') or value:match ('%s//%S+') then -- if protocol-relative bare URL: //yyyyy.zzz; authority indicator (//) must be be preceded nothing or by whitespace scheme, domain = split_url (value:match ('(//%S+)')); -- what is left should be the domain else return false; -- didn't find anything that is obviously a URL end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[[-------------------------< C H E C K _ F O R _ U R L >----------------------------------------------------- loop through a list of parameters and their values. Look at the value and if it has an external link, emit an error message. ]] local function check_for_url (parameter_list, error_list) for k, v in pairs (parameter_list) do -- for each parameter in the list if is_parameter_ext_wikilink (v) then -- look at the value; if there is a URL add an error message table.insert (error_list, utilities.wrap_style ('parameter', k)); end end end --[[--------------------------< S A F E _ F O R _ U R L >------------------------------------------------------ Escape sequences for content that will be used for URL descriptions ]] local function safe_for_url( str ) if str:match( "%[%[.-%]%]" ) ~= nil then utilities.set_message ('err_wikilink_in_url', {}); end return str:gsub( '[%[%]\n]', { ['['] = '&#91;', [']'] = '&#93;', ['\n'] = ' ' } ); end --[[--------------------------< E X T E R N A L _ L I N K >---------------------------------------------------- Format an external link with error checking ]] local function external_link (URL, label, source, access) local err_msg = ''; local domain; local path; local base_url; if not utilities.is_set (label) then label = URL; if utilities.is_set (source) then utilities.set_message ('err_bare_url_missing_title', {utilities.wrap_style ('parameter', source)}); else error (cfg.messages["bare_url_no_origin"]); -- programmer error; valid parameter name does not have matching meta-parameter end end if not check_url (URL) then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); end domain, path = URL:match ('^([/%.%-%+:%a%d]+)([/%?#].*)$'); -- split the URL into scheme plus domain and path if path then -- if there is a path portion path = path:gsub ('[%[%]]', {['['] = '%5b', [']'] = '%5d'}); -- replace '[' and ']' with their percent-encoded values URL = table.concat ({domain, path}); -- and reassemble end base_url = table.concat ({ "[", URL, " ", safe_for_url (label), "]" }); -- assemble a wiki-markup URL if utilities.is_set (access) then -- access level (subscription, registration, limited) base_url = utilities.substitute (cfg.presentation['ext-link-access-signal'], {cfg.presentation[access].class, cfg.presentation[access].title, base_url}); -- add the appropriate icon end return base_url; end --[[--------------------------< D E P R E C A T E D _ P A R A M E T E R >-------------------------------------- Categorize and emit an error message when the citation contains one or more deprecated parameters. The function includes the offending parameter name to the error message. Only one error message is emitted regardless of the number of deprecated parameters in the citation. added_deprecated_cat is a Boolean declared in page scope variables above ]] local function deprecated_parameter(name) if not added_deprecated_cat then added_deprecated_cat = true; -- note that we've added this category utilities.set_message ('err_deprecated_params', {name}); -- add error message end end --[=[-------------------------< K E R N _ Q U O T E S >-------------------------------------------------------- Apply kerning to open the space between the quote mark provided by the module and a leading or trailing quote mark contained in a |title= or |chapter= parameter's value. This function will positive kern either single or double quotes: "'Unkerned title with leading and trailing single quote marks'" " 'Kerned title with leading and trailing single quote marks' " (in real life the kerning isn't as wide as this example) Double single quotes (italic or bold wiki-markup) are not kerned. Replaces Unicode quote marks in plain text or in the label portion of a [[L|D]] style wikilink with typewriter quote marks regardless of the need for kerning. Unicode quote marks are not replaced in simple [[D]] wikilinks. Call this function for chapter titles, for website titles, etc.; not for book titles. ]=] local function kern_quotes (str) local cap = ''; local wl_type, label, link; wl_type, label, link = utilities.is_wikilink (str); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] if 1 == wl_type then -- [[D]] simple wikilink with or without quote marks if mw.ustring.match (str, '%[%[[\"“”\'‘’].+[\"“”\'‘’]%]%]') then -- leading and trailing quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); str = utilities.substitute (cfg.presentation['kern-right'], str); elseif mw.ustring.match (str, '%[%[[\"“”\'‘’].+%]%]') then -- leading quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); elseif mw.ustring.match (str, '%[%[.+[\"“”\'‘’]%]%]') then -- trailing quote marks str = utilities.substitute (cfg.presentation['kern-right'], str); end else -- plain text or [[L|D]]; text in label variable label = mw.ustring.gsub (label, '[“”]', '\"'); -- replace “” (U+201C & U+201D) with " (typewriter double quote mark) label = mw.ustring.gsub (label, '[‘’]', '\''); -- replace ‘’ (U+2018 & U+2019) with ' (typewriter single quote mark) cap = mw.ustring.match (label, "^([\"\'][^\'].+)"); -- match leading double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-left'], cap); end cap = mw.ustring.match (label, "^(.+[^\'][\"\'])$") -- match trailing double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-right'], cap); end if 2 == wl_type then str = utilities.make_wikilink (link, label); -- reassemble the wikilink else str = label; end end return str; end --[[--------------------------< F O R M A T _ S C R I P T _ V A L U E >---------------------------------------- |script-title= holds title parameters that are not written in Latin-based scripts: Chinese, Japanese, Arabic, Hebrew, etc. These scripts should not be italicized and may be written right-to-left. The value supplied by |script-title= is concatenated onto Title after Title has been wrapped in italic markup. Regardless of language, all values provided by |script-title= are wrapped in <bdi>...</bdi> tags to isolate RTL languages from the English left to right. |script-title= provides a unique feature. The value in |script-title= may be prefixed with a two-character ISO 639-1 language code and a colon: |script-title=ja:*** *** (where * represents a Japanese character) Spaces between the two-character code and the colon and the colon and the first script character are allowed: |script-title=ja : *** *** |script-title=ja: *** *** |script-title=ja :*** *** Spaces preceding the prefix are allowed: |script-title = ja:*** *** The prefix is checked for validity. If it is a valid ISO 639-1 language code, the lang attribute (lang="ja") is added to the <bdi> tag so that browsers can know the language the tag contains. This may help the browser render the script more correctly. If the prefix is invalid, the lang attribute is not added. At this time there is no error message for this condition. Supports |script-title=, |script-chapter=, |script-<periodical>= ]] local function format_script_value (script_value, script_param) local lang=''; -- initialize to empty string local name; if script_value:match('^%l%l%l?%s*:') then -- if first 3 or 4 non-space characters are script language prefix lang = script_value:match('^(%l%l%l?)%s*:%s*%S.*'); -- get the language prefix or nil if there is no script if not utilities.is_set (lang) then utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing title part']}); -- prefix without 'title'; add error message return ''; -- script_value was just the prefix so return empty string end -- if we get this far we have prefix and script name = cfg.lang_tag_remap[lang] or mw.language.fetchLanguageName( lang, cfg.this_wiki_code ); -- get language name so that we can use it to categorize if utilities.is_set (name) then -- is prefix a proper ISO 639-1 language code? script_value = script_value:gsub ('^%l+%s*:%s*', ''); -- strip prefix from script -- is prefix one of these language codes? if utilities.in_array (lang, cfg.script_lang_codes) then utilities.add_prop_cat ('script', {name, lang}) else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['unknown language code']}); -- unknown script-language; add error message end lang = ' lang="' .. lang .. '" '; -- convert prefix into a lang attribute else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['invalid language code']}); -- invalid language code; add error message lang = ''; -- invalid so set lang to empty string end else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing prefix']}); -- no language code prefix; add error message end script_value = utilities.substitute (cfg.presentation['bdi'], {lang, script_value}); -- isolate in case script is RTL return script_value; end --[[--------------------------< S C R I P T _ C O N C A T E N A T E >------------------------------------------ Initially for |title= and |script-title=, this function concatenates those two parameter values after the script value has been wrapped in <bdi> tags. ]] local function script_concatenate (title, script, script_param) if utilities.is_set (script) then script = format_script_value (script, script_param); -- <bdi> tags, lang attribute, categorization, etc.; returns empty string on error if utilities.is_set (script) then title = title .. ' ' .. script; -- concatenate title and script title end end return title; end --[[--------------------------< W R A P _ M S G >-------------------------------------------------------------- Applies additional message text to various parameter values. Supplied string is wrapped using a message_list configuration taking one argument. Supports lower case text for {{citation}} templates. Additional text taken from citation_config.messages - the reason this function is similar to but separate from wrap_style(). ]] local function wrap_msg (key, str, lower) if not utilities.is_set ( str ) then return ""; end if true == lower then local msg; msg = cfg.messages[key]:lower(); -- set the message to lower case before return utilities.substitute ( msg, str ); -- including template text else return utilities.substitute ( cfg.messages[key], str ); end end --[[----------------< W I K I S O U R C E _ U R L _ M A K E >------------------- Makes a Wikisource URL from Wikisource interwiki-link. Returns the URL and appropriate label; nil else. str is the value assigned to |chapter= (or aliases) or |title= or |title-link= ]] local function wikisource_url_make (str) local wl_type, D, L; local ws_url, ws_label; local wikisource_prefix = table.concat ({'https://', cfg.this_wiki_code, '.wikisource.org/wiki/'}); wl_type, D, L = utilities.is_wikilink (str); -- wl_type is 0 (not a wikilink), 1 (simple wikilink), 2 (complex wikilink) if 0 == wl_type then -- not a wikilink; might be from |title-link= str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 1 == wl_type then -- simple wikilink: [[Wikisource:ws article]] str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 2 == wl_type then -- non-so-simple wikilink: [[Wikisource:ws article|displayed text]] ([[L|D]]) str = L:match ('^[Ww]ikisource:(.+)') or L:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_label = D; -- get ws article name from display portion of interwiki link ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title without namespace from link portion of wikilink }); end end if ws_url then ws_url = mw.uri.encode (ws_url, 'WIKI'); -- make a usable URL ws_url = ws_url:gsub ('%%23', '#'); -- undo percent-encoding of fragment marker end return ws_url, ws_label, L or D; -- return proper URL or nil and a label or nil end --[[----------------< F O R M A T _ P E R I O D I C A L >----------------------- Format the three periodical parameters: |script-<periodical>=, |<periodical>=, and |trans-<periodical>= into a single Periodical meta-parameter. ]] local function format_periodical (script_periodical, script_periodical_source, periodical, trans_periodical) if not utilities.is_set (periodical) then periodical = ''; -- to be safe for concatenation else periodical = utilities.wrap_style ('italic-title', periodical); -- style end periodical = script_concatenate (periodical, script_periodical, script_periodical_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (trans_periodical) then trans_periodical = utilities.wrap_style ('trans-italic-title', trans_periodical); if utilities.is_set (periodical) then periodical = periodical .. ' ' .. trans_periodical; else -- here when trans-periodical without periodical or script-periodical periodical = trans_periodical; utilities.set_message ('err_trans_missing_title', {'periodical'}); end end return periodical; end --[[------------------< F O R M A T _ C H A P T E R _ T I T L E >--------------- Format the four chapter parameters: |script-chapter=, |chapter=, |trans-chapter=, and |chapter-url= into a single chapter meta- parameter (chapter_url_source used for error messages). ]] local function format_chapter_title (script_chapter, script_chapter_source, chapter, chapter_source, trans_chapter, trans_chapter_source, chapter_url, chapter_url_source, no_quotes, access) local ws_url, ws_label, L = wikisource_url_make (chapter); -- make a wikisource URL and label from a wikisource interwiki link if ws_url then ws_label = ws_label:gsub ('_', ' '); -- replace underscore separators with space characters chapter = ws_label; end if not utilities.is_set (chapter) then chapter = ''; -- to be safe for concatenation else if false == no_quotes then chapter = kern_quotes (chapter); -- if necessary, separate chapter title's leading and trailing quote marks from module provided quote marks chapter = utilities.wrap_style ('quoted-title', chapter); end end chapter = script_concatenate (chapter, script_chapter, script_chapter_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (chapter_url) then chapter = external_link (chapter_url, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate elseif ws_url then chapter = external_link (ws_url, chapter .. '&nbsp;', 'ws link in chapter'); -- adds bare_url_missing_title error if appropriate; space char to move icon away from chap text; TODO: better way to do this? chapter = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, chapter}); end if utilities.is_set (trans_chapter) then trans_chapter = utilities.wrap_style ('trans-quoted-title', trans_chapter); if utilities.is_set (chapter) then chapter = chapter .. ' ' .. trans_chapter; else -- here when trans_chapter without chapter or script-chapter chapter = trans_chapter; chapter_source = trans_chapter_source:match ('trans%-?(.+)'); -- when no chapter, get matching name from trans-<param> utilities.set_message ('err_trans_missing_title', {chapter_source}); end end return chapter; end --[[----------------< H A S _ I N V I S I B L E _ C H A R S >------------------- This function searches a parameter's value for non-printable or invisible characters. The search stops at the first match. This function will detect the visible replacement character when it is part of the Wikisource. Detects but ignores nowiki and math stripmarkers. Also detects other named stripmarkers (gallery, math, pre, ref) and identifies them with a slightly different error message. See also coins_cleanup(). Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker that was detected along with its position (or, for multi-byte characters, the position of its first byte) in the parameter value. ]] local function has_invisible_chars (param, v) local position = ''; -- position of invisible char or starting position of stripmarker local capture; -- used by stripmarker detection to hold name of the stripmarker local stripmarker; -- boolean set true when a stripmarker is found capture = string.match (v, '[%w%p ]*'); -- test for values that are simple ASCII text and bypass other tests if true if capture == v then -- if same there are no Unicode characters return; end for _, invisible_char in ipairs (cfg.invisible_chars) do local char_name = invisible_char[1]; -- the character or group name local pattern = invisible_char[2]; -- the pattern used to find it position, _, capture = mw.ustring.find (v, pattern); -- see if the parameter value contains characters that match the pattern if position and (cfg.invisible_defs.zwj == capture) then -- if we found a zero-width joiner character if mw.ustring.find (v, cfg.indic_script) then -- it's ok if one of the Indic scripts position = nil; -- unset position elseif cfg.emoji_t[mw.ustring.codepoint (v, position+1)] then -- is zwj followed by a character listed in emoji{}? position = nil; -- unset position end end if position then if 'nowiki' == capture or 'math' == capture or -- nowiki and math stripmarkers (not an error condition) ('templatestyles' == capture and utilities.in_array (param, {'id', 'quote'})) then -- templatestyles stripmarker allowed in these parameters stripmarker = true; -- set a flag elseif true == stripmarker and cfg.invisible_defs.del == capture then -- because stripmakers begin and end with the delete char, assume that we've found one end of a stripmarker position = nil; -- unset else local err_msg; if capture and not (cfg.invisible_defs.del == capture or cfg.invisible_defs.zwj == capture) then err_msg = utilities.substitute (cfg.messages.invisible_1, {capture, char_name}); -- <capture> here is stripmarker name else err_msg = utilities.substitute (cfg.messages.invisible_2, char_name); end utilities.set_message ('err_invisible_char', {err_msg, utilities.wrap_style ('parameter', param), position}); -- add error message return; -- and done with this parameter end end end end --[[-------------------< A R G U M E N T _ W R A P P E R >---------------------- Argument wrapper. This function provides support for argument mapping defined in the configuration file so that multiple names can be transparently aliased to single internal variable. ]] local function argument_wrapper ( args ) local origin = {}; return setmetatable({ ORIGIN = function ( self, k ) local dummy = self[k]; -- force the variable to be loaded. return origin[k]; end }, { __index = function ( tbl, k ) if origin[k] ~= nil then return nil; end local args, list, v = args, cfg.aliases[k]; if type( list ) == 'table' then v, origin[k] = utilities.select_one ( args, list, 'err_redundant_parameters' ); if origin[k] == nil then origin[k] = ''; -- Empty string, not nil end elseif list ~= nil then v, origin[k] = args[list], list; else -- maybe let through instead of raising an error? -- v, origin[k] = args[k], k; error( cfg.messages['unknown_argument_map'] .. ': ' .. k); end -- Empty strings, not nil; if v == nil then v = ''; origin[k] = ''; end tbl = rawset( tbl, k, v ); return v; end, }); end --[[--------------------------< N O W R A P _ D A T E >------------------------- When date is YYYY-MM-DD format wrap in nowrap span: <span ...>YYYY-MM-DD</span>. When date is DD MMMM YYYY or is MMMM DD, YYYY then wrap in nowrap span: <span ...>DD MMMM</span> YYYY or <span ...>MMMM DD,</span> YYYY DOES NOT yet support MMMM YYYY or any of the date ranges. ]] local function nowrap_date (date) local cap = ''; local cap2 = ''; if date:match("^%d%d%d%d%-%d%d%-%d%d$") then date = utilities.substitute (cfg.presentation['nowrap1'], date); elseif date:match("^%a+%s*%d%d?,%s+%d%d%d%d$") or date:match ("^%d%d?%s*%a+%s+%d%d%d%d$") then cap, cap2 = string.match (date, "^(.*)%s+(%d%d%d%d)$"); date = utilities.substitute (cfg.presentation['nowrap2'], {cap, cap2}); end return date; end --[[--------------------------< S E T _ T I T L E T Y P E >--------------------- This function sets default title types (equivalent to the citation including |type=<default value>) for those templates that have defaults. Also handles the special case where it is desirable to omit the title type from the rendered citation (|type=none). ]] local function set_titletype (cite_class, title_type) if utilities.is_set (title_type) then if 'none' == cfg.keywords_xlate[title_type] then title_type = ''; -- if |type=none then type parameter not displayed end return title_type; -- if |type= has been set to any other value use that value end return cfg.title_types [cite_class] or ''; -- set template's default title type; else empty string for concatenation end --[[--------------------------< S A F E _ J O I N >----------------------------- Joins a sequence of strings together while checking for duplicate separation characters. ]] local function safe_join( tbl, duplicate_char ) local f = {}; -- create a function table appropriate to type of 'duplicate character' if 1 == #duplicate_char then -- for single byte ASCII characters use the string library functions f.gsub = string.gsub f.match = string.match f.sub = string.sub else -- for multi-byte characters use the ustring library functions f.gsub = mw.ustring.gsub f.match = mw.ustring.match f.sub = mw.ustring.sub end local str = ''; -- the output string local comp = ''; -- what does 'comp' mean? local end_chr = ''; local trim; for _, value in ipairs( tbl ) do if value == nil then value = ''; end if str == '' then -- if output string is empty str = value; -- assign value to it (first time through the loop) elseif value ~= '' then if value:sub(1, 1) == '<' then -- special case of values enclosed in spans and other markup. comp = value:gsub( "%b<>", "" ); -- remove HTML markup (<span>string</span> -> string) else comp = value; end -- typically duplicate_char is sepc if f.sub(comp, 1, 1) == duplicate_char then -- is first character same as duplicate_char? why test first character? -- Because individual string segments often (always?) begin with terminal punct for the -- preceding segment: 'First element' .. 'sepc next element' .. etc.? trim = false; end_chr = f.sub(str, -1, -1); -- get the last character of the output string -- str = str .. "<HERE(enchr=" .. end_chr .. ")" -- debug stuff? if end_chr == duplicate_char then -- if same as separator str = f.sub(str, 1, -2); -- remove it elseif end_chr == "'" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "''" then -- if last three chars of str are sepc'' str = f.sub(str, 1, -4) .. "''"; -- remove them and add back '' elseif f.sub(str, -5, -1) == duplicate_char .. "]]''" then -- if last five chars of str are sepc]]'' trim = true; -- why? why do this and next differently from previous? elseif f.sub(str, -4, -1) == duplicate_char .. "]''" then -- if last four chars of str are sepc]'' trim = true; -- same question end elseif end_chr == "]" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "]]" then -- if last three chars of str are sepc]] wikilink trim = true; elseif f.sub(str, -3, -1) == duplicate_char .. '"]' then -- if last three chars of str are sepc"] quoted external link trim = true; elseif f.sub(str, -2, -1) == duplicate_char .. "]" then -- if last two chars of str are sepc] external link trim = true; elseif f.sub(str, -4, -1) == duplicate_char .. "'']" then -- normal case when |url=something & |title=Title. trim = true; end elseif end_chr == " " then -- if last char of output string is a space if f.sub(str, -2, -1) == duplicate_char .. " " then -- if last two chars of str are <sepc><space> str = f.sub(str, 1, -3); -- remove them both end end if trim then if value ~= comp then -- value does not equal comp when value contains HTML markup local dup2 = duplicate_char; if f.match(dup2, "%A" ) then dup2 = "%" .. dup2; end -- if duplicate_char not a letter then escape it value = f.gsub(value, "(%b<>)" .. dup2, "%1", 1 ) -- remove duplicate_char if it follows HTML markup else value = f.sub(value, 2, -1 ); -- remove duplicate_char when it is first character end end end str = str .. value; -- add it to the output string end end return str; end --[[--------------------------< I S _ S U F F I X >----------------------------- returns true if suffix is properly formed Jr, Sr, or ordinal in the range 1–9. Puncutation not allowed. ]] local function is_suffix (suffix) if utilities.in_array (suffix, {'Jr', 'Sr', 'Jnr', 'Snr', '1st', '2nd', '3rd'}) or suffix:match ('^%dth$') then return true; end return false; end --[[--------------------< I S _ G O O D _ V A N C _ N A M E >------------------- For Vancouver style, author/editor names are supposed to be rendered in Latin (read ASCII) characters. When a name uses characters that contain diacritical marks, those characters are to be converted to the corresponding Latin character. When a name is written using a non-Latin alphabet or logogram, that name is to be transliterated into Latin characters. The module doesn't do this so editors may/must. This test allows |first= and |last= names to contain any of the letters defined in the four Unicode Latin character sets [http://www.unicode.org/charts/PDF/U0000.pdf C0 Controls and Basic Latin] 0041–005A, 0061–007A [http://www.unicode.org/charts/PDF/U0080.pdf C1 Controls and Latin-1 Supplement] 00C0–00D6, 00D8–00F6, 00F8–00FF [http://www.unicode.org/charts/PDF/U0100.pdf Latin Extended-A] 0100–017F [http://www.unicode.org/charts/PDF/U0180.pdf Latin Extended-B] 0180–01BF, 01C4–024F |lastn= also allowed to contain hyphens, spaces, and apostrophes. (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) |firstn= also allowed to contain hyphens, spaces, apostrophes, and periods This original test: if nil == mw.ustring.find (last, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%'%.]+[2-6%a]*$") then was written outside of the code editor and pasted here because the code editor gets confused between character insertion point and cursor position. The test has been rewritten to use decimal character escape sequence for the individual bytes of the Unicode characters so that it is not necessary to use an external editor to maintain this code. \195\128-\195\150 – À-Ö (U+00C0–U+00D6 – C0 controls) \195\152-\195\182 – Ø-ö (U+00D8-U+00F6 – C0 controls) \195\184-\198\191 – ø-ƿ (U+00F8-U+01BF – C0 controls, Latin extended A & B) \199\132-\201\143 – DŽ-ɏ (U+01C4-U+024F – Latin extended B) ]] local function is_good_vanc_name (last, first, suffix, position) if not suffix then if first:find ('[,%s]') then -- when there is a space or comma, might be first name/initials + generational suffix first = first:match ('(.-)[,%s]+'); -- get name/initials suffix = first:match ('[,%s]+(.+)$'); -- get generational suffix end end if utilities.is_set (suffix) then if not is_suffix (suffix) then add_vanc_error (cfg.err_msg_supl.suffix, position); return false; -- not a name with an appropriate suffix end end if nil == mw.ustring.find (last, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%'%.]*$") then add_vanc_error (cfg.err_msg_supl['non-Latin char'], position); return false; -- not a string of Latin characters; Vancouver requires Romanization end; return true; end --[[--------------------------< R E D U C E _ T O _ I N I T I A L S >------------------------------------------ Attempts to convert names to initials in support of |name-list-style=vanc. Names in |firstn= may be separated by spaces or hyphens, or for initials, a period. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35062/. Vancouver style requires family rank designations (Jr, II, III, etc.) to be rendered as Jr, 2nd, 3rd, etc. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35085/. This code only accepts and understands generational suffix in the Vancouver format because Roman numerals look like, and can be mistaken for, initials. This function uses ustring functions because firstname initials may be any of the Unicode Latin characters accepted by is_good_vanc_name (). ]] local function reduce_to_initials (first, position) if first:find (',', 1, true) then return first; -- commas not allowed; abandon end local name, suffix = mw.ustring.match (first, "^(%u+) ([%dJS][%drndth]+)$"); if not name then -- if not initials and a suffix name = mw.ustring.match (first, "^(%u+)$"); -- is it just initials? end if name then -- if first is initials with or without suffix if 3 > mw.ustring.len (name) then -- if one or two initials if suffix then -- if there is a suffix if is_suffix (suffix) then -- is it legitimate? return first; -- one or two initials and a valid suffix so nothing to do else add_vanc_error (cfg.err_msg_supl.suffix, position); -- one or two initials with invalid suffix so error message return first; -- and return first unmolested end else return first; -- one or two initials without suffix; nothing to do end end end -- if here then name has 3 or more uppercase letters so treat them as a word local initials_t, names_t = {}, {}; -- tables to hold name parts and initials local i = 1; -- counter for number of initials names_t = mw.text.split (first, '[%s%-]+'); -- split into a sequence of names and possible suffix while names_t[i] do -- loop through the sequence if 1 < i and names_t[i]:match ('[%dJS][%drndth]+%.?$') then -- if not the first name, and looks like a suffix (may have trailing dot) names_t[i] = names_t[i]:gsub ('%.', ''); -- remove terminal dot if present if is_suffix (names_t[i]) then -- if a legitimate suffix table.insert (initials_t, ' ' .. names_t[i]); -- add a separator space, insert at end of initials sequence break; -- and done because suffix must fall at the end of a name end -- no error message if not a suffix; possibly because of Romanization end if 3 > i then table.insert (initials_t, mw.ustring.sub (names_t[i], 1, 1)); -- insert the initial at end of initials sequence end i = i + 1; -- bump the counter end return table.concat (initials_t); -- Vancouver format does not include spaces. end --[[--------------------------< I N T E R W I K I _ P R E F I X E N _ G E T >---------------------------------- extract interwiki prefixen from <value>. Returns two one or two values: false – no prefixen nil – prefix exists but not recognized project prefix, language prefix – when value has either of: :<project>:<language>:<article> :<language>:<project>:<article> project prefix, nil – when <value> has only a known single-letter prefix nil, language prefix – when <value> has only a known language prefix accepts single-letter project prefixen: 'd' (wikidata), 's' (wikisource), and 'w' (wikipedia) prefixes; at this writing, the other single-letter prefixen (b (wikibook), c (commons), m (meta), n (wikinews), q (wikiquote), and v (wikiversity)) are not supported. ]] local function interwiki_prefixen_get (value, is_link) if not value:find (':%l+:') then -- if no prefix return false; -- abandon; boolean here to distinguish from nil fail returns later end local prefix_patterns_linked_t = { -- sequence of valid interwiki and inter project prefixen '^%[%[:([dsw]):(%l%l+):', -- wikilinked; project and language prefixes '^%[%[:(%l%l+):([dsw]):', -- wikilinked; language and project prefixes '^%[%[:([dsw]):', -- wikilinked; project prefix '^%[%[:(%l%l+):', -- wikilinked; language prefix } local prefix_patterns_unlinked_t = { -- sequence of valid interwiki and inter project prefixen '^:([dsw]):(%l%l+):', -- project and language prefixes '^:(%l%l+):([dsw]):', -- language and project prefixes '^:([dsw]):', -- project prefix '^:(%l%l+):', -- language prefix } local cap1, cap2; for _, pattern in ipairs ((is_link and prefix_patterns_linked_t) or prefix_patterns_unlinked_t) do cap1, cap2 = value:match (pattern); if cap1 then break; -- found a match so stop looking end end if cap1 and cap2 then -- when both then :project:language: or :language:project: (both forms allowed) if 1 == #cap1 then -- length == 1 then :project:language: if cfg.inter_wiki_map[cap2] then -- is language prefix in the interwiki map? return cap1, cap2; -- return interwiki project and interwiki language end else -- here when :language:project: if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return cap2, cap1; -- return interwiki project and interwiki language end end return nil; -- unknown interwiki language elseif not (cap1 or cap2) then -- both are nil? return nil; -- we got something that looks like a project prefix but isn't; return fail elseif 1 == #cap1 then -- here when one capture return cap1, nil; -- length is 1 so return project, nil language else -- here when one capture and its length it more than 1 if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return nil, cap1; -- return nil project, language end end end --[[--------------------------< L I S T _ P E O P L E >-------------------------- Formats a list of people (authors, contributors, editors, interviewers, translators) names in the list will be linked when |<name>-link= has a value |<name>-mask- does NOT have a value; masked names are presumed to have been rendered previously so should have been linked there when |<name>-mask=0, the associated name is not rendered ]] local function list_people (control, people, etal) local sep; local namesep; local format = control.format; local maximum = control.maximum; local name_list = {}; if 'vanc' == format then -- Vancouver-like name styling? sep = cfg.presentation['sep_nl_vanc']; -- name-list separator between names is a comma namesep = cfg.presentation['sep_name_vanc']; -- last/first separator is a space else sep = cfg.presentation['sep_nl']; -- name-list separator between names is a semicolon namesep = cfg.presentation['sep_name']; -- last/first separator is <comma><space> end if sep:sub (-1, -1) ~= " " then sep = sep .. " " end if utilities.is_set (maximum) and maximum < 1 then return "", 0; end -- returned 0 is for EditorCount; not used for other names for i, person in ipairs (people) do if utilities.is_set (person.last) then local mask = person.mask; local one; local sep_one = sep; if utilities.is_set (maximum) and i > maximum then etal = true; break; end if mask then local n = tonumber (mask); -- convert to a number if it can be converted; nil else if n then one = 0 ~= n and string.rep("&mdash;", n) or nil; -- make a string of (n > 0) mdashes, nil else, to replace name person.link = nil; -- don't create link to name if name is replaces with mdash string or has been set nil else one = mask; -- replace name with mask text (must include name-list separator) sep_one = " "; -- modify name-list separator end else one = person.last; -- get surname local first = person.first -- get given name if utilities.is_set (first) then if ("vanc" == format) then -- if Vancouver format one = one:gsub ('%.', ''); -- remove periods from surnames (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) if not person.corporate and is_good_vanc_name (one, first, nil, i) then -- and name is all Latin characters; corporate authors not tested first = reduce_to_initials (first, i); -- attempt to convert first name(s) to initials end end one = one .. namesep .. first; end end if utilities.is_set (person.link) then one = utilities.make_wikilink (person.link, one); -- link author/editor end if one then -- if <one> has a value (name, mdash replacement, or mask text replacement) local proj, tag = interwiki_prefixen_get (one, true); -- get the interwiki prefixen if present if 'w' == proj and ('Wikipedia' == mw.site.namespaces.Project['name']) then proj = nil; -- for stuff like :w:de:<article>, :w is unnecessary TODO: maint cat? end if proj then local proj_name = ({['d'] = cfg.messages.wikidata, ['s'] = cfg.messages.wikisource, ['w'] = cfg.messages.wikipedia})[proj]; -- :w (wikipedia) for linking from a non-wikipedia project if proj_name then one = one .. utilities.wrap_style ('interproj', proj_name); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interproj-linked-name', proj); -- categorize it; <proj> is sort key tag = nil; -- unset; don't do both project and language end end if tag == cfg.this_wiki_code then tag = nil; -- stuff like :en:<article> at en.wiki is pointless TODO: maint cat? end if tag then local lang = cfg.lang_tag_remap[tag] or cfg.mw_languages_by_tag_t[tag]; if lang then -- error messaging done in extract_names() where we know parameter names one = one .. utilities.wrap_style ('interwiki', lang); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interwiki-linked-name', tag); -- categorize it; <tag> is sort key end end table.insert (name_list, one); -- add it to the list of names table.insert (name_list, sep_one); -- add the proper name-list separator end end end local count = #name_list / 2; -- (number of names + number of separators) divided by 2 if 0 < count then if 1 < count and not etal then if 'amp' == format then name_list[#name_list-2] = " & "; -- replace last separator with ampersand text elseif 'and' == format then if 2 == count then name_list[#name_list-2] = cfg.presentation.sep_nl_and; -- replace last separator with 'and' text else name_list[#name_list-2] = cfg.presentation.sep_nl_end; -- replace last separator with '(sep) and' text end end end name_list[#name_list] = nil; -- erase the last separator end local result = table.concat (name_list); -- construct list if etal and utilities.is_set (result) then -- etal may be set by |display-authors=etal but we might not have a last-first list result = result .. sep .. cfg.messages['et al']; -- we've got a last-first list and etal so add et al. end return result, count; -- return name-list string and count of number of names (count used for editor names only) end --[[--------------------< M A K E _ C I T E R E F _ I D >----------------------- Generates a CITEREF anchor ID if we have at least one name or a date. Otherwise returns an empty string. namelist is one of the contributor-, author-, or editor-name lists chosen in that order. year is Year or anchor_year. ]] local function make_citeref_id (namelist, year) local names={}; -- a table for the one to four names and year for i,v in ipairs (namelist) do -- loop through the list and take up to the first four last names names[i] = v.last if i == 4 then break end -- if four then done end table.insert (names, year); -- add the year at the end local id = table.concat(names); -- concatenate names and year for CITEREF id if utilities.is_set (id) then -- if concatenation is not an empty string return "CITEREF" .. id; -- add the CITEREF portion else return ''; -- return an empty string; no reason to include CITEREF id in this citation end end --[[--------------------------< C I T E _ C L A S S _A T T R I B U T E _M A K E >------------------------------ construct <cite> tag class attribute for this citation. <cite_class> – config.CitationClass from calling template <mode> – value from |mode= parameter ]] local function cite_class_attribute_make (cite_class, mode) local class_t = {}; table.insert (class_t, 'citation'); -- required for blue highlight if 'citation' ~= cite_class then table.insert (class_t, cite_class); -- identify this template for user css table.insert (class_t, utilities.is_set (mode) and mode or 'cs1'); -- identify the citation style for user css or javascript else table.insert (class_t, utilities.is_set (mode) and mode or 'cs2'); -- identify the citation style for user css or javascript end for _, prop_key in ipairs (z.prop_keys_t) do table.insert (class_t, prop_key); -- identify various properties for user css or javascript end return table.concat (class_t, ' '); -- make a big string and done end --[[---------------------< N A M E _ H A S _ E T A L >-------------------------- Evaluates the content of name parameters (author, editor, etc.) for variations on the theme of et al. If found, the et al. is removed, a flag is set to true and the function returns the modified name and the flag. This function never sets the flag to false but returns its previous state because it may have been set by previous passes through this function or by the associated |display-<names>=etal parameter ]] local function name_has_etal (name, etal, nocat, param) if utilities.is_set (name) then -- name can be nil in which case just return local patterns = cfg.et_al_patterns; -- get patterns from configuration for _, pattern in ipairs (patterns) do -- loop through all of the patterns if name:match (pattern) then -- if this 'et al' pattern is found in name name = name:gsub (pattern, ''); -- remove the offending text etal = true; -- set flag (may have been set previously here or by |display-<names>=etal) if not nocat then -- no categorization for |vauthors= utilities.set_message ('err_etal', {param}); -- and set an error if not added end end end end return name, etal; end --[[---------------------< N A M E _ I S _ N U M E R I C >---------------------- Add an error message and category when <name> parameter value does not contain letters. Add a maintenance category when <name> parameter value has numeric characters mixed with characters that are not numeric characters; could be letters and/or punctuation characters. This function will only emit one error and one maint message for the current template. Does not emit both error and maint messages/categories for the same parameter value. returns nothing ]] local function name_is_numeric (name, name_alias, list_name) local patterns = { '^%D+%d', -- <name> must have digits preceded by other characters '^%D*%d+%D+', -- <name> must have digits followed by other characters } if not added_numeric_name_errs and mw.ustring.match (name, '^[%A]+$') then -- if we have not already set an error message and <name> does not have any alpha characters utilities.set_message ('err_numeric_names', name_alias); -- add an error message added_numeric_name_errs = true; -- set the flag so we emit only one error message return; -- when here no point in further testing; abandon end if not added_numeric_name_maint then -- if we have already set a maint message for _, pattern in ipairs (patterns) do -- spin through list of patterns if mw.ustring.match (name, pattern) then -- digits preceded or followed by anything but digits; %D+ includes punctuation utilities.set_message ('maint_numeric_names', cfg.special_case_translation [list_name]); -- add a maint cat for this template added_numeric_name_maint = true; -- set the flag so we emit only one maint message return; -- when here no point in further testing; abandon end end end end --[[-----------------< N A M E _ H A S _ M U L T _ N A M E S >------------------ Evaluates the content of last/surname (authors etc.) parameters for multiple names. Multiple names are indicated if there is more than one comma or any "unescaped" semicolons. Escaped semicolons are ones used as part of selected HTML entities. If the condition is met, the function adds the multiple name maintenance category. Same test for first except that commas should not appear in given names (MOS:JR says that the generational suffix does not take a separator character). Titles, degrees, postnominals, affiliations, all normally comma separated don't belong in a citation. <name> – name parameter value <list_name> – AuthorList, EditorList, etc <limit> – number of allowed commas; 1 (default) for surnames; 0 for given names returns nothing ]] local function name_has_mult_names (name, list_name, limit) local _, commas, semicolons, nbsps; limit = limit and limit or 1; if utilities.is_set (name) then _, commas = name:gsub (',', ''); -- count the number of commas _, semicolons = name:gsub (';', ''); -- count the number of semicolons -- nbsps probably should be its own separate count rather than merged in -- some way with semicolons because Lua patterns do not support the -- grouping operator that regex does, which means there is no way to add -- more entities to escape except by adding more counts with the new -- entities _, nbsps = name:gsub ('&nbsp;',''); -- count nbsps -- There is exactly 1 semicolon per &nbsp; entity, so subtract nbsps -- from semicolons to 'escape' them. If additional entities are added, -- they also can be subtracted. if limit < commas or 0 < (semicolons - nbsps) then utilities.set_message ('maint_mult_names', cfg.special_case_translation [list_name]); -- add a maint message end end end --[=[-------------------------< I S _ G E N E R I C >---------------------------------------------------------- Compares values assigned to various parameters according to the string provided as <item> in the function call. <item> can have on of two values: 'generic_names' – for name-holding parameters: |last=, |first=, |editor-last=, etc 'generic_titles' – for |title= There are two types of generic tests. The 'accept' tests look for a pattern that should not be rejected by the 'reject' test. For example, |author=[[John Smith (author)|Smith, John]] would be rejected by the 'author' reject test. But piped wikilinks with 'author' disambiguation should not be rejected so the 'accept' test prevents that from happening. Accept tests are always performed before reject tests. Each of the 'accept' and 'reject' sequence tables hold tables for en.wiki (['en']) and local.wiki (['local']) that each can hold a test sequence table The sequence table holds, at index [1], a test pattern, and, at index [2], a boolean control value. The control value tells string.find() or mw.ustring.find() to do plain-text search (true) or a pattern search (false). The intent of all this complexity is to make these searches as fast as possible so that we don't run out of processing time on very large articles. Returns true when a reject test finds the pattern or string false when an accept test finds the pattern or string nil else ]=] local function is_generic (item, value, wiki) local test_val; local str_lower = { -- use string.lower() for en.wiki (['en']) and use mw.ustring.lower() or local.wiki (['local']) ['en'] = string.lower, ['local'] = mw.ustring.lower, } local str_find = { -- use string.find() for en.wiki (['en']) and use mw.ustring.find() or local.wiki (['local']) ['en'] = string.find, ['local'] = mw.ustring.find, } local function test (val, test_t, wiki) -- local function to do the testing; <wiki> selects lower() and find() functions val = test_t[2] and str_lower[wiki](value) or val; -- when <test_t[2]> set to 'true', plaintext search using lowercase value return str_find[wiki] (val, test_t[1], 1, test_t[2]); -- return nil when not found or matched end local test_types_t = {'accept', 'reject'}; -- test accept patterns first, then reject patterns local wikis_t = {'en', 'local'}; -- do tests for each of these keys; en.wiki first, local.wiki second for _, test_type in ipairs (test_types_t) do -- for each test type for _, generic_value in pairs (cfg.special_case_translation[item][test_type]) do -- spin through the list of generic value fragments to accept or reject for _, wiki in ipairs (wikis_t) do if generic_value[wiki] then if test (value, generic_value[wiki], wiki) then -- go do the test return ('reject' == test_type); -- param value rejected, return true; false else end end end end end end --[[--------------------------< N A M E _ I S _ G E N E R I C >------------------------------------------------ calls is_generic() to determine if <name> is a 'generic name' listed in cfg.generic_names; <name_alias> is the parameter name used in error messaging ]] local function name_is_generic (name, name_alias) if not added_generic_name_errs and is_generic ('generic_names', name) then utilities.set_message ('err_generic_name', name_alias); -- set an error message added_generic_name_errs = true; end end --[[--------------------------< N A M E _ C H E C K S >-------------------------------------------------------- This function calls various name checking functions used to validate the content of the various name-holding parameters. ]] local function name_checks (last, first, list_name, last_alias, first_alias) local accept_name; if utilities.is_set (last) then last, accept_name = utilities.has_accept_as_written (last); -- remove accept-this-as-written markup when it wraps all of <last> if not accept_name then -- <last> not wrapped in accept-as-written markup name_has_mult_names (last, list_name); -- check for multiple names in the parameter name_is_numeric (last, last_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (last, last_alias); -- check for names found in the generic names list end end if utilities.is_set (first) then first, accept_name = utilities.has_accept_as_written (first); -- remove accept-this-as-written markup when it wraps all of <first> if not accept_name then -- <first> not wrapped in accept-as-written markup name_has_mult_names (first, list_name, 0); -- check for multiple names in the parameter; 0 is number of allowed commas in a given name name_is_numeric (first, first_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (first, first_alias); -- check for names found in the generic names list end local wl_type, D = utilities.is_wikilink (first); if 0 ~= wl_type then first = D; utilities.set_message ('err_bad_paramlink', first_alias); end end return last, first; -- done end --[[----------------------< E X T R A C T _ N A M E S >------------------------- Gets name list from the input arguments Searches through args in sequential order to find |lastn= and |firstn= parameters (or their aliases), and their matching link and mask parameters. Stops searching when both |lastn= and |firstn= are not found in args after two sequential attempts: found |last1=, |last2=, and |last3= but doesn't find |last4= and |last5= then the search is done. This function emits an error message when there is a |firstn= without a matching |lastn=. When there are 'holes' in the list of last names, |last1= and |last3= are present but |last2= is missing, an error message is emitted. |lastn= is not required to have a matching |firstn=. When an author or editor parameter contains some form of 'et al.', the 'et al.' is stripped from the parameter and a flag (etal) returned that will cause list_people() to add the static 'et al.' text from Module:Citation/CS1/Configuration. This keeps 'et al.' out of the template's metadata. When this occurs, an error is emitted. ]] local function extract_names(args, list_name) local names = {}; -- table of names local last; -- individual name components local first; local link; local mask; local i = 1; -- loop counter/indexer local n = 1; -- output table indexer local count = 0; -- used to count the number of times we haven't found a |last= (or alias for authors, |editor-last or alias for editors) local etal = false; -- return value set to true when we find some form of et al. in an author parameter local last_alias, first_alias, link_alias; -- selected parameter aliases used in error messaging while true do last, last_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'err_redundant_parameters', i ); -- search through args for name components beginning at 1 first, first_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'err_redundant_parameters', i ); link, link_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ); mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); if last then -- error check |lastn= alias for unknown interwiki link prefix; done here because this is where we have the parameter name local project, language = interwiki_prefixen_get (last, true); -- true because we expect interwiki links in |lastn= to be wikilinked if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', last_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? last = utilities.remove_wiki_link (last); -- remove wikilink markup; show display value only end end if link then -- error check |linkn= alias for unknown interwiki link prefix local project, language = interwiki_prefixen_get (link, false); -- false because wiki links in |author-linkn= is an error if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', link_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? link = nil; -- unset so we don't link link_alias = nil; end end last, etal = name_has_etal (last, etal, false, last_alias); -- find and remove variations on et al. first, etal = name_has_etal (first, etal, false, first_alias); -- find and remove variations on et al. last, first = name_checks (last, first, list_name, last_alias, first_alias); -- multiple names, extraneous annotation, etc. checks if first and not last then -- if there is a firstn without a matching lastn local alias = first_alias:find ('given', 1, true) and 'given' or 'first'; -- get first or given form of the alias utilities.set_message ('err_first_missing_last', { first_alias, -- param name of alias missing its mate first_alias:gsub (alias, {['first'] = 'last', ['given'] = 'surname'}), -- make param name appropriate to the alias form }); -- add this error message elseif not first and not last then -- if both firstn and lastn aren't found, are we done? count = count + 1; -- number of times we haven't found last and first if 2 <= count then -- two missing names and we give up break; -- normal exit or there is a two-name hole in the list; can't tell which end else -- we have last with or without a first local result; link = link_title_ok (link, link_alias, last, last_alias); -- check for improper wiki-markup if first then link = link_title_ok (link, link_alias, first, first_alias); -- check for improper wiki-markup end names[n] = {last = last, first = first, link = link, mask = mask, corporate = false}; -- add this name to our names list (corporate for |vauthors= only) n = n + 1; -- point to next location in the names table if 1 == count then -- if the previous name was missing utilities.set_message ('err_missing_name', {list_name:match ("(%w+)List"):lower(), i - 1}); -- add this error message end count = 0; -- reset the counter, we're looking for two consecutive missing names end i = i + 1; -- point to next args location end return names, etal; -- all done, return our list of names and the etal flag end --[[--------------------------< N A M E _ T A G _ G E T >------------------------------------------------------ attempt to decode |language=<lang_param> and return language name and matching tag; nil else. This function looks for: <lang_param> as a tag in cfg.lang_tag_remap{} <lang_param> as a name in cfg.lang_name_remap{} <lang_param> as a name in cfg.mw_languages_by_name_t <lang_param> as a tag in cfg.mw_languages_by_tag_t when those fail, presume that <lang_param> is an IETF-like tag that MediaWiki does not recognize. Strip all script, region, variant, whatever subtags from <lang_param> to leave just a two or three character language tag and look for the new <lang_param> in cfg.mw_languages_by_tag_t{} on success, returns name (in properly capitalized form) and matching tag (in lowercase); on failure returns nil ]] local function name_tag_get (lang_param) local lang_param_lc = mw.ustring.lower (lang_param); -- use lowercase as an index into the various tables local name; local tag; name = cfg.lang_tag_remap[lang_param_lc]; -- assume <lang_param_lc> is a tag; attempt to get remapped language name if name then -- when <name>, <lang_param> is a tag for a remapped language name if cfg.lang_name_remap[name:lower()][2] ~= lang_param_lc then utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added return name, cfg.lang_name_remap[name:lower()][2]; -- so return name and tag from lang_name_remap[name]; special case to xlate sr-ec and sr-el to sr-cyrl and sr-latn end return name, lang_param_lc; -- so return <name> from remap and <lang_param_lc> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- still assuming that <lang_param_lc> is a tag; strip script, region, variant subtags name = cfg.lang_tag_remap[tag]; -- attempt to get remapped language name with language subtag only if name then -- when <name>, <tag> is a tag for a remapped language name return name, tag; -- so return <name> from remap and <tag> end if cfg.lang_name_remap[lang_param_lc] then -- not a remapped tag, assume <lang_param_lc> is a name; attempt to get remapped language tag return cfg.lang_name_remap[lang_param_lc][1], cfg.lang_name_remap[lang_param_lc][2]; -- for this <lang_param_lc>, return a (possibly) new name and appropriate tag end name = cfg.mw_languages_by_tag_t[lang_param_lc]; -- assume that <lang_param_lc> is a tag; attempt to get its matching language name if name then return name, lang_param_lc; -- <lang_param_lc> is a tag so return it and <name> end tag = cfg.mw_languages_by_name_t[lang_param_lc]; -- assume that <lang_param_lc> is a language name; attempt to get its matching tag if tag then return cfg.mw_languages_by_tag_t[tag], tag; -- <lang_param_lc> is a name so return the name from the table and <tag> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- is <lang_param_lc> an IETF-like tag that MediaWiki doesn't recognize? <tag> gets the language subtag; nil else if tag then name = cfg.mw_languages_by_tag_t[tag]; -- attempt to get a language name using the shortened <tag> if name then return name, tag; -- <lang_param_lc> is an unrecognized IETF-like tag so return <name> and language subtag end end end --[[-------------------< L A N G U A G E _ P A R A M E T E R >------------------ Gets language name from a provided two- or three-character ISO 639 code. If a code is recognized by MediaWiki, use the returned name; if not, then use the value that was provided with the language parameter. When |language= contains a recognized language (either code or name), the page is assigned to the category for that code: Category:Norwegian-language sources (no). For valid three-character code languages, the page is assigned to the single category for '639-2' codes: Category:CS1 ISO 639-2 language sources. Languages that are the same as the local wiki are not categorized. MediaWiki does not recognize three-character equivalents of two-character codes: code 'ar' is recognized but code 'ara' is not. This function supports multiple languages in the form |language=nb, French, th where the language names or codes are separated from each other by commas with optional space characters. ]] local function language_parameter (lang) local tag; -- some form of IETF-like language tag; language subtag with optional region, sript, vatiant, etc subtags local lang_subtag; -- ve populates |language= with mostly unecessary region subtags the MediaWiki does not recognize; this is the base language subtag local name; -- the language name local language_list = {}; -- table of language names to be rendered local names_t = {}; -- table made from the value assigned to |language= local this_wiki_name = mw.language.fetchLanguageName (cfg.this_wiki_code, cfg.this_wiki_code); -- get this wiki's language name names_t = mw.text.split (lang, '%s*,%s*'); -- names should be a comma separated list for _, lang in ipairs (names_t) do -- reuse lang here because we don't yet know if lang is a language name or a language tag name, tag = name_tag_get (lang); -- attempt to get name/tag pair for <lang>; <name> has proper capitalization; <tag> is lowercase if utilities.is_set (tag) then lang_subtag = tag:gsub ('^(%a%a%a?)%-.*', '%1'); -- for categorization, strip any IETF-like tags from language tag if cfg.this_wiki_code ~= lang_subtag then -- when the language is not the same as this wiki's language if 2 == lang_subtag:len() then -- and is a two-character tag utilities.add_prop_cat ('foreign-lang-source', {name, tag}, lang_subtag); -- categorize it; tag appended to allow for multiple language categorization else -- or is a recognized language (but has a three-character tag) utilities.add_prop_cat ('foreign-lang-source-2', {lang_subtag}, lang_subtag); -- categorize it differently TODO: support multiple three-character tag categories per cs1|2 template? end elseif cfg.local_lang_cat_enable then -- when the language and this wiki's language are the same and categorization is enabled utilities.add_prop_cat ('local-lang-source', {name, lang_subtag}); -- categorize it end else name = lang; -- return whatever <lang> has so that we show something utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added end table.insert (language_list, name); name = ''; -- so we can reuse it end name = utilities.make_sep_list (#language_list, language_list); if (1 == #language_list) and (lang_subtag == cfg.this_wiki_code) then -- when only one language, find lang name in this wiki lang name; for |language=en-us, 'English' in 'American English' return ''; -- if one language and that language is this wiki's return an empty string (no annotation) end return (" " .. wrap_msg ('language', name)); -- otherwise wrap with '(in ...)' --[[ TODO: should only return blank or name rather than full list so we can clean up the bunched parenthetical elements Language, Type, Format ]] end --[[-----------------------< S E T _ C S _ S T Y L E >-------------------------- Gets the default CS style configuration for the given mode. Returns default separator and either postscript as passed in or the default. In CS1, the default postscript and separator are '.'. In CS2, the default postscript is the empty string and the default separator is ','. ]] local function set_cs_style (postscript, mode) if utilities.is_set(postscript) then -- emit a maintenance message if user postscript is the default cs1 postscript -- we catch the opposite case for cs2 in set_style if mode == 'cs1' and postscript == cfg.presentation['ps_' .. mode] then utilities.set_message ('maint_postscript'); end else postscript = cfg.presentation['ps_' .. mode]; end return cfg.presentation['sep_' .. mode], postscript; end --[[--------------------------< S E T _ S T Y L E >----------------------------- Sets the separator and postscript styles. Checks the |mode= first and the #invoke CitationClass second. Removes the postscript if postscript == none. ]] local function set_style (mode, postscript, cite_class) local sep; if 'cs2' == mode then sep, postscript = set_cs_style (postscript, 'cs2'); elseif 'cs1' == mode then sep, postscript = set_cs_style (postscript, 'cs1'); elseif 'citation' == cite_class then sep, postscript = set_cs_style (postscript, 'cs2'); else sep, postscript = set_cs_style (postscript, 'cs1'); end if cfg.keywords_xlate[postscript:lower()] == 'none' then -- emit a maintenance message if user postscript is the default cs2 postscript -- we catch the opposite case for cs1 in set_cs_style if 'cs2' == mode or ('cs1' ~= mode and 'citation' == cite_class) then -- {{citation |title=Title |mode=cs1 |postscript=none}} should not emit maint message utilities.set_message ('maint_postscript'); end postscript = ''; end return sep, postscript end --[=[-------------------------< I S _ P D F >----------------------------------- Determines if a URL has the file extension that is one of the PDF file extensions used by [[MediaWiki:Common.css]] when applying the PDF icon to external links. returns true if file extension is one of the recognized extensions, else false ]=] local function is_pdf (url) return url:match ('%.pdf$') or url:match ('%.PDF$') or url:match ('%.pdf[%?#]') or url:match ('%.PDF[%?#]') or url:match ('%.PDF&#035') or url:match ('%.pdf&#035'); end --[[--------------------------< S T Y L E _ F O R M A T >----------------------- Applies CSS style to |format=, |chapter-format=, etc. Also emits an error message if the format parameter does not have a matching URL parameter. If the format parameter is not set and the URL contains a file extension that is recognized as a PDF document by MediaWiki's commons.css, this code will set the format parameter to (PDF) with the appropriate styling. ]] local function style_format (format, url, fmt_param, url_param) if utilities.is_set (format) then format = utilities.wrap_style ('format', format); -- add leading space, parentheses, resize if not utilities.is_set (url) then utilities.set_message ('err_format_missing_url', {fmt_param, url_param}); -- add an error message end elseif is_pdf (url) then -- format is not set so if URL is a PDF file then format = utilities.wrap_style ('format', 'PDF'); -- set format to PDF else format = ''; -- empty string for concatenation end return format; end --[[---------------------< G E T _ D I S P L A Y _ N A M E S >------------------ Returns a number that defines the number of names displayed for author and editor name lists and a Boolean flag to indicate when et al. should be appended to the name list. When the value assigned to |display-xxxxors= is a number greater than or equal to zero, return the number and the previous state of the 'etal' flag (false by default but may have been set to true if the name list contains some variant of the text 'et al.'). When the value assigned to |display-xxxxors= is the keyword 'etal', return a number that is one greater than the number of authors in the list and set the 'etal' flag true. This will cause the list_people() to display all of the names in the name list followed by 'et al.' In all other cases, returns nil and the previous state of the 'etal' flag. inputs: max: A['DisplayAuthors'] or A['DisplayEditors'], etc; a number or some flavor of etal count: #a or #e list_name: 'authors' or 'editors' etal: author_etal or editor_etal This function sets an error message when |display-xxxxors= value greater than or equal to number of names but not when <max> comes from {{cs1 config}} global settings. When using global settings, <param> is set to the keyword 'cs1 config' which is used to supress the normal error. Error is suppressed because it is to be expected that some citations in an article will have the same or fewer names that the limit specified in {{cs1 config}}. ]] local function get_display_names (max, count, list_name, etal, param) if utilities.is_set (max) then if 'etal' == max:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings max = count + 1; -- number of authors + 1 so display all author name plus et al. etal = true; -- overrides value set by extract_names() elseif max:match ('^%d+$') then -- if is a string of numbers max = tonumber (max); -- make it a number if (max >= count) and ('cs1 config' ~= param) then -- error when local |display-xxxxors= value greater than or equal to number of names; not an error when using global setting utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; end else -- not a valid keyword or number utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; -- unset; as if |display-xxxxors= had not been set end end return max, etal; end --[[----------< E X T R A _ T E X T _ I N _ P A G E _ C H E C K >--------------- Adds error if |page=, |pages=, |quote-page=, |quote-pages= has what appears to be some form of p. or pp. abbreviation in the first characters of the parameter content. check page for extraneous p, p., pp, pp., pg, pg. at start of parameter value: good pattern: '^P[^%.P%l]' matches when page begins PX or P# but not Px where x and X are letters and # is a digit bad pattern: '^[Pp][PpGg]' matches when page begins pp, pP, Pp, PP, pg, pG, Pg, PG ]] local function extra_text_in_page_check (val, name) if not val:match (cfg.vol_iss_pg_patterns.good_ppattern) then for _, pattern in ipairs (cfg.vol_iss_pg_patterns.bad_ppatterns) do -- spin through the selected sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message ('err_extra_text_pages', name); -- add error message return; -- and done end end end end --[[--------------------------< E X T R A _ T E X T _ I N _ V O L _ I S S _ C H E C K >------------------------ Adds error if |volume= or |issue= has what appears to be some form of redundant 'type' indicator. Applies to both; this function looks for issue text in both |issue= and |volume= and looks for volume-like text in |voluem= and |issue=. For |volume=: 'V.', or 'Vol.' (with or without the dot) abbreviations or 'Volume' in the first characters of the parameter content (all case insensitive). 'V' and 'v' (without the dot) are presumed to be roman numerals so are allowed. For |issue=: 'No.', 'I.', 'Iss.' (with or without the dot) abbreviations, or 'Issue' in the first characters of the parameter content (all case insensitive); numero styling: 'n°' with degree sign U+00B0, and № precomposed numero sign U+2116. Single character values ('v', 'i', 'n') allowed when not followed by separator character ('.', ':', '=', or whitespace character) – param values are trimmed of whitespace by MediaWiki before delivered to the module. <val> is |volume= or |issue= parameter value <name> is |volume= or |issue= parameter name for error message <selector> is 'v' for |volume=, 'i' for |issue= sets error message on failure; returns nothing ]] local function extra_text_in_vol_iss_check (val, name, selector) if not utilities.is_set (val) then return; end local handler = 'v' == selector and 'err_extra_text_volume' or 'err_extra_text_issue'; local accept_val; val, accept_val = utilities.has_accept_as_written (val); --if accept_val then -- if uncomment this, |volume=((vol. 1)) suppresses error -- return; --end --val = mw.text.unstripNoWiki (val); -- if uncomment this, |volume=<nowiki>vol. 1</nowiki> shows error val = val:lower(); -- force parameter value to lower case for _, pattern in ipairs (cfg.vol_iss_pg_patterns.vi_patterns_t) do -- spin through the sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message (handler, name); -- add error message return; -- and done end end end --[=[-------------------------< G E T _ V _ N A M E _ T A B L E >---------------------------------------------- split apart a |vauthors= or |veditors= parameter. This function allows for corporate names, wrapped in doubled parentheses to also have commas; in the old version of the code, the doubled parentheses were included in the rendered citation and in the metadata. Individual author names may be wikilinked |vauthors=Jones AB, [[E. B. White|White EB]], ((Black, Brown, and Co.)) ]=] local function get_v_name_table (vparam, output_table, output_link_table) local _, accept = utilities.has_accept_as_written (vparam); if accept then utilities.add_prop_cat ('vanc-accept'); -- add properties category end local name_table = mw.text.split(vparam, "%s*,%s*"); -- names are separated by commas local wl_type, label, link; -- wl_type not used here; just a placeholder local i = 1; while name_table[i] do if name_table[i]:match ('^%(%(.*[^%)][^%)]$') then -- first segment of corporate with one or more commas; this segment has the opening doubled parentheses local name = name_table[i]; i = i + 1; -- bump indexer to next segment while name_table[i] do name = name .. ', ' .. name_table[i]; -- concatenate with previous segments if name_table[i]:match ('^.*%)%)$') then -- if this table member has the closing doubled parentheses break; -- and done reassembling so end i = i + 1; -- bump indexer end table.insert (output_table, name); -- and add corporate name to the output table table.insert (output_link_table, ''); -- no wikilink else wl_type, label, link = utilities.is_wikilink (name_table[i]); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] table.insert (output_table, label); -- add this name if 1 == wl_type then table.insert (output_link_table, label); -- simple wikilink [[D]] else table.insert (output_link_table, link); -- no wikilink or [[L|D]]; add this link if there is one, else empty string end end i = i + 1; end return output_table; end --[[--------------------------< P A R S E _ V A U T H O R S _ V E D I T O R S >-------------------------------- This function extracts author / editor names from |vauthors= or |veditors= and finds matching |xxxxor-maskn= and |xxxxor-linkn= in args. It then returns a table of assembled names just as extract_names() does. Author / editor names in |vauthors= or |veditors= must be in Vancouver system style. Corporate or institutional names may sometimes be required and because such names will often fail the is_good_vanc_name() and other format compliance tests, are wrapped in doubled parentheses ((corporate name)) to suppress the format tests. Supports generational suffixes Jr, 2nd, 3rd, 4th–6th. This function sets the Vancouver error when a required comma is missing and when there is a space between an author's initials. ]] local function parse_vauthors_veditors (args, vparam, list_name) local names = {}; -- table of names assembled from |vauthors=, |author-maskn=, |author-linkn= local v_name_table = {}; local v_link_table = {}; -- when name is wikilinked, targets go in this table local etal = false; -- return value set to true when we find some form of et al. vauthors parameter local last, first, link, mask, suffix; local corporate = false; vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period) v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); -- names are separated by commas for i, v_name in ipairs(v_name_table) do first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor local accept_name; v_name, accept_name = utilities.has_accept_as_written (v_name); -- remove accept-this-as-written markup when it wraps all of <v_name> if accept_name then last = v_name; corporate = true; -- flag used in list_people() elseif string.find(v_name, "%s") then if v_name:find('[;%.]') then -- look for commonly occurring punctuation characters; add_vanc_error (cfg.err_msg_supl.punctuation, i); end local lastfirstTable = {} lastfirstTable = mw.text.split(v_name, "%s+") first = table.remove(lastfirstTable); -- removes and returns value of last element in table which should be initials or generational suffix if not mw.ustring.match (first, '^%u+$') then -- mw.ustring here so that later we will catch non-Latin characters suffix = first; -- not initials so assume that whatever we got is a generational suffix first = table.remove(lastfirstTable); -- get what should be the initials from the table end last = table.concat(lastfirstTable, ' ') -- returns a string that is the concatenation of all other names that are not initials and generational suffix if not utilities.is_set (last) then first = ''; -- unset last = v_name; -- last empty because something wrong with first add_vanc_error (cfg.err_msg_supl.name, i); end if mw.ustring.match (last, '%a+%s+%u+%s+%a+') then add_vanc_error (cfg.err_msg_supl['missing comma'], i); -- matches last II last; the case when a comma is missing end if mw.ustring.match (v_name, ' %u %u$') then -- this test is in the wrong place TODO: move or replace with a more appropriate test add_vanc_error (cfg.err_msg_supl.initials, i); -- matches a space between two initials end else last = v_name; -- last name or single corporate name? Doesn't support multiword corporate names? do we need this? end if utilities.is_set (first) then if not mw.ustring.match (first, "^%u?%u$") then -- first shall contain one or two upper-case letters, nothing else add_vanc_error (cfg.err_msg_supl.initials, i); -- too many initials; mixed case initials (which may be ok Romanization); hyphenated initials end is_good_vanc_name (last, first, suffix, i); -- check first and last before restoring the suffix which may have a non-Latin digit if utilities.is_set (suffix) then first = first .. ' ' .. suffix; -- if there was a suffix concatenate with the initials suffix = ''; -- unset so we don't add this suffix to all subsequent names end else if not corporate then is_good_vanc_name (last, '', nil, i); end end link = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ) or v_link_table[i]; mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); names[i] = {last = last, first = first, link = link, mask = mask, corporate = corporate}; -- add this assembled name to our names list end return names, etal; -- all done, return our list of names end --[[--------------------------< S E L E C T _ A U T H O R _ E D I T O R _ S O U R C E >------------------------ Select one of |authors=, |authorn= / |lastn / firstn=, or |vauthors= as the source of the author name list or select one of |editorn= / editor-lastn= / |editor-firstn= or |veditors= as the source of the editor name list. Only one of these appropriate three will be used. The hierarchy is: |authorn= (and aliases) highest and |authors= lowest; |editorn= (and aliases) highest and |veditors= lowest (support for |editors= withdrawn) When looking for |authorn= / |editorn= parameters, test |xxxxor1= and |xxxxor2= (and all of their aliases); stops after the second test which mimicks the test used in extract_names() when looking for a hole in the author name list. There may be a better way to do this, I just haven't discovered what that way is. Emits an error message when more than one xxxxor name source is provided. In this function, vxxxxors = vauthors or veditors; xxxxors = authors as appropriate. ]] local function select_author_editor_source (vxxxxors, xxxxors, args, list_name) local lastfirst = false; if utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 1 ) or -- do this twice in case we have a |first1= without a |last1=; this ... utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 1 ) or -- ... also catches the case where |first= is used with |vauthors= utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 2 ) or utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 2 ) then lastfirst = true; end if (utilities.is_set (vxxxxors) and true == lastfirst) or -- these are the three error conditions (utilities.is_set (vxxxxors) and utilities.is_set (xxxxors)) or (true == lastfirst and utilities.is_set (xxxxors)) then utilities.set_message ('err_redundant_parameters', utilities.substitute (cfg.special_case_translation.name_list_params, ('AuthorList' == list_name) and cfg.special_case_translation.author or cfg.special_case_translation.editor)); -- add error message end if true == lastfirst then return 1 end; -- return a number indicating which author name source to use if utilities.is_set (vxxxxors) then return 2 end; if utilities.is_set (xxxxors) then return 3 end; return 1; -- no authors so return 1; this allows missing author name test to run in case there is a first without last end --[[--------------------------< I S _ V A L I D _ P A R A M E T E R _ V A L U E >------------------------------ This function is used to validate a parameter's assigned value for those parameters that have only a limited number of allowable values (yes, y, true, live, dead, etc.). When the parameter value has not been assigned a value (missing or empty in the source template) the function returns the value specified by ret_val. If the parameter value is one of the list of allowed values returns the translated value; else, emits an error message and returns the value specified by ret_val. TODO: explain <invert> ]] local function is_valid_parameter_value (value, name, possible, ret_val, invert) if not utilities.is_set (value) then return ret_val; -- an empty parameter is ok end if (not invert and utilities.in_array (value, possible)) then -- normal; <value> is in <possible> table return cfg.keywords_xlate[value]; -- return translation of parameter keyword elseif invert and not utilities.in_array (value, possible) then -- invert; <value> is not in <possible> table return value; -- return <value> as it is else utilities.set_message ('err_invalid_param_val', {name, value}); -- not an allowed value so add error message return ret_val; end end --[[--------------------------< T E R M I N A T E _ N A M E _ L I S T >---------------------------------------- This function terminates a name list (author, contributor, editor) with a separator character (sepc) and a space when the last character is not a sepc character or when the last three characters are not sepc followed by two closing square brackets (close of a wikilink). When either of these is true, the name_list is terminated with a single space character. ]] local function terminate_name_list (name_list, sepc) if (string.sub (name_list, -3, -1) == sepc .. '. ') then -- if already properly terminated return name_list; -- just return the name list elseif (string.sub (name_list, -1, -1) == sepc) or (string.sub (name_list, -3, -1) == sepc .. ']]') then -- if last name in list ends with sepc char return name_list .. " "; -- don't add another else return name_list .. sepc .. ' '; -- otherwise terminate the name list end end --[[-------------------------< F O R M A T _ V O L U M E _ I S S U E >----------------------------------------- returns the concatenation of the formatted volume and issue (or journal article number) parameters as a single string; or formatted volume or formatted issue, or an empty string if neither are set. ]] local function format_volume_issue (volume, issue, article, cite_class, origin, sepc, lower) if not utilities.is_set (volume) and not utilities.is_set (issue) and not utilities.is_set (article) then return ''; end -- same condition as in format_pages_sheets() local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); local is_numeric_vol = volume and (volume:match ('^[MDCLXVI]+$') or volume:match ('^%d+$')); -- is only uppercase roman numerals or only digits? local is_long_vol = volume and (4 < mw.ustring.len(volume)); -- is |volume= value longer than 4 characters? if volume and (not is_numeric_vol and is_long_vol) then -- when not all digits or Roman numerals, is |volume= longer than 4 characters? utilities.add_prop_cat ('long-vol'); -- yes, add properties cat end if is_journal then -- journal-style formatting local vol = ''; if utilities.is_set (volume) then if is_numeric_vol then -- |volume= value all digits or all uppercase Roman numerals? vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, volume}); -- render in bold face elseif is_long_vol then -- not all digits or Roman numerals; longer than 4 characters? vol = utilities.substitute (cfg.messages['j-vol'], {sepc, utilities.hyphen_to_dash (volume)}); -- not bold else -- four or fewer characters vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, utilities.hyphen_to_dash (volume)}); -- bold end end vol = vol .. (utilities.is_set (issue) and utilities.substitute (cfg.messages['j-issue'], issue) or '') vol = vol .. (utilities.is_set (article) and utilities.substitute (cfg.messages['j-article-num'], article) or '') return vol; end if 'podcast' == cite_class and utilities.is_set (issue) then return wrap_msg ('issue', {sepc, issue}, lower); end if 'conference' == cite_class and utilities.is_set (article) then -- |article-number= supported only in journal and conference cites if utilities.is_set (volume) and utilities.is_set (article) then -- both volume and article number return wrap_msg ('vol-art', {sepc, utilities.hyphen_to_dash (volume), article}, lower); elseif utilities.is_set (article) then -- article number alone; when volume alone, handled below return wrap_msg ('art', {sepc, article}, lower); end end -- all other types of citation if utilities.is_set (volume) and utilities.is_set (issue) then return wrap_msg ('vol-no', {sepc, utilities.hyphen_to_dash (volume), issue}, lower); elseif utilities.is_set (volume) then return wrap_msg ('vol', {sepc, utilities.hyphen_to_dash (volume)}, lower); else return wrap_msg ('issue', {sepc, issue}, lower); end end --[[-------------------------< F O R M A T _ P A G E S _ S H E E T S >----------------------------------------- adds static text to one of |page(s)= or |sheet(s)= values and returns it with all of the others set to empty strings. The return order is: page, pages, sheet, sheets Singular has priority over plural when both are provided. ]] local function format_pages_sheets (page, pages, sheet, sheets, cite_class, origin, sepc, nopp, lower) if 'map' == cite_class then -- only cite map supports sheet(s) as in-source locators if utilities.is_set (sheet) then if 'journal' == origin then return '', '', wrap_msg ('j-sheet', sheet, lower), ''; else return '', '', wrap_msg ('sheet', {sepc, sheet}, lower), ''; end elseif utilities.is_set (sheets) then if 'journal' == origin then return '', '', '', wrap_msg ('j-sheets', sheets, lower); else return '', '', '', wrap_msg ('sheets', {sepc, sheets}, lower); end end end local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); if utilities.is_set (page) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], page), '', '', ''; elseif not nopp then return utilities.substitute (cfg.messages['p-prefix'], {sepc, page}), '', '', ''; else return utilities.substitute (cfg.messages['nopp'], {sepc, page}), '', '', ''; end elseif utilities.is_set (pages) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], pages), '', '', ''; elseif tonumber(pages) ~= nil and not nopp then -- if pages is only digits, assume a single page number return '', utilities.substitute (cfg.messages['p-prefix'], {sepc, pages}), '', ''; elseif not nopp then return '', utilities.substitute (cfg.messages['pp-prefix'], {sepc, pages}), '', ''; else return '', utilities.substitute (cfg.messages['nopp'], {sepc, pages}), '', ''; end end return '', '', '', ''; -- return empty strings end --[[--------------------------< I N S O U R C E _ L O C _ G E T >---------------------------------------------- returns one of the in-source locators: page, pages, or at. If any of these are interwiki links to Wikisource, returns the label portion of the interwiki-link as plain text for use in COinS. This COinS thing is done because here we convert an interwiki-link to an external link and add an icon span around that; get_coins_pages() doesn't know about the span. TODO: should it? TODO: add support for sheet and sheets?; streamline; TODO: make it so that this function returns only one of the three as the single in-source (the return value assigned to a new name)? ]] local function insource_loc_get (page, page_orig, pages, pages_orig, at) local ws_url, ws_label, coins_pages, L; -- for Wikisource interwiki-links; TODO: this corrupts page metadata (span remains in place after cleanup; fix there?) if utilities.is_set (page) then if utilities.is_set (pages) or utilities.is_set (at) then pages = ''; -- unset the others at = ''; end extra_text_in_page_check (page, page_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (page); -- make ws URL from |page= interwiki link; link portion L becomes tooltip label if ws_url then page = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in page'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? page = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, page}); coins_pages = ws_label; end elseif utilities.is_set (pages) then if utilities.is_set (at) then at = ''; -- unset end extra_text_in_page_check (pages, pages_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (pages); -- make ws URL from |pages= interwiki link; link portion L becomes tooltip label if ws_url then pages = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in pages'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? pages = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, pages}); coins_pages = ws_label; end elseif utilities.is_set (at) then ws_url, ws_label, L = wikisource_url_make (at); -- make ws URL from |at= interwiki link; link portion L becomes tooltip label if ws_url then at = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in at'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? at = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, at}); coins_pages = ws_label; end end return page, pages, at, coins_pages; end --[[--------------------------< I S _ U N I Q U E _ A R C H I V E _ U R L >------------------------------------ add error message when |archive-url= value is same as |url= or chapter-url= (or alias...) value ]] local function is_unique_archive_url (archive, url, c_url, source, date) if utilities.is_set (archive) then if archive == url or archive == c_url then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); -- add error message return '', ''; -- unset |archive-url= and |archive-date= because same as |url= or |chapter-url= end end return archive, date; end --[=[-------------------------< A R C H I V E _ U R L _ C H E C K >-------------------------------------------- Check archive.org URLs to make sure they at least look like they are pointing at valid archives and not to the save snapshot URL or to calendar pages. When the archive URL is 'https://web.archive.org/save/' (or http://...) archive.org saves a snapshot of the target page in the URL. That is something that Wikipedia should not allow unwitting readers to do. When the archive.org URL does not have a complete timestamp, archive.org chooses a snapshot according to its own algorithm or provides a calendar 'search' result. [[WP:ELNO]] discourages links to search results. This function looks at the value assigned to |archive-url= and returns empty strings for |archive-url= and |archive-date= and an error message when: |archive-url= holds an archive.org save command URL |archive-url= is an archive.org URL that does not have a complete timestamp (YYYYMMDDhhmmss 14 digits) in the correct place otherwise returns |archive-url= and |archive-date= There are two mostly compatible archive.org URLs: //web.archive.org/<timestamp>... -- the old form //web.archive.org/web/<timestamp>... -- the new form The old form does not support or map to the new form when it contains a display flag. There are four identified flags ('id_', 'js_', 'cs_', 'im_') but since archive.org ignores others following the same form (two letters and an underscore) we don't check for these specific flags but we do check the form. This function supports a preview mode. When the article is rendered in preview mode, this function may return a modified archive URL: for save command errors, return undated wildcard (/*/) for timestamp errors when the timestamp has a wildcard, return the URL unmodified for timestamp errors when the timestamp does not have a wildcard, return with timestamp limited to six digits plus wildcard (/yyyymm*/) A secondary function is to return an archive-url timestamp from those urls that have them (archive.org and archive.today). The timestamp is used by validation.archive_date_check() to see if the value in |archive-date= matches the timestamp in the archive url. ]=] local function archive_url_check (url, date) local err_msg = ''; -- start with the error message empty local path, timestamp, flag; -- portions of the archive.org URL local function is_ts_date_valid (timestamp, origin_date) -- local function to validate archive url taimestamp date; time ignored local y, m, d = timestamp:match ('(%d%d%d%d)(%d%d)(%d%d)'); -- split into parts if y and validation.is_valid_date (y, m, d) and (tonumber (y) >= origin_date) then -- <origin_date> is 1996 for archive.org; 2012 for archive.today return true; end end timestamp = url:match ('//archive.today/(%d%d%d%d%d%d%d%d%d%d%d%d%d%d)/') or -- get timestamp from archive.today urls url:match ('//archive.today/(%d%d%d%d%.%d%d%.%d%d%-%d%d%d%d%d%d)/'); -- this timestamp needs cleanup if timestamp then -- if this is an archive.today url ... timestamp = timestamp:gsub ('[%.%-]', ''); -- strip dots and dashes if not is_ts_date_valid (timestamp, 2012) then -- is ymd portion of timestamp a valid date? utilities.set_message ('err_archive_url', {cfg.err_msg_supl.timestamp}); -- no; set error message; if is_preview_mode then return url, date; -- preview mode so return ArchiveURL, ArchiveDate; suppress timestamp because invalid else return '', ''; -- return empty strings for ArchiveURL and ArchiveDate end else return url, date, timestamp; -- return ArchiveURL, ArchiveDate, and timestamp (dots and dashes removed) from |archive-url=, and done end end -- here for archive.org urls if (not url:match('//web%.archive%.org/')) and (not url:match('//liveweb%.archive%.org/')) then -- also deprecated liveweb Wayback machine URL return url, date; -- not an archive.org archive, return ArchiveURL and ArchiveDate end if url:match('//web%.archive%.org/save/') then -- if a save command URL, we don't want to allow saving of the target page err_msg = cfg.err_msg_supl.save; url = url:gsub ('(//web%.archive%.org)/save/', '%1/*/', 1); -- for preview mode: modify ArchiveURL elseif url:match('//liveweb%.archive%.org/') then err_msg = cfg.err_msg_supl.liveweb; else path, timestamp, flag = url:match('//web%.archive%.org/([^%d]*)(%d+)([^/]*)/'); -- split out some of the URL parts for evaluation if not path then -- malformed in some way; pattern did not match err_msg = cfg.err_msg_supl.timestamp; elseif 14 ~= timestamp:len() then -- path and flag optional, must have 14-digit timestamp here err_msg = cfg.err_msg_supl.timestamp; if '*' ~= flag then local replacement = timestamp:match ('^%d%d%d%d%d%d') or timestamp:match ('^%d%d%d%d'); -- get the first 6 (YYYYMM) or first 4 digits (YYYY) if replacement then -- nil if there aren't at least 4 digits (year) replacement = replacement .. string.rep ('0', 14 - replacement:len()); -- year or yearmo (4 or 6 digits) zero-fill to make 14-digit timestamp url=url:gsub ('(//web%.archive%.org/[^%d]*)%d[^/]*', '%1' .. replacement .. '*', 1) -- for preview, modify ts to 14 digits plus splat for calendar display end end elseif not is_ts_date_valid (timestamp, 1996) then -- is ymd portion of timestamp a valid date? err_msg = cfg.err_msg_supl.timestamp; timestamp = nil; -- unset because invalid elseif utilities.is_set (path) and 'web/' ~= path then -- older archive URLs do not have the extra 'web/' path element err_msg = cfg.err_msg_supl.path; elseif utilities.is_set (flag) and not utilities.is_set (path) then -- flag not allowed with the old form URL (without the 'web/' path element) err_msg = cfg.err_msg_supl.flag; elseif utilities.is_set (flag) and not flag:match ('%a%a_') then -- flag if present must be two alpha characters and underscore (requires 'web/' path element) err_msg = cfg.err_msg_supl.flag; else return url, date, timestamp; -- return ArchiveURL, ArchiveDate, and timestamp from |archive-url= end end -- if here, something not right so utilities.set_message ('err_archive_url', {err_msg}); -- add error message and if is_preview_mode then return url, date, timestamp; -- preview mode so return ArchiveURL, ArchiveDate, and timestamp from |archive-url= else return '', ''; -- return empty strings for ArchiveURL and ArchiveDate end end --[[--------------------------< P L A C E _ C H E C K >-------------------------------------------------------- check |place=, |publication-place=, |location= to see if these params include digits. This function added because many editors misuse location to specify the in-source location (|page(s)= and |at= are supposed to do that) returns the original parameter value without modification; added maint cat when parameter value contains digits ]] local function place_check (param_val) if not utilities.is_set (param_val) then -- parameter empty or omitted return param_val; -- return that empty state end if mw.ustring.find (param_val, '%d') then -- not empty, are there digits in the parameter value utilities.set_message ('maint_location'); -- yep, add maint cat end return param_val; -- and done end --[[--------------------------< I S _ A R C H I V E D _ C O P Y >---------------------------------------------- compares |title= to 'Archived copy' (placeholder added by bots that can't find proper title); if matches, return true; nil else ]] local function is_archived_copy (title) title = mw.ustring.lower(title); -- switch title to lower case if title:find (cfg.special_case_translation.archived_copy.en) then -- if title is 'Archived copy' return true; elseif cfg.special_case_translation.archived_copy['local'] then if mw.ustring.find (title, cfg.special_case_translation.archived_copy['local']) then -- mw.ustring() because might not be Latin script return true; end end end --[[--------------------------< D I S P L A Y _ N A M E S _ S E L E C T >-------------------------------------- for any of the |display-authors=, |display-editors=, etc parameters, select either the local or global setting. When both are present, look at <local_display_names> value. When the value is some sort of 'et al.'string, special handling is required. When {{cs1 config}} has |display-<namelist>= AND this template has |display-<namelist>=etal AND: the number of names specified by <number_of_names> is: greater than the number specified in the global |display-<namelist>= parameter (<global_display_names>) use global |display-<namelist>= parameter value set overridden maint category less than or equal to the number specified in the global |display-<namelist>= parameter use local |display-<namelist>= parameter value The purpose of this function is to prevent categorizing a template that has fewer names than the global setting to keep the etal annotation specified by <local_display_names>. ]] local function display_names_select (global_display_names, local_display_names, param_name, number_of_names, test) if global_display_names and utilities.is_set (local_display_names) then -- when both if 'etal' == local_display_names:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings number_of_names = tonumber (number_of_names); -- convert these to numbers for comparison local global_display_names_num = tonumber (global_display_names); -- <global_display_names> not set when parameter value is not digits if number_of_names > global_display_names_num then -- template has more names than global config allows to be displayed? utilities.set_message ('maint_overridden_setting'); -- set a maint message because global is overriding local |display-<namelist>=etal return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local because fewer names so let <local_display_names> control end end -- here when <global_display_names> and <local_display_names> both numbers; <global_display_names> controls utilities.set_message ('maint_overridden_setting'); -- set a maint message return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) end -- here when only one of <global_display_names> or <local_display_names> set if global_display_names then return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local end end --[[--------------------------< M O D E _ S E T >-------------------------------------------------------------- fetch global mode setting from {{cs1 config}} (if present) or from |mode= (if present); global setting overrides local |mode= parameter value. When both are present, emit maintenance message ]] local function mode_set (Mode, Mode_origin) local mode; if cfg.global_cs1_config_t['Mode'] then -- global setting in {{cs1 config}}; nil when empty or assigned value invalid mode = is_valid_parameter_value (cfg.global_cs1_config_t['Mode'], 'cs1 config: mode', cfg.keywords_lists['mode'], ''); -- error messaging 'param' here is a hoax else mode = is_valid_parameter_value (Mode, Mode_origin, cfg.keywords_lists['mode'], ''); end if cfg.global_cs1_config_t['Mode'] and utilities.is_set (Mode) then -- when template has |mode=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end return mode; end --[[--------------------------< Q U O T E _ M A K E >---------------------------------------------------------- create quotation from |quote=, |trans-quote=, and/or script-quote= with or without |quote-page= or |quote-pages= when any of those three quote parameters are set, this function unsets <PostScript>. When none of those parameters are set, |quote-page= and |quote-pages= are unset to nil so that they are not included in the template's metadata ]] local function quote_make (quote, trans_quote, script_quote, quote_page, quote_pages, nopp, sepc, postscript) if utilities.is_set (quote) or utilities.is_set (trans_quote) or utilities.is_set (script_quote) then if utilities.is_set (quote) then if quote:sub(1, 1) == '"' and quote:sub(-1, -1) == '"' then -- if first and last characters of quote are quote marks quote = quote:sub(2, -2); -- strip them off end end quote = kern_quotes (quote); -- kern if needed quote = utilities.wrap_style ('quoted-text', quote ); -- wrap in <q>...</q> tags if utilities.is_set (script_quote) then quote = script_concatenate (quote, script_quote, 'script-quote'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after quote is wrapped end if utilities.is_set (trans_quote) then if trans_quote:sub(1, 1) == '"' and trans_quote:sub(-1, -1) == '"' then -- if first and last characters of |trans-quote are quote marks trans_quote = trans_quote:sub(2, -2); -- strip them off end quote = quote .. " " .. utilities.wrap_style ('trans-quoted-title', trans_quote ); end if utilities.is_set (quote_page) or utilities.is_set (quote_pages) then -- add page prefix local quote_prefix = ''; if utilities.is_set (quote_page) then extra_text_in_page_check (quote_page, 'quote-page'); -- add to maint cat if |quote-page= value begins with what looks like p., pp., etc. if not nopp then quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_page}), '', '', ''; else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_page}), '', '', ''; end elseif utilities.is_set (quote_pages) then extra_text_in_page_check (quote_pages, 'quote-pages'); -- add to maint cat if |quote-pages= value begins with what looks like p., pp., etc. if tonumber(quote_pages) ~= nil and not nopp then -- if only digits, assume single page quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_pages}), '', ''; elseif not nopp then quote_prefix = utilities.substitute (cfg.messages['pp-prefix'], {sepc, quote_pages}), '', ''; else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_pages}), '', ''; end end quote = quote_prefix .. ": " .. quote; else quote = sepc .. " " .. quote; end postscript = ""; -- cs1|2 does not supply terminal punctuation when |quote= is set elseif utilities.is_set (quote_page) or utilities.is_set (quote_pages) then quote_page = nil; -- unset; these require |quote=; TODO: error message? quote_pages = nil; end return quote, quote_page, quote_pages, postscript; end --[[--------------------------< C H E C K _ P U B L I S H E R _ N A M E >-------------------------------------- look for variations of '<text>: <text>' that might be '<location>: <publisher>' in |publisher= parameter value. when found, emit a maintenance message; return nil else <publisher> is the value assigned to |publisher= or |institution= ]] local function check_publisher_name (publisher) local patterns_t = { '^[%w%s]+%s*:%s*[%w%s]+$', -- plain text <location>: <publisher> '^%[+[%w%s:|]+%]+%s*:%s*[%w%s]+$', -- partially wikilinked [[<location>]]: <publisher> '^[%w%s]+%s*:%s*%[+[%w%s:|]+%]+$', -- partially wikilinked <location>: [[<publisher>]] '^%[+[%w%s:|]+%]+%s*:%s*%[+[%w%s:|]+%]+$', -- wikilinked [[<location>]]: [[<publisher>]] } for _, pattern in ipairs (patterns_t) do -- spin through the patterns_t sequence if mw.ustring.match (publisher, pattern) then -- does this pattern match? utilities.set_message ('maint_publisher_location'); -- set a maint message return; -- and done end end end --[[--------------------------< I S _ P A G E _ A R T _ N U M >------------------------------------------------ compare the trailing (rightmost) characters of the |doi= value against the whole value assigned to |page(s)=. return boolean true when: |page(s)= has exactly 8 digits and a dot between the fourth and fifth digits matches the trailing 9 characters of the |doi= value: |page=12345678 → |page=1234.5678 matches |doi=10.xxxx/yyyy1234.5678 |page(s)= is 5 or more characters and matches |doi= values's trailing characters |page(s)= begins with a lowercase 'e' and |page(s)= without the 'e' matches |doi= values's trailing characters: |page=e12345 → |page=12345 matches |doi=10.xxxx/yyyy12345 |page(s)= begins with a uppercase 'CD' followed by (typically) six digits matches |doi= values that ends with 'CDxxxxxx.pubx' (where 'x' is any single digit) return nil when |page(s)= values: are ranges separated by underscore, hyphen, emdash, endash, figure dash, or minus character are comma- or semicolon-separated lists of pages have external urls (has text 'http') are digit-only values less than 10000 do not match |doi= values's trailing characters ]] local function is_page_art_num (page, doi) if not (utilities.is_set (page) and utilities.is_set (doi)) then -- both required return; -- abandon; nothing to do end if page:match ('[,;_−–—‒%-]') then -- when |page(s)= might be a page range or a separated list of pages return; -- abandon end page = page:lower(); -- because doi names are case insensitive doi = doi:lower(); -- force these to lowercase for testing if page:match ('http') then -- when |page(s)= appears to hold a url return; -- abandon end if tonumber (page) then -- is |page(s)= digits only if 10000 > tonumber (page) then -- when |page(s)= less than 10000 return; -- abandon end if doi:match (page .. '$') then -- digits only page number match the last digits in |doi=? return true; end if 8 == page:len() then -- special case when |page(s)= is exactly 8 digits local dot_page = page:gsub ('(%d%d%d%d)(%d%d%d%d)', '%1.%2'); -- make a |page=xxxx.yyyy version commonly used in |doi= if doi:match (dot_page .. '$') then -- 8-digit dotted page number match the last characters in |doi=? return true; end end else -- here when |page(s)= is alpha-numeric if 4 < page:len() then -- when |page(s)= is five or more characters if doi:match (page .. '$') then -- alpha-numeric page match the last characters in |doi=? return true; end local epage = page:match ('^e([%w]+)$'); -- if first character of |page= is 'e', remove it if epage and doi:match (epage .. '$') then -- page number match the last characters in |doi=? return true; end local cdpage = page:match ('^cd%d+$'); -- if first characters of |page= are 'CD' and last characters are digits (typically 6 digits) if cdpage and doi:match (cdpage .. '%.pub%d$') then -- page number matches doi 'CDxxxxxx.pubx' where 'x' is a digit return true; end end end end --[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------ This is the main function doing the majority of the citation formatting. ]] local function citation0( config, args ) --[[ Load Input Parameters The argument_wrapper facilitates the mapping of multiple aliases to single internal variable. ]] local A = argument_wrapper ( args ); local i -- Pick out the relevant fields from the arguments. Different citation templates -- define different field names for the same underlying things. local author_etal; local a = {}; -- authors list from |lastn= / |firstn= pairs or |vauthors= local Authors; local NameListStyle; if cfg.global_cs1_config_t['NameListStyle'] then -- global setting in {{cs1 config}} overrides local |name-list-style= parameter value; nil when empty or assigned value invalid NameListStyle = is_valid_parameter_value (cfg.global_cs1_config_t['NameListStyle'], 'cs1 config: name-list-style', cfg.keywords_lists['name-list-style'], ''); -- error messaging 'param' here is a hoax else NameListStyle = is_valid_parameter_value (A['NameListStyle'], A:ORIGIN('NameListStyle'), cfg.keywords_lists['name-list-style'], ''); end if cfg.global_cs1_config_t['NameListStyle'] and utilities.is_set (A['NameListStyle']) then -- when template has |name-list-style=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end local Collaboration = A['Collaboration']; do -- to limit scope of selected local selected = select_author_editor_source (A['Vauthors'], A['Authors'], args, 'AuthorList'); if 1 == selected then a, author_etal = extract_names (args, 'AuthorList'); -- fetch author list from |authorn= / |lastn= / |firstn=, |author-linkn=, and |author-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be a, author_etal = parse_vauthors_veditors (args, A['Vauthors'], 'AuthorList'); -- fetch author list from |vauthors=, |author-linkn=, and |author-maskn= elseif 3 == selected then Authors = A['Authors']; -- use content of |people= or |credits=; |authors= is deprecated; TODO: constrain |people= and |credits= to cite av media, episode, serial? end if utilities.is_set (Collaboration) then author_etal = true; -- so that |display-authors=etal not required end end local editor_etal; local e = {}; -- editors list from |editor-lastn= / |editor-firstn= pairs or |veditors= do -- to limit scope of selected local selected = select_author_editor_source (A['Veditors'], nil, args, 'EditorList'); -- support for |editors= withdrawn if 1 == selected then e, editor_etal = extract_names (args, 'EditorList'); -- fetch editor list from |editorn= / |editor-lastn= / |editor-firstn=, |editor-linkn=, and |editor-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be e, editor_etal = parse_vauthors_veditors (args, args.veditors, 'EditorList'); -- fetch editor list from |veditors=, |editor-linkn=, and |editor-maskn= end end local Chapter = A['Chapter']; -- done here so that we have access to |contribution= from |chapter= aliases local Chapter_origin = A:ORIGIN ('Chapter'); local Contribution; -- because contribution is required for contributor(s) if 'contribution' == Chapter_origin then Contribution = Chapter; -- get the name of the contribution end local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (A['Periodical']) then -- |contributor= and |contribution= only supported in book cites c = extract_names (args, 'ContributorList'); -- fetch contributor list from |contributorn= / |contributor-lastn=, -firstn=, -linkn=, -maskn= if 0 < #c then if not utilities.is_set (Contribution) then -- |contributor= requires |contribution= utilities.set_message ('err_contributor_missing_required_param', 'contribution'); -- add missing contribution error message c = {}; -- blank the contributors' table; it is used as a flag later end if 0 == #a then -- |contributor= requires |author= utilities.set_message ('err_contributor_missing_required_param', 'author'); -- add missing author error message c = {}; -- blank the contributors' table; it is used as a flag later end end else -- if not a book cite if utilities.select_one (args, cfg.aliases['ContributorList-Last'], 'err_redundant_parameters', 1 ) then -- are there contributor name list parameters? utilities.set_message ('err_contributor_ignored'); -- add contributor ignored error message end Contribution = nil; -- unset end local Title = A['Title']; local TitleLink = A['TitleLink']; local auto_select = ''; -- default is auto local accept_link; TitleLink, accept_link = utilities.has_accept_as_written (TitleLink, true); -- test for accept-this-as-written markup if (not accept_link) and utilities.in_array (TitleLink, {'none', 'pmc', 'doi'}) then -- check for special keywords auto_select = TitleLink; -- remember selection for later TitleLink = ''; -- treat as if |title-link= would have been empty end TitleLink = link_title_ok (TitleLink, A:ORIGIN ('TitleLink'), Title, 'title'); -- check for wiki-markup in |title-link= or wiki-markup in |title= when |title-link= is set local Section = ''; -- {{cite map}} only; preset to empty string for concatenation if not used if 'map' == config.CitationClass and 'section' == Chapter_origin then Section = A['Chapter']; -- get |section= from |chapter= alias list; |chapter= and the other aliases not supported in {{cite map}} Chapter = ''; -- unset for now; will be reset later from |map= if present end local Periodical = A['Periodical']; local Periodical_origin = A:ORIGIN('Periodical'); local ScriptPeriodical = A['ScriptPeriodical']; local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical'); local TransPeriodical = A['TransPeriodical']; local TransPeriodical_origin = A:ORIGIN ('TransPeriodical'); if (utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical))) then local param; if utilities.is_set (Periodical) then -- get a parameter name from one of these periodical related meta-parameters Periodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = Periodical_origin -- get parameter name for error messaging elseif utilities.is_set (TransPeriodical) then TransPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = TransPeriodical_origin; -- get parameter name for error messaging elseif utilities.is_set (ScriptPeriodical) then ScriptPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = ScriptPeriodical_origin; -- get parameter name for error messaging end if utilities.is_set (param) then -- if we found one utilities.set_message ('err_periodical_ignored', {param}); -- emit an error message end end if utilities.is_set (Periodical) then local i; Periodical, i = utilities.strip_apostrophe_markup (Periodical); -- strip apostrophe markup so that metadata isn't contaminated if i then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {Periodical_origin}); end end if 'mailinglist' == config.CitationClass then -- special case for {{cite mailing list}} if utilities.is_set (Periodical) and utilities.is_set (A ['MailingList']) then -- both set emit an error TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', Periodical_origin) .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'mailinglist')}); end Periodical = A ['MailingList']; -- error or no, set Periodical to |mailinglist= value because this template is {{cite mailing list}} Periodical_origin = A:ORIGIN('MailingList'); end -- web and news not tested for now because of -- Wikipedia:Administrators%27_noticeboard#Is_there_a_semi-automated_tool_that_could_fix_these_annoying_"Cite_Web"_errors? if not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) then -- 'periodical' templates require periodical parameter -- local p = {['journal'] = 'journal', ['magazine'] = 'magazine', ['news'] = 'newspaper', ['web'] = 'website'}; -- for error message local p = {['journal'] = 'journal', ['magazine'] = 'magazine'}; -- for error message if p[config.CitationClass] then utilities.set_message ('err_missing_periodical', {config.CitationClass, p[config.CitationClass]}); end end local Volume; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) then if not utilities.in_array (Periodical_origin, cfg.citation_no_volume_t) then -- {{citation}} does not render |volume= when these parameters are used Volume = A['Volume']; -- but does for all other 'periodicals' end elseif utilities.is_set (ScriptPeriodical) then if 'script-website' ~= ScriptPeriodical_origin then -- {{citation}} does not render volume for |script-website= Volume = A['Volume']; -- but does for all other 'periodicals' end else Volume = A['Volume']; -- and does for non-'periodical' cites end elseif utilities.in_array (config.CitationClass, cfg.templates_using_volume) then -- render |volume= for cs1 according to the configuration settings Volume = A['Volume']; end extra_text_in_vol_iss_check (Volume, A:ORIGIN ('Volume'), 'v'); local Issue; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) and utilities.in_array (Periodical_origin, cfg.citation_issue_t) then -- {{citation}} may render |issue= when these parameters are used Issue = A['Issue']; end elseif utilities.in_array (config.CitationClass, cfg.templates_using_issue) then -- conference & map books do not support issue; {{citation}} listed here because included in settings table if not (utilities.in_array (config.CitationClass, {'conference', 'map', 'citation'}) and not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical))) then Issue = A['Issue']; end end local ArticleNumber; if utilities.in_array (config.CitationClass, {'journal', 'conference'}) or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then ArticleNumber = A['ArticleNumber']; end extra_text_in_vol_iss_check (Issue, A:ORIGIN ('Issue'), 'i'); Issue = utilities.hyphen_to_dash (Issue); local Page; local Pages; local At; local QuotePage; local QuotePages; if not utilities.in_array (config.CitationClass, cfg.templates_not_using_page) then -- TODO: rewrite to emit ignored parameter error message? Page = A['Page']; Pages = utilities.hyphen_to_dash (A['Pages']); At = A['At']; QuotePage = A['QuotePage']; QuotePages = utilities.hyphen_to_dash (A['QuotePages']); end local NoPP = is_valid_parameter_value (A['NoPP'], A:ORIGIN('NoPP'), cfg.keywords_lists['yes_true_y'], nil); local Mode = mode_set (A['Mode'], A:ORIGIN('Mode')); -- separator character and postscript local sepc, PostScript = set_style (Mode:lower(), A['PostScript'], config.CitationClass); local Quote; Quote, QuotePage, QuotePages, PostScript = quote_make (A['Quote'], A['TransQuote'], A['ScriptQuote'], QuotePage, QuotePages, NoPP, sepc, PostScript); local Edition = A['Edition']; local PublicationPlace = place_check (A['PublicationPlace'], A:ORIGIN('PublicationPlace')); local Place = place_check (A['Place'], A:ORIGIN('Place')); local PublisherName = A['PublisherName']; local PublisherName_origin = A:ORIGIN('PublisherName'); if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then local i = 0; PublisherName, i = utilities.strip_apostrophe_markup (PublisherName); -- strip apostrophe markup so that metadata isn't contaminated; publisher is never italicized if i and (0 < i) then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {PublisherName_origin}); end end if ('document' == config.CitationClass) and not utilities.is_set (PublisherName) then utilities.set_message ('err_missing_publisher', {config.CitationClass, 'publisher'}); end local Newsgroup = A['Newsgroup']; -- TODO: strip apostrophe markup? local Newsgroup_origin = A:ORIGIN('Newsgroup'); if 'newsgroup' == config.CitationClass then if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then -- general use parameter |publisher= not allowed in cite newsgroup utilities.set_message ('err_parameter_ignored', {PublisherName_origin}); end PublisherName = nil; -- ensure that this parameter is unset for the time being; will be used again after COinS end if 'book' == config.CitationClass or 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then local accept; PublisherName, accept = utilities.has_accept_as_written (PublisherName); -- check for and remove accept-as-written markup from |publisher= wrapped if not accept then -- when no accept-as-written markup check_publisher_name (PublisherName); -- emit maint message when |publisher= might be prefixed with publisher's location end end local URL = A['URL']; -- TODO: better way to do this for URL, ChapterURL, and MapURL? local UrlAccess = is_valid_parameter_value (A['UrlAccess'], A:ORIGIN('UrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (URL) and utilities.is_set (UrlAccess) then UrlAccess = nil; utilities.set_message ('err_param_access_requires_param', 'url'); end local ChapterURL = A['ChapterURL']; local ChapterUrlAccess = is_valid_parameter_value (A['ChapterUrlAccess'], A:ORIGIN('ChapterUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (ChapterURL) and utilities.is_set (ChapterUrlAccess) then ChapterUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {A:ORIGIN('ChapterUrlAccess'):gsub ('%-access', '')}); end local MapUrlAccess = is_valid_parameter_value (A['MapUrlAccess'], A:ORIGIN('MapUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (A['MapURL']) and utilities.is_set (MapUrlAccess) then MapUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {'map-url'}); end local this_page = mw.title.getCurrentTitle(); -- also used for COinS and for language local no_tracking_cats = is_valid_parameter_value (A['NoTracking'], A:ORIGIN('NoTracking'), cfg.keywords_lists['yes_true_y'], nil); -- check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories if not utilities.is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page if cfg.uncategorized_namespaces[this_page.namespace] then -- is this page's namespace id one of the uncategorized namespace ids? no_tracking_cats = "true"; -- set no_tracking_cats end for _, v in ipairs (cfg.uncategorized_subpages) do -- cycle through page name patterns if this_page.text:match (v) then -- test page name against each pattern no_tracking_cats = "true"; -- set no_tracking_cats break; -- bail out if one is found end end end -- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it) utilities.select_one (args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'err_redundant_parameters'); -- this is a dummy call simply to get the error message and category local coins_pages; Page, Pages, At, coins_pages = insource_loc_get (Page, A:ORIGIN('Page'), Pages, A:ORIGIN('Pages'), At); if utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- both |publication-place= and |place= (|location=) allowed if different utilities.add_prop_cat ('location-test'); -- add property cat to evaluate how often PublicationPlace and Place are used together if PublicationPlace == Place then Place = ''; -- unset; don't need both if they are the same end elseif not utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- when only |place= (|location=) is set ... PublicationPlace = Place; -- promote |place= (|location=) to |publication-place end if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same local URL_origin = A:ORIGIN('URL'); -- get name of parameter that holds URL local ChapterURL_origin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL local ScriptChapter = A['ScriptChapter']; local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); local Format = A['Format']; local ChapterFormat = A['ChapterFormat']; local TransChapter = A['TransChapter']; local TransChapter_origin = A:ORIGIN ('TransChapter'); local TransTitle = A['TransTitle']; local ScriptTitle = A['ScriptTitle']; --[[ Parameter remapping for cite encyclopedia: When the citation has these parameters: |encyclopedia= and |title= then map |title= to |article= and |encyclopedia= to |title= for rendering |encyclopedia= and |article= then map |encyclopedia= to |title= for rendering |trans-title= maps to |trans-chapter= when |title= is re-mapped |url= maps to |chapter-url= when |title= is remapped All other combinations of |encyclopedia=, |title=, and |article= are not modified ]] local Encyclopedia = A['Encyclopedia']; -- used as a flag by this module and by ~/COinS local ScriptEncyclopedia = A['ScriptEncyclopedia']; local TransEncyclopedia = A['TransEncyclopedia']; if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then -- emit error message when Encyclopedia set but template is other than {{cite encyclopedia}} or {{citation}} if 'encyclopaedia' ~= config.CitationClass and 'citation' ~= config.CitationClass then if utilities.is_set (Encyclopedia) then utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('Encyclopedia')}); else utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('ScriptEncyclopedia')}); end Encyclopedia = nil; -- unset these because not supported by this template ScriptEncyclopedia = nil; TransEncyclopedia = nil; end elseif utilities.is_set (TransEncyclopedia) then utilities.set_message ('err_trans_missing_title', {'encyclopedia'}); end if ('encyclopaedia' == config.CitationClass) or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Periodical) and utilities.is_set (Encyclopedia) then -- when both parameters set emit an error message; {{citation}} only; Periodical not allowed in {{cite encyclopedia}} utilities.set_message ('err_periodical_ignored', {Periodical_origin}); end if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then Periodical = Encyclopedia; -- error or no, set Periodical to Encyclopedia for rendering; {{citation}} could (not legitimately) have both; use Encyclopedia Periodical_origin = A:ORIGIN ('Encyclopedia'); ScriptPeriodical = ScriptEncyclopedia; ScriptPeriodical_origin = A:ORIGIN ('ScriptEncyclopedia'); if utilities.is_set (Title) or utilities.is_set (ScriptTitle) then if not utilities.is_set (Chapter) then Chapter = Title; -- |encyclopedia= and |title= are set so map |title= params to |article= params for rendering ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle') TransChapter = TransTitle; ChapterURL = URL; ChapterURL_origin = URL_origin; ChapterUrlAccess = UrlAccess; ChapterFormat = Format; if not utilities.is_set (ChapterURL) and utilities.is_set (TitleLink) then Chapter = utilities.make_wikilink (TitleLink, Chapter); end Title = Periodical; -- now map |encyclopedia= params to |title= params for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; URL = ''; Format = ''; TitleLink = ''; end elseif utilities.is_set (Chapter) or utilities.is_set (ScriptChapter) then -- |title= not set Title = Periodical; -- |encyclopedia= set and |article= set so map |encyclopedia= to |title= for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; end end end -- special case for cite techreport. local ID = A['ID']; if (config.CitationClass == "techreport") then -- special case for cite techreport if utilities.is_set (A['Number']) then -- cite techreport uses 'number', which other citations alias to 'issue' if not utilities.is_set (ID) then -- can we use ID for the "number"? ID = A['Number']; -- yes, use it else -- ID has a value so emit error message utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'id') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'number')}); end end end -- Account for the oddity that is {{cite conference}}, before generation of COinS data. local ChapterLink -- = A['ChapterLink']; -- deprecated as a parameter but still used internally by cite episode local Conference = A['Conference']; local BookTitle = A['BookTitle']; local TransTitle_origin = A:ORIGIN ('TransTitle'); if 'conference' == config.CitationClass then if utilities.is_set (BookTitle) then Chapter = Title; Chapter_origin = 'title'; -- ChapterLink = TitleLink; -- |chapter-link= is deprecated ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; URL_origin = ''; ChapterFormat = Format; TransChapter = TransTitle; TransChapter_origin = TransTitle_origin; Title = BookTitle; Format = ''; -- TitleLink = ''; TransTitle = ''; URL = ''; end elseif 'speech' ~= config.CitationClass then Conference = ''; -- not cite conference or cite speech so make sure this is empty string end local cs2_lower = function (text) -- if mode is cs2, use lower case if (sepc ~= '.') then return text:lower(); end return text; end local use_lowercase = ( sepc == ',' ); -- controls capitalization of certain static text -- cite map oddities local Cartography = ""; local Scale = ""; local Sheet = A['Sheet'] or ''; local Sheets = A['Sheets'] or ''; if config.CitationClass == "map" then if utilities.is_set (Chapter) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'map') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', Chapter_origin)}); -- add error message end Chapter = A['Map']; Chapter_origin = A:ORIGIN('Map'); ChapterURL = A['MapURL']; ChapterURL_origin = A:ORIGIN('MapURL'); TransChapter = A['TransMap']; ScriptChapter = A['ScriptMap'] ScriptChapter_origin = A:ORIGIN('ScriptMap') ChapterUrlAccess = MapUrlAccess; ChapterFormat = A['MapFormat']; Cartography = A['Cartography']; if utilities.is_set ( Cartography ) then Cartography = sepc .. " " .. wrap_msg ('cartography', Cartography, use_lowercase); end Scale = A['Scale']; if utilities.is_set ( Scale ) then Scale = sepc .. " " .. Scale; end end -- Account for the oddities that are {{cite episode}} and {{cite serial}}, before generation of COinS data. local Series = A['Series']; if 'episode' == config.CitationClass or 'serial' == config.CitationClass then local SeriesLink = A['SeriesLink']; SeriesLink = link_title_ok (SeriesLink, A:ORIGIN ('SeriesLink'), Series, 'series'); -- check for wiki-markup in |series-link= or wiki-markup in |series= when |series-link= is set local Network = A['Network']; local Station = A['Station']; local s, n = {}, {}; -- do common parameters first if utilities.is_set (Network) then table.insert(n, Network); end if utilities.is_set (Station) then table.insert(n, Station); end ID = table.concat(n, sepc .. ' '); if 'episode' == config.CitationClass then -- handle the oddities that are strictly {{cite episode}} local Season = A['Season']; local SeriesNumber = A['SeriesNumber']; if utilities.is_set (Season) and utilities.is_set (SeriesNumber) then -- these are mutually exclusive so if both are set TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'season') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'seriesno')}); -- add error message SeriesNumber = ''; -- unset; prefer |season= over |seriesno= end -- assemble a table of parts concatenated later into Series if utilities.is_set (Season) then table.insert(s, wrap_msg ('season', Season, use_lowercase)); end if utilities.is_set (SeriesNumber) then table.insert(s, wrap_msg ('seriesnum', SeriesNumber, use_lowercase)); end if utilities.is_set (Issue) then table.insert(s, wrap_msg ('episode', Issue, use_lowercase)); end Issue = ''; -- unset because this is not a unique parameter Chapter = Title; -- promote title parameters to chapter ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle'); ChapterLink = TitleLink; -- alias |episode-link= TransChapter = TransTitle; ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; ChapterFormat = Format; Title = Series; -- promote series to title TitleLink = SeriesLink; Series = table.concat(s, sepc .. ' '); -- this is concatenation of season, seriesno, episode number if utilities.is_set (ChapterLink) and not utilities.is_set (ChapterURL) then -- link but not URL Chapter = utilities.make_wikilink (ChapterLink, Chapter); elseif utilities.is_set (ChapterLink) and utilities.is_set (ChapterURL) then -- if both are set, URL links episode; Series = utilities.make_wikilink (ChapterLink, Series); end URL = ''; -- unset TransTitle = ''; ScriptTitle = ''; Format = ''; else -- now oddities that are cite serial Issue = ''; -- unset because this parameter no longer supported by the citation/core version of cite serial Chapter = A['Episode']; -- TODO: make |episode= available to cite episode someday? if utilities.is_set (Series) and utilities.is_set (SeriesLink) then Series = utilities.make_wikilink (SeriesLink, Series); end Series = utilities.wrap_style ('italic-title', Series); -- series is italicized end end -- end of {{cite episode}} stuff -- handle type parameter for those CS1 citations that have default values local TitleType = A['TitleType']; local Degree = A['Degree']; if utilities.in_array (config.CitationClass, {'AV-media-notes', 'document', 'interview', 'mailinglist', 'map', 'podcast', 'pressrelease', 'report', 'speech', 'techreport', 'thesis'}) then TitleType = set_titletype (config.CitationClass, TitleType); if utilities.is_set (Degree) and "Thesis" == TitleType then -- special case for cite thesis TitleType = Degree .. ' ' .. cfg.title_types ['thesis']:lower(); end end if utilities.is_set (TitleType) then -- if type parameter is specified TitleType = utilities.substitute ( cfg.messages['type'], TitleType); -- display it in parentheses -- TODO: Hack on TitleType to fix bunched parentheses problem end -- legacy: promote PublicationDate to Date if neither Date nor Year are set. local Date = A['Date']; local Date_origin; -- to hold the name of parameter promoted to Date; required for date error messaging local PublicationDate = A['PublicationDate']; local Year = A['Year']; if utilities.is_set (Year) then validation.year_check (Year); -- returns nothing; emits maint message when |year= doesn't hold a 'year' value end if not utilities.is_set (Date) then Date = Year; -- promote Year to Date Year = nil; -- make nil so Year as empty string isn't used for CITEREF if not utilities.is_set (Date) and utilities.is_set (PublicationDate) then -- use PublicationDate when |date= and |year= are not set Date = PublicationDate; -- promote PublicationDate to Date PublicationDate = ''; -- unset, no longer needed Date_origin = A:ORIGIN('PublicationDate'); -- save the name of the promoted parameter else Date_origin = A:ORIGIN('Year'); -- save the name of the promoted parameter end else Date_origin = A:ORIGIN('Date'); -- not a promotion; name required for error messaging end if PublicationDate == Date then PublicationDate = ''; end -- if PublicationDate is same as Date, don't display in rendered citation --[[ Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates. This must be done before we do COinS because here is where we get the date used in the metadata. Date validation supporting code is in Module:Citation/CS1/Date_validation ]] local DF = is_valid_parameter_value (A['DF'], A:ORIGIN('DF'), cfg.keywords_lists['df'], ''); if not utilities.is_set (DF) then DF = cfg.global_df; -- local |df= if present overrides global df set by {{use xxx date}} template end local ArchiveURL; local ArchiveDate; local ArchiveFormat = A['ArchiveFormat']; local archive_url_timestamp; -- timestamp from wayback machine url ArchiveURL, ArchiveDate, archive_url_timestamp = archive_url_check (A['ArchiveURL'], A['ArchiveDate']) ArchiveFormat = style_format (ArchiveFormat, ArchiveURL, 'archive-format', 'archive-url'); ArchiveURL, ArchiveDate = is_unique_archive_url (ArchiveURL, URL, ChapterURL, A:ORIGIN('ArchiveURL'), ArchiveDate); -- add error message when URL or ChapterURL == ArchiveURL local AccessDate = A['AccessDate']; local COinS_date = {}; -- holds date info extracted from |date= for the COinS metadata by Module:Date verification local DoiBroken = A['DoiBroken']; local Embargo = A['Embargo']; local anchor_year; -- used in the CITEREF identifier do -- create defined block to contain local variables error_message, date_parameters_list, mismatch local error_message = ''; -- AirDate has been promoted to Date so not necessary to check it local date_parameters_list = { ['access-date'] = {val = AccessDate, name = A:ORIGIN ('AccessDate')}, ['archive-date'] = {val = ArchiveDate, name = A:ORIGIN ('ArchiveDate')}, ['date'] = {val = Date, name = Date_origin}, ['doi-broken-date'] = {val = DoiBroken, name = A:ORIGIN ('DoiBroken')}, ['pmc-embargo-date'] = {val = Embargo, name = A:ORIGIN ('Embargo')}, ['publication-date'] = {val = PublicationDate, name = A:ORIGIN ('PublicationDate')}, ['year'] = {val = Year, name = A:ORIGIN ('Year')}, }; local error_list = {}; anchor_year, Embargo = validation.dates(date_parameters_list, COinS_date, error_list); if utilities.is_set (Year) and utilities.is_set (Date) then -- both |date= and |year= not normally needed; validation.year_date_check (Year, A:ORIGIN ('Year'), Date, A:ORIGIN ('Date'), error_list); end if 0 == #error_list then -- error free dates only; 0 when error_list is empty local modified = false; -- flag if utilities.is_set (DF) then -- if we need to reformat dates modified = validation.reformat_dates (date_parameters_list, DF); -- reformat to DF format, use long month names if appropriate end if true == validation.date_hyphen_to_dash (date_parameters_list) then -- convert hyphens to dashes where appropriate modified = true; utilities.set_message ('maint_date_format'); -- hyphens were converted so add maint category end -- for those wikis that can and want to have English date names translated to the local language; not supported at en.wiki if cfg.date_name_auto_xlate_enable and validation.date_name_xlate (date_parameters_list, cfg.date_digit_auto_xlate_enable ) then utilities.set_message ('maint_date_auto_xlated'); -- add maint cat modified = true; end if modified then -- if the date_parameters_list values were modified AccessDate = date_parameters_list['access-date'].val; -- overwrite date holding parameters with modified values ArchiveDate = date_parameters_list['archive-date'].val; Date = date_parameters_list['date'].val; DoiBroken = date_parameters_list['doi-broken-date'].val; PublicationDate = date_parameters_list['publication-date'].val; end if archive_url_timestamp and utilities.is_set (ArchiveDate) then validation.archive_date_check (ArchiveDate, archive_url_timestamp, DF); -- does YYYYMMDD in archive_url_timestamp match date in ArchiveDate end else utilities.set_message ('err_bad_date', {utilities.make_sep_list (#error_list, error_list)}); -- add this error message end end -- end of do if utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) or -- {{cite book}}, {{cite encyclopedia}}; TODO: {{cite conference}} and others? ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) or -- {{citation}} as an encylopedia citation ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then -- {{citation}} as a book citation if utilities.is_set (PublicationPlace) then if not utilities.is_set (PublisherName) then local date = COinS_date.rftdate and tonumber (COinS_date.rftdate:match ('%d%d%d%d')); -- get year portion of COinS date (because in Arabic numerals); convert string to number if date and (1850 <= date) then -- location has no publisher; if date is 1850 or later utilities.set_message ('maint_location_no_publisher'); -- add maint cat end else -- PublisherName has a value if cfg.keywords_xlate['none'] == PublisherName then -- if that value is 'none' (only for book and encyclopedia citations) PublisherName = ''; -- unset end end end end local ID_list = {}; -- sequence table of rendered identifiers local ID_list_coins = {}; -- table of identifiers and their values from args; key is same as cfg.id_handlers's key local Class = A['Class']; -- arxiv class identifier local ID_support = { {A['ASINTLD'], 'ASIN', 'err_asintld_missing_asin', A:ORIGIN ('ASINTLD')}, {DoiBroken, 'DOI', 'err_doibroken_missing_doi', A:ORIGIN ('DoiBroken')}, {Embargo, 'PMC', 'err_embargo_missing_pmc', A:ORIGIN ('Embargo')}, } ID_list, ID_list_coins = identifiers.identifier_lists_get (args, { DoiBroken = DoiBroken, -- for |doi= ASINTLD = A['ASINTLD'], -- for |asin= Embargo = Embargo, -- for |pmc= Class = Class, -- for |arxiv= CitationClass = config.CitationClass, -- for |arxiv= Year=anchor_year, -- for |isbn= }, ID_support); if 'citation' == config.CitationClass then -- catch ve/citoid malformed book cites in {{citation}} templates for _, id in ipairs (ID_list) do -- search through the ID_list sequence looking for an ISBN identifier string if id:find ('ISBN', 3, true) then -- plain find, start at index 3 ([[ISBN) if utilities.is_set (Periodical) then -- when a |work= alias is set utilities.set_message ('maint_work_isbn'); -- add maint cat end end end end -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, {{cite ssrn}}, before generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv=, |citeseerx=, |medrxiv=, |ssrn= required for their templates if not (args[cfg.id_handlers[config.CitationClass:upper()].parameters[1]] or -- can't use ID_list_coins k/v table here because invalid parameters omitted args[cfg.id_handlers[config.CitationClass:upper()].parameters[2]]) then -- which causes unexpected parameter missing error message utilities.set_message ('err_' .. config.CitationClass .. '_missing'); -- add error message end Periodical = ({['arxiv'] = 'arXiv', ['biorxiv'] = 'bioRxiv', ['citeseerx'] = 'CiteSeerX', ['medrxiv'] = 'medRxiv', ['ssrn'] = 'Social Science Research Network'})[config.CitationClass]; end -- Link the title of the work if no |url= was provided, but we have a |pmc= or a |doi= with |doi-access=free if config.CitationClass == "journal" and not utilities.is_set (URL) and not utilities.is_set (TitleLink) and not utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) then -- TODO: remove 'none' once existing citations have been switched to 'off', so 'none' can be used as token for "no title" instead if 'none' ~= cfg.keywords_xlate[auto_select] then -- if auto-linking not disabled if identifiers.auto_link_urls[auto_select] then -- manual selection URL = identifiers.auto_link_urls[auto_select]; -- set URL to be the same as identifier's external link URL_origin = cfg.id_handlers[auto_select:upper()].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['pmc'] then -- auto-select PMC URL = identifiers.auto_link_urls['pmc']; -- set URL to be the same as the PMC external link if not embargoed URL_origin = cfg.id_handlers['PMC'].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['doi'] then -- auto-select DOI URL = identifiers.auto_link_urls['doi']; URL_origin = cfg.id_handlers['DOI'].parameters[1]; end end if utilities.is_set (URL) then -- set when using an identifier-created URL if utilities.is_set (AccessDate) then -- |access-date= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_accessdate_missing_url'); -- add an error message AccessDate = ''; -- unset end if utilities.is_set (ArchiveURL) then -- |archive-url= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_archive_missing_url'); -- add an error message ArchiveURL = ''; -- unset end end end -- At this point fields may be nil if they weren't specified in the template use. We can use that fact. -- Test if citation has no title if not utilities.is_set (Title) and not utilities.is_set (TransTitle) and not utilities.is_set (ScriptTitle) then -- has special case for cite episode utilities.set_message ('err_citation_missing_title', {'episode' == config.CitationClass and 'series' or 'title'}); end if utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) and utilities.in_array (config.CitationClass, {'journal', 'citation'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and ('journal' == Periodical_origin or 'script-journal' == ScriptPeriodical_origin) then -- special case for journal cites Title = ''; -- set title to empty string utilities.set_message ('maint_untitled'); -- add maint cat end if 'journal' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then if is_page_art_num (((utilities.is_set (Page) and Page) or (utilities.is_set (Pages) and Pages)) or nil, ID_list_coins['DOI']) then -- does |page(s)= look like it holds an article number utilities.set_message ('maint_page_art_num'); -- add maint cat end end -- COinS metadata (see <http://ocoins.info/>) for automated parsing of citation information. -- handle the oddity that is cite encyclopedia and {{citation |encyclopedia=something}}. Here we presume that -- when Periodical, Title, and Chapter are all set, then Periodical is the book (encyclopedia) title, Title -- is the article title, and Chapter is a section within the article. So, we remap local coins_chapter = Chapter; -- default assuming that remapping not required local coins_title = Title; -- et tu if 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Chapter) and utilities.is_set (Title) and utilities.is_set (Periodical) then -- if all are used then coins_chapter = Title; -- remap coins_title = Periodical; end end local coins_author = a; -- default for coins rft.au if 0 < #c then -- but if contributor list coins_author = c; -- use that instead end -- this is the function call to COinS() local OCinSoutput = metadata.COinS({ ['Periodical'] = utilities.strip_apostrophe_markup (Periodical), -- no markup in the metadata ['Encyclopedia'] = Encyclopedia, -- just a flag; content ignored by ~/COinS ['Chapter'] = metadata.make_coins_title (coins_chapter, ScriptChapter), -- Chapter and ScriptChapter stripped of bold / italic / accept-as-written markup ['Degree'] = Degree; -- cite thesis only ['Title'] = metadata.make_coins_title (coins_title, ScriptTitle), -- Title and ScriptTitle stripped of bold / italic / accept-as-written markup ['PublicationPlace'] = PublicationPlace, ['Date'] = COinS_date.rftdate, -- COinS_date.* has correctly formatted date values if Date is valid; ['Season'] = COinS_date.rftssn, ['Quarter'] = COinS_date.rftquarter, ['Chron'] = COinS_date.rftchron, ['Series'] = Series, ['Volume'] = Volume, ['Issue'] = Issue, ['ArticleNumber'] = ArticleNumber, ['Pages'] = coins_pages or metadata.get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At, QuotePage, QuotePages}, 7)), -- pages stripped of external links ['Edition'] = Edition, ['PublisherName'] = PublisherName or Newsgroup, -- any apostrophe markup already removed from PublisherName ['URL'] = first_set ({ChapterURL, URL}, 2), ['Authors'] = coins_author, ['ID_list'] = ID_list_coins, ['RawPage'] = this_page.prefixedText, }, config.CitationClass); -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, and {{cite ssrn}} AFTER generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- we have set rft.jtitle in COinS to arXiv, bioRxiv, CiteSeerX, medRxiv, or ssrn now unset so it isn't displayed Periodical = ''; -- periodical not allowed in these templates; if article has been published, use cite journal end -- special case for cite newsgroup. Do this after COinS because we are modifying Publishername to include some static text if 'newsgroup' == config.CitationClass and utilities.is_set (Newsgroup) then PublisherName = utilities.substitute (cfg.messages['newsgroup'], external_link( 'news:' .. Newsgroup, Newsgroup, Newsgroup_origin, nil )); end local Editors; local EditorCount; -- used only for choosing {ed.) or (eds.) annotation at end of editor name-list local Contributors; -- assembled contributors name list local contributor_etal; local Translators; -- assembled translators name list local translator_etal; local t = {}; -- translators list from |translator-lastn= / translator-firstn= pairs t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= local Interviewers; local interviewers_list = {}; interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters local interviewer_etal; -- Now perform various field substitutions. -- We also add leading spaces and surrounding markup and punctuation to the -- various parts of the citation, but only when they are non-nil. do local last_first_list; local control = { format = NameListStyle, -- empty string, '&', 'amp', 'and', or 'vanc' maximum = nil, -- as if display-authors or display-editors not set mode = Mode }; do -- do editor name list first because the now unsupported coauthors used to modify control table local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayEditors'], A['DisplayEditors'], A:ORIGIN ('DisplayEditors'), #e); control.maximum, editor_etal = get_display_names (display_names, #e, 'editors', editor_etal, param); Editors, EditorCount = list_people (control, e, editor_etal); if 1 == EditorCount and (true == editor_etal or 1 < #e) then -- only one editor displayed but includes etal then EditorCount = 2; -- spoof to display (eds.) annotation end end do -- now do interviewers local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayInterviewers'], A['DisplayInterviewers'], A:ORIGIN ('DisplayInterviewers'), #interviewers_list); control.maximum, interviewer_etal = get_display_names (display_names, #interviewers_list, 'interviewers', interviewer_etal, param); Interviewers = list_people (control, interviewers_list, interviewer_etal); end do -- now do translators local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayTranslators'], A['DisplayTranslators'], A:ORIGIN ('DisplayTranslators'), #t); control.maximum, translator_etal = get_display_names (display_names, #t, 'translators', translator_etal, param); Translators = list_people (control, t, translator_etal); end do -- now do contributors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayContributors'], A['DisplayContributors'], A:ORIGIN ('DisplayContributors'), #c); control.maximum, contributor_etal = get_display_names (display_names, #c, 'contributors', contributor_etal, param); Contributors = list_people (control, c, contributor_etal); end do -- now do authors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayAuthors'], A['DisplayAuthors'], A:ORIGIN ('DisplayAuthors'), #a, author_etal); control.maximum, author_etal = get_display_names (display_names, #a, 'authors', author_etal, param); last_first_list = list_people (control, a, author_etal); if utilities.is_set (Authors) then Authors, author_etal = name_has_etal (Authors, author_etal, false, 'authors'); -- find and remove variations on et al. if author_etal then Authors = Authors .. ' ' .. cfg.messages['et al']; -- add et al. to authors parameter end else Authors = last_first_list; -- either an author name list or an empty string end end -- end of do if utilities.is_set (Authors) and utilities.is_set (Collaboration) then Authors = Authors .. ' (' .. Collaboration .. ')'; -- add collaboration after et al. end end local ConferenceFormat = A['ConferenceFormat']; local ConferenceURL = A['ConferenceURL']; ConferenceFormat = style_format (ConferenceFormat, ConferenceURL, 'conference-format', 'conference-url'); Format = style_format (Format, URL, 'format', 'url'); -- special case for chapter format so no error message or cat when chapter not supported if not (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia))) then ChapterFormat = style_format (ChapterFormat, ChapterURL, 'chapter-format', 'chapter-url'); end if not utilities.is_set (URL) then if utilities.in_array (config.CitationClass, {"web", "podcast", "mailinglist"}) or -- |url= required for cite web, cite podcast, and cite mailinglist ('citation' == config.CitationClass and ('website' == Periodical_origin or 'script-website' == ScriptPeriodical_origin)) then -- and required for {{citation}} with |website= or |script-website= utilities.set_message ('err_cite_web_url'); end -- do we have |accessdate= without either |url= or |chapter-url=? if utilities.is_set (AccessDate) and not utilities.is_set (ChapterURL) then -- ChapterURL may be set when URL is not set; utilities.set_message ('err_accessdate_missing_url'); AccessDate = ''; end end local UrlStatus = is_valid_parameter_value (A['UrlStatus'], A:ORIGIN('UrlStatus'), cfg.keywords_lists['url-status'], ''); local OriginalURL local OriginalURL_origin local OriginalFormat local OriginalAccess; UrlStatus = UrlStatus:lower(); -- used later when assembling archived text if utilities.is_set ( ArchiveURL ) then if utilities.is_set (ChapterURL) then -- if chapter-url= is set apply archive url to it OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text OriginalURL_origin = ChapterURL_origin; -- name of |chapter-url= parameter for error messages OriginalFormat = ChapterFormat; -- and original |chapter-format= if 'live' ~= UrlStatus then ChapterURL = ArchiveURL -- swap-in the archive's URL ChapterURL_origin = A:ORIGIN('ArchiveURL') -- name of |archive-url= parameter for error messages ChapterFormat = ArchiveFormat or ''; -- swap in archive's format ChapterUrlAccess = nil; -- restricted access levels do not make sense for archived URLs end elseif utilities.is_set (URL) then OriginalURL = URL; -- save copy of original source URL OriginalURL_origin = URL_origin; -- name of URL parameter for error messages OriginalFormat = Format; -- and original |format= OriginalAccess = UrlAccess; if 'live' ~= UrlStatus then -- if URL set then |archive-url= applies to it URL = ArchiveURL -- swap-in the archive's URL URL_origin = A:ORIGIN('ArchiveURL') -- name of archive URL parameter for error messages Format = ArchiveFormat or ''; -- swap in archive's format UrlAccess = nil; -- restricted access levels do not make sense for archived URLs end end elseif utilities.is_set (UrlStatus) then -- if |url-status= is set when |archive-url= is not set utilities.set_message ('maint_url_status'); -- add maint cat end if utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or -- if any of the 'periodical' cites except encyclopedia ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) then local chap_param; if utilities.is_set (Chapter) then -- get a parameter name from one of these chapter related meta-parameters chap_param = A:ORIGIN ('Chapter') elseif utilities.is_set (TransChapter) then chap_param = A:ORIGIN ('TransChapter') elseif utilities.is_set (ChapterURL) then chap_param = A:ORIGIN ('ChapterURL') elseif utilities.is_set (ScriptChapter) then chap_param = ScriptChapter_origin; else utilities.is_set (ChapterFormat) chap_param = A:ORIGIN ('ChapterFormat') end if utilities.is_set (chap_param) then -- if we found one utilities.set_message ('err_chapter_ignored', {chap_param}); -- add error message Chapter = ''; -- and set them to empty string to be safe with concatenation TransChapter = ''; ChapterURL = ''; ScriptChapter = ''; ChapterFormat = ''; end else -- otherwise, format chapter / article title local no_quotes = false; -- default assume that we will be quoting the chapter parameter value if utilities.is_set (Contribution) and 0 < #c then -- if this is a contribution with contributor(s) if utilities.in_array (Contribution:lower(), cfg.keywords_lists.contribution) then -- and a generic contribution title no_quotes = true; -- then render it unquoted end end Chapter = format_chapter_title (ScriptChapter, ScriptChapter_origin, Chapter, Chapter_origin, TransChapter, TransChapter_origin, ChapterURL, ChapterURL_origin, no_quotes, ChapterUrlAccess); -- Contribution is also in Chapter if utilities.is_set (Chapter) then Chapter = Chapter .. ChapterFormat ; if 'map' == config.CitationClass and utilities.is_set (TitleType) then Chapter = Chapter .. ' ' .. TitleType; -- map annotation here; not after title end Chapter = Chapter .. sepc .. ' '; elseif utilities.is_set (ChapterFormat) then -- |chapter= not set but |chapter-format= is so ... Chapter = ChapterFormat .. sepc .. ' '; -- ... ChapterFormat has error message, we want to see it end end -- Format main title local plain_title = false; local accept_title; Title, accept_title = utilities.has_accept_as_written (Title, true); -- remove accept-this-as-written markup when it wraps all of <Title> if accept_title and ('' == Title) then -- only support forced empty for now "(())" Title = cfg.messages['notitle']; -- replace by predefined "No title" message -- TODO: utilities.set_message ( 'err_redundant_parameters', ...); -- issue proper error message instead of muting ScriptTitle = ''; -- just mute for now TransTitle = ''; -- just mute for now plain_title = true; -- suppress text decoration for descriptive title utilities.set_message ('maint_untitled'); -- add maint cat end if not accept_title then -- <Title> not wrapped in accept-as-written markup if '...' == Title:sub (-3) then -- if ellipsis is the last three characters of |title= Title = Title:gsub ('(%.%.%.)%.+$', '%1'); -- limit the number of dots to three elseif not mw.ustring.find (Title, '%.%s*%a%.$') and -- end of title is not a 'dot-(optional space-)letter-dot' initialism ... not mw.ustring.find (Title, '%s+%a%.$') then -- ...and not a 'space-letter-dot' initial (''Allium canadense'' L.) Title = mw.ustring.gsub(Title, '%' .. sepc .. '$', ''); -- remove any trailing separator character; sepc and ms.ustring() here for languages that use multibyte separator characters end if utilities.is_set (ArchiveURL) and is_archived_copy (Title) then utilities.set_message ('maint_archived_copy'); -- add maintenance category before we modify the content of Title end if is_generic ('generic_titles', Title) then utilities.set_message ('err_generic_title'); -- set an error message end end if (not plain_title) and (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'document', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) or ('map' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)))) then -- special case for cite map when the map is in a periodical treat as an article Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from module provided quote marks Title = utilities.wrap_style ('quoted-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); elseif plain_title or ('report' == config.CitationClass) then -- no styling for cite report and descriptive titles (otherwise same as above) Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); -- for cite report, use this form for trans-title else Title = utilities.wrap_style ('italic-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-italic-title', TransTitle); end if utilities.is_set (TransTitle) then if utilities.is_set (Title) then TransTitle = " " .. TransTitle; else utilities.set_message ('err_trans_missing_title', {'title'}); end end if utilities.is_set (Title) then -- TODO: is this the right place to be making Wikisource URLs? if utilities.is_set (TitleLink) and utilities.is_set (URL) then utilities.set_message ('err_wikilink_in_url'); -- set an error message because we can't have both TitleLink = ''; -- unset end if not utilities.is_set (TitleLink) and utilities.is_set (URL) then Title = external_link (URL, Title, URL_origin, UrlAccess) .. TransTitle .. Format; URL = ''; -- unset these because no longer needed Format = ""; elseif utilities.is_set (TitleLink) and not utilities.is_set (URL) then local ws_url; ws_url = wikisource_url_make (TitleLink); -- ignore ws_label return; not used here if ws_url then Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title-link'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], TitleLink, Title}); Title = Title .. TransTitle; else Title = utilities.make_wikilink (TitleLink, Title) .. TransTitle; end else local ws_url, ws_label, L; -- Title has italic or quote markup by the time we get here which causes is_wikilink() to return 0 (not a wikilink) ws_url, ws_label, L = wikisource_url_make (Title:gsub('^[\'"]*(.-)[\'"]*$', '%1')); -- make ws URL from |title= interwiki link (strip italic or quote markup); link portion L becomes tooltip label if ws_url then Title = Title:gsub ('%b[]', ws_label); -- replace interwiki link with ws_label to retain markup Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, Title}); Title = Title .. TransTitle; else Title = Title .. TransTitle; end end else Title = TransTitle; end if utilities.is_set (Place) then Place = " " .. wrap_msg ('written', Place, use_lowercase) .. sepc .. " "; end local ConferenceURL_origin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL if utilities.is_set (Conference) then if utilities.is_set (ConferenceURL) then Conference = external_link( ConferenceURL, Conference, ConferenceURL_origin, nil ); end Conference = sepc .. " " .. Conference .. ConferenceFormat; elseif utilities.is_set (ConferenceURL) then Conference = sepc .. " " .. external_link( ConferenceURL, nil, ConferenceURL_origin, nil ); end local Position = ''; if not utilities.is_set (Position) then local Minutes = A['Minutes']; local Time = A['Time']; if utilities.is_set (Minutes) then if utilities.is_set (Time) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'minutes') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'time')}); end Position = utilities.substitute (cfg.messages.minutes, Minutes); else if utilities.is_set (Time) then local TimeCaption = A['TimeCaption'] if not utilities.is_set (TimeCaption) then TimeCaption = cs2_lower(cfg.messages['event']); end Position = " " .. TimeCaption .. " " .. Time; end end else Position = " " .. Position; At = ''; end Page, Pages, Sheet, Sheets = format_pages_sheets (Page, Pages, Sheet, Sheets, config.CitationClass, Periodical_origin, sepc, NoPP, use_lowercase); At = utilities.is_set (At) and (sepc .. " " .. At) or ""; Position = utilities.is_set (Position) and (sepc .. " " .. Position) or ""; if config.CitationClass == 'map' then local Sections = A['Sections']; -- Section (singular) is an alias of Chapter so set earlier local Inset = A['Inset']; if utilities.is_set ( Inset ) then Inset = sepc .. " " .. wrap_msg ('inset', Inset, use_lowercase); end if utilities.is_set ( Sections ) then Section = sepc .. " " .. wrap_msg ('sections', Sections, use_lowercase); elseif utilities.is_set ( Section ) then Section = sepc .. " " .. wrap_msg ('section', Section, use_lowercase); end At = At .. Inset .. Section; end local Others = A['Others']; if utilities.is_set (Others) and 0 == #a and 0 == #e then -- add maint cat when |others= has value and used without |author=, |editor= if config.CitationClass == "AV-media-notes" or config.CitationClass == "audio-visual" then -- special maint for AV/M which has a lot of 'false' positives right now utilities.set_message ('maint_others_avm') else utilities.set_message ('maint_others'); end end Others = utilities.is_set (Others) and (sepc .. " " .. Others) or ""; if utilities.is_set (Translators) then Others = safe_join ({sepc .. ' ', wrap_msg ('translated', Translators, use_lowercase), Others}, sepc); end if utilities.is_set (Interviewers) then Others = safe_join ({sepc .. ' ', wrap_msg ('interview', Interviewers, use_lowercase), Others}, sepc); end local TitleNote = A['TitleNote']; TitleNote = utilities.is_set (TitleNote) and (sepc .. " " .. TitleNote) or ""; if utilities.is_set (Edition) then if Edition:match ('%f[%a][Ee]d%n?%.?$') or Edition:match ('%f[%a][Ee]dition$') then -- Ed, ed, Ed., ed., Edn, edn, Edn., edn. utilities.set_message ('err_extra_text_edition'); -- add error message end Edition = " " .. wrap_msg ('edition', Edition); else Edition = ''; end Series = utilities.is_set (Series) and wrap_msg ('series', {sepc, Series}) or ""; -- not the same as SeriesNum local Agency = A['Agency'] or ''; -- |agency= is supported by {{cite magazine}}, {{cite news}}, {{cite press release}}, {{cite web}}, and certain {{citation}} templates if utilities.is_set (Agency) then -- this testing done here because {{citation}} supports 'news' citations if utilities.in_array (config.CitationClass, {'magazine', 'news', 'pressrelease', 'web'}) or ('citation' == config.CitationClass and utilities.in_array (Periodical_origin, {"magazine", "newspaper", "work"})) then Agency = wrap_msg ('agency', {sepc, Agency}); -- format for rendering else Agency = ''; -- unset; not supported utilities.set_message ('err_parameter_ignored', {'agency'}); -- add error message end end Volume = format_volume_issue (Volume, Issue, ArticleNumber, config.CitationClass, Periodical_origin, sepc, use_lowercase); if utilities.is_set (AccessDate) then local retrv_text = " " .. cfg.messages['retrieved']; AccessDate = nowrap_date (AccessDate); -- wrap in nowrap span if date in appropriate format retrv_text = cs2_lower(retrv_text); -- if mode is cs2, lower case AccessDate = utilities.substitute (retrv_text, AccessDate); -- add retrieved text AccessDate = utilities.substitute (cfg.presentation['accessdate'], {sepc, AccessDate}); -- allow editors to hide accessdates end if utilities.is_set (ID) then ID = sepc .. " " .. ID; end local Docket = A['Docket']; if "thesis" == config.CitationClass and utilities.is_set (Docket) then ID = sepc .. " Docket " .. Docket .. ID; end if "report" == config.CitationClass and utilities.is_set (Docket) then -- for cite report when |docket= is set ID = sepc .. ' ' .. Docket; -- overwrite ID even if |id= is set end if utilities.is_set (URL) then URL = " " .. external_link( URL, nil, URL_origin, UrlAccess ); end -- We check length of PostScript here because it will have been nuked by -- the quote parameters. We'd otherwise emit a message even if there wasn't -- a displayed postscript. -- TODO: Should the max size (1) be configurable? -- TODO: Should we check a specific pattern? if utilities.is_set(PostScript) and mw.ustring.len(PostScript) > 1 then utilities.set_message ('maint_postscript') end local Archived; if utilities.is_set (ArchiveURL) then if not utilities.is_set (ArchiveDate) then -- ArchiveURL set but ArchiveDate not set utilities.set_message ('err_archive_missing_date'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end else if utilities.is_set (ArchiveDate) then -- ArchiveURL not set but ArchiveDate is set utilities.set_message ('err_archive_date_missing_url'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end end if utilities.is_set (ArchiveURL) then local arch_text; if "live" == UrlStatus then if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cfg.messages['archived-live'], { external_link( ArchiveURL, cs2_lower(cfg.messages['archived']), A:ORIGIN('ArchiveURL'), nil) .. ArchiveFormat, ArchiveDate } ); else Archived = ''; end if not utilities.is_set (OriginalURL) then utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (OriginalURL) then -- UrlStatus is empty, 'dead', 'unfit', 'usurped', 'bot: unknown' if utilities.in_array (UrlStatus, {'unfit', 'usurped', 'bot: unknown'}) then Archived = sepc .. ' ' .. utilities.substitute ( cs2_lower(cfg.messages['archived-unfit']), ArchiveDate); if 'bot: unknown' == UrlStatus then utilities.set_message ('maint_bot_unknown'); -- and add a category if not already added else utilities.add_prop_cat ('unfit'); -- and add a category if not already added end else -- UrlStatus is empty, 'dead' if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cs2_lower(cfg.messages['archived-dead']), { external_link( OriginalURL, cfg.messages['original'], OriginalURL_origin, OriginalAccess ) .. OriginalFormat, ArchiveDate } ); else Archived = ''; -- unset for concatenation end end else -- OriginalUrl not set utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (ArchiveFormat) then Archived = ArchiveFormat; -- if set and ArchiveURL not set ArchiveFormat has error message else Archived = ''; end local TranscriptURL = A['TranscriptURL'] local TranscriptFormat = A['TranscriptFormat']; TranscriptFormat = style_format (TranscriptFormat, TranscriptURL, 'transcript-format', 'transcripturl'); local Transcript = A['Transcript']; local TranscriptURL_origin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL if utilities.is_set (Transcript) then if utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, Transcript, TranscriptURL_origin, nil ); end Transcript = sepc .. ' ' .. Transcript .. TranscriptFormat; elseif utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, nil, TranscriptURL_origin, nil ); end local Publisher; if utilities.is_set (PublicationDate) then PublicationDate = wrap_msg ('published', PublicationDate); end if utilities.is_set (PublisherName) then if utilities.is_set (PublicationPlace) then Publisher = sepc .. " " .. PublicationPlace .. ": " .. PublisherName .. PublicationDate; else Publisher = sepc .. " " .. PublisherName .. PublicationDate; end elseif utilities.is_set (PublicationPlace) then Publisher= sepc .. " " .. PublicationPlace .. PublicationDate; else Publisher = PublicationDate; end -- Several of the above rely upon detecting this as nil, so do it last. if (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical)) then if utilities.is_set (Title) or utilities.is_set (TitleNote) then Periodical = sepc .. " " .. format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); else Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); end end local Language = A['Language']; if utilities.is_set (Language) then Language = language_parameter (Language); -- format, categories, name from ISO639-1, etc. else Language=''; -- language not specified so make sure this is an empty string; --[[ TODO: need to extract the wrap_msg from language_parameter so that we can solve parentheses bunching problem with Format/Language/TitleType ]] end --[[ Handle the oddity that is cite speech. This code overrides whatever may be the value assigned to TitleNote (through |department=) and forces it to be " (Speech)" so that the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided). ]] if "speech" == config.CitationClass then -- cite speech only TitleNote = TitleType; -- move TitleType to TitleNote so that it renders ahead of |event= TitleType = ''; -- and unset if utilities.is_set (Periodical) then -- if Periodical, perhaps because of an included |website= or |journal= parameter if utilities.is_set (Conference) then -- and if |event= is set Conference = Conference .. sepc .. " "; -- then add appropriate punctuation to the end of the Conference variable before rendering end end end -- Piece all bits together at last. Here, all should be non-nil. -- We build things this way because it is more efficient in LUA -- not to keep reassigning to the same string variable over and over. local tcommon; local tcommon2; -- used for book cite when |contributor= is set if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (Periodical) then -- special cases for book cites if utilities.is_set (Contributors) then -- when we are citing foreword, preface, introduction, etc. tcommon = safe_join ({Title, TitleNote}, sepc); -- author and other stuff will come after this and before tcommon2 tcommon2 = safe_join ({TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); else tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); end elseif 'map' == config.CitationClass then -- special cases for cite map if utilities.is_set (Chapter) then -- map in a book; TitleType is part of Chapter tcommon = safe_join ({Title, Edition, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); elseif utilities.is_set (Periodical) then -- map in a periodical tcommon = safe_join ({Title, TitleType, Periodical, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); else -- a sheet or stand-alone map tcommon = safe_join ({Title, TitleType, Edition, Scale, Series, Language, Cartography, Others, Publisher}, sepc); end elseif 'episode' == config.CitationClass then -- special case for cite episode tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Edition, Publisher}, sepc); else -- all other CS1 templates tcommon = safe_join ({Title, TitleNote, Conference, Periodical, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc); end if #ID_list > 0 then ID_list = safe_join( { sepc .. " ", table.concat( ID_list, sepc .. " " ), ID }, sepc ); else ID_list = ID; end local Via = A['Via']; Via = utilities.is_set (Via) and wrap_msg ('via', Via) or ''; local idcommon; if 'audio-visual' == config.CitationClass or 'episode' == config.CitationClass then -- special case for cite AV media & cite episode position transcript idcommon = safe_join( { ID_list, URL, Archived, Transcript, AccessDate, Via, Quote }, sepc ); else idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, Quote }, sepc ); end local text; local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; local OrigDate = A['OrigDate']; OrigDate = utilities.is_set (OrigDate) and wrap_msg ('origdate', OrigDate) or ''; if utilities.is_set (Date) then if utilities.is_set (Authors) or utilities.is_set (Editors) then -- date follows authors or editors when authors not set Date = " (" .. Date .. ")" .. OrigDate .. sepc .. " "; -- in parentheses else -- neither of authors and editors set if (string.sub(tcommon, -1, -1) == sepc) then -- if the last character of tcommon is sepc Date = " " .. Date .. OrigDate; -- Date does not begin with sepc else Date = sepc .. " " .. Date .. OrigDate; -- Date begins with sepc end end end if utilities.is_set (Authors) then if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Authors termination Authors = terminate_name_list (Authors, sepc); -- when no date, terminate with 0 or 1 sepc and a space end if utilities.is_set (Editors) then local in_text = ''; local post_text = ''; if utilities.is_set (Chapter) and 0 == #c then in_text = cfg.messages['in'] .. ' '; in_text = cs2_lower(in_text); -- lowercase for cs2 end if EditorCount <= 1 then post_text = ' (' .. cfg.messages['editor'] .. ')'; -- be consistent with no-author, no-date case else post_text = ' (' .. cfg.messages['editors'] .. ')'; end Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space end if utilities.is_set (Contributors) then -- book cite and we're citing the intro, preface, etc. local by_text = sepc .. ' ' .. cfg.messages['by'] .. ' '; by_text = cs2_lower(by_text); -- lowercase for cs2 Authors = by_text .. Authors; -- author follows title so tweak it here if utilities.is_set (Editors) and utilities.is_set (Date) then -- when Editors make sure that Authors gets terminated Authors = terminate_name_list (Authors, sepc); -- terminate with 0 or 1 sepc and a space end if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Contributors termination Contributors = terminate_name_list (Contributors, sepc); -- terminate with 0 or 1 sepc and a space end text = safe_join( {Contributors, Date, Chapter, tcommon, Authors, Place, Editors, tcommon2, pgtext, idcommon }, sepc ); else text = safe_join( {Authors, Date, Chapter, Place, Editors, tcommon, pgtext, idcommon }, sepc ); end elseif utilities.is_set (Editors) then if utilities.is_set (Date) then if EditorCount <= 1 then Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editor']; else Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editors']; end else if EditorCount <= 1 then Editors = Editors .. " (" .. cfg.messages['editor'] .. ")" .. sepc .. " " else Editors = Editors .. " (" .. cfg.messages['editors'] .. ")" .. sepc .. " " end end text = safe_join( {Editors, Date, Chapter, Place, tcommon, pgtext, idcommon}, sepc ); else if utilities.in_array (config.CitationClass, {"journal", "citation"}) and utilities.is_set (Periodical) then text = safe_join( {Chapter, Place, tcommon, pgtext, Date, idcommon}, sepc ); else text = safe_join( {Chapter, Place, tcommon, Date, pgtext, idcommon}, sepc ); end end if utilities.is_set (PostScript) and PostScript ~= sepc then text = safe_join( {text, sepc}, sepc ); -- Deals with italics, spaces, etc. if '.' == sepc then -- remove final seperator if present text = text:gsub ('%' .. sepc .. '$', ''); -- dot must be escaped here else text = mw.ustring.gsub (text, sepc .. '$', ''); -- using ustring for non-dot sepc (likely a non-Latin character) end end text = safe_join( {text, PostScript}, sepc ); -- Now enclose the whole thing in a <cite> element local options_t = {}; options_t.class = cite_class_attribute_make (config.CitationClass, Mode); local Ref = is_valid_parameter_value (A['Ref'], A:ORIGIN('Ref'), cfg.keywords_lists['ref'], nil, true); -- nil when |ref=harv; A['Ref'] else if 'none' ~= cfg.keywords_xlate[(Ref and Ref:lower()) or ''] then local namelist_t = {}; -- holds selected contributor, author, editor name list local year = first_set ({Year, anchor_year}, 2); -- Year first for legacy citations and for YMD dates that require disambiguation if #c > 0 then -- if there is a contributor list namelist_t = c; -- select it elseif #a > 0 then -- or an author list namelist_t = a; elseif #e > 0 then -- or an editor list namelist_t = e; end local citeref_id; if #namelist_t > 0 then -- if there are names in namelist_t citeref_id = make_citeref_id (namelist_t, year); -- go make the CITEREF anchor if mw.uri.anchorEncode (citeref_id) == ((Ref and mw.uri.anchorEncode (Ref)) or '') then -- Ref may already be encoded (by {{sfnref}}) so citeref_id must be encoded before comparison utilities.set_message ('maint_ref_duplicates_default'); end else citeref_id = ''; -- unset end options_t.id = Ref or citeref_id; end if string.len (text:gsub('%b<>', '')) <= 2 then -- remove html and html-like tags; then get length of what remains; z.error_cats_t = {}; -- blank the categories list z.error_msgs_t = {}; -- blank the error messages list OCinSoutput = nil; -- blank the metadata string text = ''; -- blank the the citation utilities.set_message ('err_empty_citation'); -- set empty citation message and category end local render_t = {}; -- here we collect the final bits for concatenation into the rendered citation if is_preview_mode then -- when in preview mode if not utilities.is_set (options_t.id) then -- and when this template has not created an anchor ID math.randomseed (tonumber (mw.getLanguage ('en'):formatDate ('U')) * 10000 + os.clock() * 10000); options_t.id = 'CITEREF_temp_preview_id_' .. math.random (100000, 999999); -- create temporary anchor ID for preview mode end end if utilities.is_set (options_t.id) then -- here we wrap the rendered citation in <cite ...>...</cite> tags options_t.id = mw.uri.anchorEncode(options_t.id); -- do this here; also used when adding preview warning messages table.insert (render_t, utilities.substitute (cfg.presentation['cite-id'], {options_t.id, mw.text.nowiki(options_t.class), text})); -- when |ref= is set or when there is a namelist else table.insert (render_t, utilities.substitute (cfg.presentation['cite'], {mw.text.nowiki(options_t.class), text})); -- when |ref=none or when namelist_t empty and |ref= is missing or is empty end if OCinSoutput then -- blanked when citation is 'empty' so don't bother to add boilerplate metadata span table.insert (render_t, utilities.substitute (cfg.presentation['ocins'], OCinSoutput)); -- format and append metadata to the citation end local template_name = cfg.citation_class_map_t[config.CitationClass]; local template_link = '[[Template:' .. template_name .. '|' .. template_name .. ']]'; local msg_prefix = '<code class="cs1-code">{{' .. template_link .. '}}</code>: '; local warn_link = '[[#' .. options_t.id .. ']]'; if 0 ~= #z.error_msgs_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_e, {template_link, options_t.id})); table.insert (render_t, ' '); -- insert a space between citation and its error messages table.sort (z.error_msgs_t); -- sort the error messages list; sorting includes wrapping <span> and <code> tags; hidden-error sorts ahead of visible-error local hidden = true; -- presume that the only error messages emited by this template are hidden for _, v in ipairs (z.error_msgs_t) do -- spin through the list of error messages if v:find ('cs1-visible-error', 1, true) then -- look for the visible error class name hidden = false; -- found one; so don't hide the error message prefix break; -- and done because no need to look further end end z.error_msgs_t[1] = table.concat ({utilities.error_comment (msg_prefix, hidden), z.error_msgs_t[1]}); -- add error message prefix to first error message to prevent extraneous punctuation table.insert (render_t, table.concat (z.error_msgs_t, '; ')); -- make a big string of error messages and add it to the rendering end if 0 ~= #z.maint_cats_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_m, {template_link, options_t.id})); table.sort (z.maint_cats_t); -- sort the maintenance messages list local maint_msgs_t = {}; -- here we collect all of the maint messages if 0 == #z.error_msgs_t then -- if no error messages table.insert (maint_msgs_t, msg_prefix); -- insert message prefix in maint message livery end for _, v in ipairs( z.maint_cats_t ) do -- append maintenance categories table.insert (maint_msgs_t, -- assemble new maint message and add it to the maint_msgs_t table table.concat ({v, ' (', utilities.substitute (cfg.messages[':cat wikilink'], v), ')'}) ); end table.insert (render_t, utilities.substitute (cfg.presentation['hidden-maint'], table.concat (maint_msgs_t, ' '))); -- wrap the group of maint messages with proper presentation and save end if not no_tracking_cats then local sort_key; local cat_wikilink = 'cat wikilink'; if cfg.enable_sort_keys then -- when namespace sort keys enabled local namespace_number = mw.title.getCurrentTitle().namespace; -- get namespace number for this wikitext sort_key = (0 ~= namespace_number and (cfg.name_space_sort_keys[namespace_number] or cfg.name_space_sort_keys.other)) or nil; -- get sort key character; nil for mainspace cat_wikilink = (not sort_key and 'cat wikilink') or 'cat wikilink sk'; -- make <cfg.messages> key end for _, v in ipairs (z.error_cats_t) do -- append error categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end if cfg.id_limits_data_load_fail then -- boolean true when load failed utilities.set_message ('maint_id_limit_load_fail'); -- done here because this maint cat emits no message end for _, v in ipairs (z.maint_cats_t) do -- append maintenance categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end for _, v in ipairs (z.prop_cats_t) do -- append properties categories table.insert (render_t, utilities.substitute (cfg.messages['cat wikilink'], v)); -- no sort keys end end return table.concat (render_t); -- make a big string and done end --[[--------------------------< V A L I D A T E >-------------------------------------------------------------- Looks for a parameter's name in one of several whitelists. Parameters in the whitelist can have three values: true - active, supported parameters false - deprecated, supported parameters nil - unsupported parameters ]] local function validate (name, cite_class, empty) local name = tostring (name); local enum_name; -- parameter name with enumerator (if any) replaced with '#' local state; local function state_test (state, name) -- local function to do testing of state values if true == state then return true; end -- valid actively supported parameter if false == state then if empty then return nil; end -- empty deprecated parameters are treated as unknowns deprecated_parameter (name); -- parameter is deprecated but still supported return true; end if 'tracked' == state then local base_name = name:gsub ('%d', ''); -- strip enumerators from parameter names that have them to get the base name utilities.add_prop_cat ('tracked-param', {base_name}, base_name); -- add a properties category; <base_name> modifies <key> return true; end return nil; end if name:find ('#') then -- # is a cs1|2 reserved character so parameters with # not permitted return nil; end -- replace enumerator digit(s) with # (|last25= becomes |last#=) (mw.ustring because non-Western 'local' digits) enum_name = mw.ustring.gsub (name, '%d+$', '#'); -- where enumerator is last charaters in parameter name (these to protect |s2cid=) enum_name = mw.ustring.gsub (enum_name, '%d+([%-l])', '#%1'); -- where enumerator is in the middle of the parameter name; |author#link= is the oddity if 'document' == cite_class then -- special case for {{cite document}} state = whitelist.document_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end return false; end if utilities.in_array (cite_class, whitelist.preprint_template_list_t) then -- limited parameter sets allowed for these templates state = whitelist.limited_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end state = whitelist.preprint_arguments_t[cite_class][name]; -- look in the parameter-list for the template identified by cite_class if true == state_test (state, name) then return true; end return false; -- not supported because not found or name is set to nil end -- end limited parameter-set templates if utilities.in_array (cite_class, whitelist.unique_param_template_list_t) then -- template-specific parameters for templates that accept parameters from the basic argument list state = whitelist.unique_arguments_t[cite_class][name]; -- look in the template-specific parameter-lists for the template identified by cite_class if true == state_test (state, name) then return true; end end -- if here, fall into general validation state = whitelist.common_parameters_t[enum_name]; -- all other templates; all normal parameters allowed; this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end return false; -- not supported because not found or name is set to nil end --[=[-------------------------< I N T E R _ W I K I _ C H E C K >---------------------------------------------- check <value> for inter-language interwiki-link markup. <prefix> must be a MediaWiki-recognized language code. when these values have the form (without leading colon): [[<prefix>:link|label]] return label as plain-text [[<prefix>:link]] return <prefix>:link as plain-text return value as is else ]=] local function inter_wiki_check (parameter, value) local prefix = value:match ('%[%[(%a+):'); -- get an interwiki prefix if one exists local _; if prefix and cfg.inter_wiki_map[prefix:lower()] then -- if prefix is in the map, needs preceding colon so utilities.set_message ('err_bad_paramlink', parameter); -- emit an error message _, value, _ = utilities.is_wikilink (value); -- extract label portion from wikilink end return value; end --[[--------------------------< M I S S I N G _ P I P E _ C H E C K >------------------------------------------ Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal sign, compare the alphanumeric string to the list of cs1|2 parameters. If found, then the string is possibly a parameter that is missing its pipe. There are two tests made: {{cite ... |title=Title access-date=2016-03-17}} -- the first parameter has a value and whitespace separates that value from the missing pipe parameter name {{cite ... |title=access-date=2016-03-17}} -- the first parameter has no value (whitespace after the first = is trimmed by MediaWiki) cs1|2 shares some parameter names with XML/HTML attributes: class=, title=, etc. To prevent false positives XML/HTML tags are removed before the search. If a missing pipe is detected, this function adds the missing pipe maintenance category. ]] local function missing_pipe_check (parameter, value) local capture; value = value:gsub ('%b<>', ''); -- remove XML/HTML tags because attributes: class=, title=, etc. capture = value:match ('%s+(%a[%w%-]+)%s*=') or value:match ('^(%a[%w%-]+)%s*='); -- find and categorize parameters with possible missing pipes if capture and validate (capture) then -- if the capture is a valid parameter name utilities.set_message ('err_missing_pipe', parameter); end end --[[--------------------------< H A S _ E X T R A N E O U S _ P U N C T >-------------------------------------- look for extraneous terminal punctuation in most parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_punc (param, value) if 'number' == type (param) then return; end param = param:gsub ('%d+', '#'); -- enumerated name-list mask params allow terminal punct; normalize if cfg.punct_skip[param] then return; -- parameter name found in the skip table so done end if value:match ('[,;:]$') then utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end if value:match ('^=') then -- sometimes an extraneous '=' character appears ... utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end end --[[--------------------------< H A S _ T W L _ U R L >-------------------------------------------------------- look for The Wikipedia Library urls in url-holding parameters. TWL urls are accessible only for readers who are active extended confirmed Wikipedia editors. This function sets an error message when such urls are discovered and when appropriate, sets the |<param>-url-access=subscription. returns nothing. looks for: '.wikipedialibrary.idm.oclc.org' ]] local function has_twl_url (url_params_t, cite_args_t) local url_error_t = {}; -- sequence of url-holding parameters that have a TWL url for param, value in pairs (url_params_t) do if value:find ('%.wikipedialibrary%.idm%.oclc%.org') then -- has the TWL base url? table.insert (url_error_t, param); -- add parameter name to the error list end end if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); -- sor for error messaging for i, param in ipairs (url_error_t) do if cfg.url_access_map_t[param] then -- if <param> has a matching -access parameter cite_args_t[cfg.url_access_map_t[param]] = cfg.keywords_xlate.subscription; -- set |<param>-url-access=subscription end url_error_t[i] = utilities.wrap_style ('parameter', param); -- make the parameter pretty for error message end utilities.set_message ('err_param_has_twl_url', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< H A S _ E X T R A N E O U S _ U R L >------------------------------------------ look for extraneous url parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_url (non_url_param_t) local url_error_t = {}; check_for_url (non_url_param_t, url_error_t); -- extraneous url check if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); utilities.set_message ('err_param_has_ext_link', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< _ C I T A T I O N >------------------------------------------------------------ Module entry point frame – from template call (citation()); may be nil when called from another module args_t – table of all cs1|2 parameters in the template (the parent frame) config_t – table of template-supplied parameter (the #invoke frame) ]] local function _citation (frame, args_t, config_t) -- save a copy in case we need to display an error message in preview mode if not frame then frame = mw.getCurrentFrame(); -- if called from another module, get a frame for frame-provided functions end -- i18n: set the name that your wiki uses to identify sandbox subpages from sandbox template invoke (or can be set here) local sandbox = ((config_t.SandboxPath and '' ~= config_t.SandboxPath) and config_t.SandboxPath) or '/sandbox'; -- sandbox path from {{#invoke:Citation/CS1/sandbox|citation|SandboxPath=/...}} is_sandbox = nil ~= string.find (frame:getTitle(), sandbox, 1, true); -- is this invoke the sandbox module? sandbox = is_sandbox and sandbox or ''; -- use i18n sandbox to load sandbox modules when this module is the sandox; live modules else cfg = mw.loadData ('Module:Citation/CS1/Configuration' .. sandbox); -- load sandbox versions of support modules when {{#invoke:Citation/CS1/sandbox|...}}; live modules else whitelist = mw.loadData ('Module:Citation/CS1/Whitelist' .. sandbox); utilities = require ('Module:Citation/CS1/Utilities' .. sandbox); validation = require ('Module:Citation/CS1/Date_validation' .. sandbox); identifiers = require ('Module:Citation/CS1/Identifiers' .. sandbox); metadata = require ('Module:Citation/CS1/COinS' .. sandbox); utilities.set_selected_modules (cfg); -- so that functions in Utilities can see the selected cfg tables identifiers.set_selected_modules (cfg, utilities); -- so that functions in Identifiers can see the selected cfg tables and selected Utilities module validation.set_selected_modules (cfg, utilities); -- so that functions in Date validataion can see selected cfg tables and the selected Utilities module metadata.set_selected_modules (cfg, utilities); -- so that functions in COinS can see the selected cfg tables and selected Utilities module z = utilities.z; -- table of error and category tables in Module:Citation/CS1/Utilities local cite_args_t = {}; -- because args_t is the parent (template) frame args (which cannot be modified); params and their values will be placed here is_preview_mode = not utilities.is_set (frame:preprocess ('{{REVISIONID}}')); local suggestions = {}; -- table where we store suggestions if we need to loadData them local error_text; -- used as a flag local capture; -- the single supported capture when matching unknown parameters using patterns local empty_unknowns = {}; -- sequence table to hold empty unknown params for error message listing for k, v in pairs (args_t) do -- get parameters from the parent (template) frame v = mw.ustring.gsub (v, '^%s*(.-)%s*$', '%1'); -- trim leading/trailing whitespace; when v is only whitespace, becomes empty string if v ~= '' then if ('string' == type (k)) then k = mw.ustring.gsub (k, '%d', cfg.date_names.local_digits); -- for enumerated parameters, translate 'local' digits to Western 0-9 end if not validate( k, config_t.CitationClass ) then if type (k) ~= 'string' then -- exclude empty numbered parameters if v:match("%S+") ~= nil then error_text = utilities.set_message ('err_text_ignored', {v}); end elseif validate (k:lower(), config_t.CitationClass) then error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, k:lower()}); -- suggest the lowercase version of the parameter else if nil == suggestions.suggestions then -- if this table is nil then we need to load it suggestions = mw.loadData ('Module:Citation/CS1/Suggestions' .. sandbox); --load sandbox version of suggestion module when {{#invoke:Citation/CS1/sandbox|...}}; live module else end for pattern, param in pairs (suggestions.patterns) do -- loop through the patterns to see if we can suggest a proper parameter capture = k:match (pattern); -- the whole match if no capture in pattern else the capture if a match if capture then -- if the pattern matches param = utilities.substitute (param, capture); -- add the capture to the suggested parameter (typically the enumerator) if validate (param, config_t.CitationClass) then -- validate the suggestion to make sure that the suggestion is supported by this template (necessary for limited parameter lists) error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, param}); -- set the suggestion error message else error_text = utilities.set_message ('err_parameter_ignored', {k}); -- suggested param not supported by this template v = ''; -- unset end end end if not utilities.is_set (error_text) then -- couldn't match with a pattern, is there an explicit suggestion? if (suggestions.suggestions[ k:lower() ] ~= nil) and validate (suggestions.suggestions[ k:lower() ], config_t.CitationClass) then utilities.set_message ('err_parameter_ignored_suggest', {k, suggestions.suggestions[ k:lower() ]}); else utilities.set_message ('err_parameter_ignored', {k}); v = ''; -- unset value assigned to unrecognized parameters (this for the limited parameter lists) end end end end cite_args_t[k] = v; -- save this parameter and its value elseif not utilities.is_set (v) then -- for empty parameters if not validate (k, config_t.CitationClass, true) then -- is this empty parameter a valid parameter k = ('' == k) and cfg.err_msg_supl.empty_str or k; -- when k is empty string (or was space(s) trimmed to empty string), replace with descriptive text table.insert (empty_unknowns, utilities.wrap_style ('parameter', k)); -- format for error message and add to the list end end end if 0 ~= #empty_unknowns then -- create empty unknown error message utilities.set_message ('err_param_unknown_empty', { 1 == #empty_unknowns and '' or 's', utilities.make_sep_list (#empty_unknowns, empty_unknowns) }); end local non_url_param_t = {}; -- table of parameters and values that are not url-holding parameters local url_param_t = {}; -- table of url-holding paramters and their values for k, v in pairs (cite_args_t) do if 'string' == type (k) then -- don't evaluate positional parameters has_invisible_chars (k, v); -- look for invisible characters end has_extraneous_punc (k, v); -- look for extraneous terminal punctuation in parameter values missing_pipe_check (k, v); -- do we think that there is a parameter that is missing a pipe? cite_args_t[k] = inter_wiki_check (k, v); -- when language interwiki-linked parameter missing leading colon replace with wiki-link label if 'string' == type (k) then -- when parameter k is not positional if not cfg.url_skip[k] then -- and not in url skip table non_url_param_t[k] = v; -- make a parameter/value list for extraneous url check else -- and is in url skip table (a url-holding parameter) url_param_t[k] = v; -- make a parameter/value list to check for values that are The Wikipedia Library url end end end has_extraneous_url (non_url_param_t); -- look for url in parameter values where a url does not belong has_twl_url (url_param_t, cite_args_t); -- look for url-holding parameters that hold a The Wikipedia Library url return table.concat ({ frame:extensionTag ('templatestyles', '', {src='Module:Citation/CS1' .. sandbox .. '/styles.css'}), citation0 (config_t, cite_args_t) }); end --[[--------------------------< C I T A T I O N >-------------------------------------------------------------- Template entry point ]] local function citation (frame) local config_t = {}; -- table to store parameters from the module {{#invoke:}} local args_t = frame:getParent().args; -- get template's preset parameters for k, v in pairs (frame.args) do -- get parameters from the {{#invoke}} frame config_t[k] = v; -- args_t[k] = v; -- crude debug support that allows us to render a citation from module {{#invoke:}}; skips parameter validation; TODO: keep? end return _citation (frame, args_t, config_t) end --[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------ ]] return { citation = citation, -- template entry point _citation = _citation, -- module entry point } 4w9nddxv60scr439nht7cvso9rjyldk 736731 736730 2026-01-17T19:37:57Z en>Trappist the monk 0 736731 Scribunto text/plain require ('strict'); --[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- each of these counts against the Lua upvalue limit ]] local validation; -- functions in Module:Citation/CS1/Date_validation local utilities; -- functions in Module:Citation/CS1/Utilities local z = {}; -- table of tables in Module:Citation/CS1/Utilities local identifiers; -- functions and tables in Module:Citation/CS1/Identifiers local metadata; -- functions in Module:Citation/CS1/COinS local cfg = {}; -- table of configuration tables that are defined in Module:Citation/CS1/Configuration local whitelist = {}; -- table of tables listing valid template parameter names; defined in Module:Citation/CS1/Whitelist --[[------------------< P A G E S C O P E V A R I A B L E S >--------------- declare variables here that have page-wide scope that are not brought in from other modules; that are created here and used here ]] local added_deprecated_cat; -- Boolean flag so that the category is added only once local added_vanc_errs; -- Boolean flag so we only emit one Vancouver error / category local added_generic_name_errs; -- Boolean flag so we only emit one generic name error / category and stop testing names once an error is encountered local added_numeric_name_errs; -- Boolean flag so we only emit one numeric name error / category and stop testing names once an error is encountered local added_numeric_name_maint; -- Boolean flag so we only emit one numeric name maint category and stop testing names once a category has been emitted local is_preview_mode; -- true when article is in preview mode; false when using 'Preview page with this template' (previewing the module) local is_sandbox; -- true when using sandbox modules to render citation --[[--------------------------< F I R S T _ S E T >------------------------------------------------------------ Locates and returns the first set value in a table of values where the order established in the table, left-to-right (or top-to-bottom), is the order in which the values are evaluated. Returns nil if none are set. This version replaces the original 'for _, val in pairs do' and a similar version that used ipairs. With the pairs version the order of evaluation could not be guaranteed. With the ipairs version, a nil value would terminate the for-loop before it reached the actual end of the list. ]] local function first_set (list, count) local i = 1; while i <= count do -- loop through all items in list if utilities.is_set( list[i] ) then return list[i]; -- return the first set list member end i = i + 1; -- point to next end end --[[--------------------------< A D D _ V A N C _ E R R O R >---------------------------------------------------- Adds a single Vancouver system error message to the template's output regardless of how many error actually exist. To prevent duplication, added_vanc_errs is nil until an error message is emitted. added_vanc_errs is a Boolean declared in page scope variables above ]] local function add_vanc_error (source, position) if added_vanc_errs then return end added_vanc_errs = true; -- note that we've added this category utilities.set_message ('err_vancouver', {source, position}); end --[[--------------------------< I S _ S C H E M E >------------------------------------------------------------ does this thing that purports to be a URI scheme seem to be a valid scheme? The scheme is checked to see if it is in agreement with http://tools.ietf.org/html/std66#section-3.1 which says: Scheme names consist of a sequence of characters beginning with a letter and followed by any combination of letters, digits, plus ("+"), period ("."), or hyphen ("-"). returns true if it does, else false ]] local function is_scheme (scheme) return scheme and scheme:match ('^%a[%a%d%+%.%-]*:'); -- true if scheme is set and matches the pattern end --[=[-------------------------< I S _ D O M A I N _ N A M E >-------------------------------------------------- Does this thing that purports to be a domain name seem to be a valid domain name? Syntax defined here: http://tools.ietf.org/html/rfc1034#section-3.5 BNF defined here: https://tools.ietf.org/html/rfc4234 Single character names are generally reserved; see https://tools.ietf.org/html/draft-ietf-dnsind-iana-dns-01#page-15; see also [[Single-letter second-level domain]] list of TLDs: https://www.iana.org/domains/root/db RFC 952 (modified by RFC 1123) requires the first and last character of a hostname to be a letter or a digit. Between the first and last characters the name may use letters, digits, and the hyphen. Also allowed are IPv4 addresses. IPv6 not supported domain is expected to be stripped of any path so that the last character in the last character of the TLD. tld is two or more alpha characters. Any preceding '//' (from splitting a URL with a scheme) will be stripped here. Perhaps not necessary but retained in case it is necessary for IPv4 dot decimal. There are several tests: the first character of the whole domain name including subdomains must be a letter or a digit internationalized domain name (ASCII characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the TLD) see https://tools.ietf.org/html/rfc3490 single-letter/digit second-level domains in the .org, .cash, and .today TLDs q, x, and z SL domains in the .com TLD i and q SL domains in the .net TLD single-letter SL domains in the ccTLDs (where the ccTLD is two letters) two-character SL domains in gTLDs (where the gTLD is two or more letters) three-plus-character SL domains in gTLDs (where the gTLD is two or more letters) IPv4 dot-decimal address format; TLD not allowed returns true if domain appears to be a proper name and TLD or IPv4 address, else false ]=] local function is_domain_name (domain) if not domain then return false; -- if not set, abandon end domain = domain:gsub ('^//', ''); -- strip '//' from domain name if present; done here so we only have to do it once if not domain:match ('^[%w]') then -- first character must be letter or digit return false; end if domain:match ('^%a+:') then -- hack to detect things that look like s:Page:Title where Page: is namespace at Wikisource return false; end local patterns = { -- patterns that look like URLs '%f[%w][%w][%w%-]+[%w]%.%a%a+$', -- three or more character hostname.hostname or hostname.tld '%f[%w][%w][%w%-]+[%w]%.xn%-%-[%w]+$', -- internationalized domain name with ACE prefix '%f[%a][qxz]%.com$', -- assigned one character .com hostname (x.com times out 2015-12-10) '%f[%a][iq]%.net$', -- assigned one character .net hostname (q.net registered but not active 2015-12-10) '%f[%w][%w]%.%a%a$', -- one character hostname and ccTLD (2 chars) '%f[%w][%w][%w]%.%a%a+$', -- two character hostname and TLD '^%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?', -- IPv4 address '[%a%d]+%:?' -- IPv6 address } for _, pattern in ipairs (patterns) do -- loop through the patterns list if domain:match (pattern) then return true; -- if a match then we think that this thing that purports to be a URL is a URL end end for _, d in ipairs (cfg.single_letter_2nd_lvl_domains_t) do -- look for single letter second level domain names for these top level domains if domain:match ('%f[%w][%w]%.' .. d) then return true end end return false; -- no matches, we don't know what this thing is end --[[--------------------------< I S _ U R L >------------------------------------------------------------------ returns true if the scheme and domain parts of a URL appear to be a valid URL; else false. This function is the last step in the validation process. This function is separate because there are cases that are not covered by split_url(), for example is_parameter_ext_wikilink() which is looking for bracketted external wikilinks. ]] local function is_url (scheme, domain) if utilities.is_set (scheme) then -- if scheme is set check it and domain return is_scheme (scheme) and is_domain_name (domain); else return is_domain_name (domain); -- scheme not set when URL is protocol-relative end end --[[--------------------------< S P L I T _ U R L >------------------------------------------------------------ Split a URL into a scheme, authority indicator, and domain. First remove Fully Qualified Domain Name terminator (a dot following TLD) (if any) and any path(/), query(?) or fragment(#). If protocol-relative URL, return nil scheme and domain else return nil for both scheme and domain. When not protocol-relative, get scheme, authority indicator, and domain. If there is an authority indicator (one or more '/' characters immediately following the scheme's colon), make sure that there are only 2. Any URL that does not have news: scheme must have authority indicator (//). TODO: are there other common schemes like news: that don't use authority indicator? Strip off any port and path; ]] local function split_url (url_str) local scheme, authority, domain; url_str = url_str:gsub ('([%a%d])%.?[/%?#].*$', '%1'); -- strip FQDN terminator and path(/), query(?), fragment (#) (the capture prevents false replacement of '//') if url_str:match ('^//%S*') then -- if there is what appears to be a protocol-relative URL domain = url_str:match ('^//(%S*)') elseif url_str:match ('%S-:/*%S+') then -- if there is what appears to be a scheme, optional authority indicator, and domain name scheme, authority, domain = url_str:match ('(%S-:)(/*)(%S+)'); -- extract the scheme, authority indicator, and domain portions if utilities.is_set (authority) then authority = authority:gsub ('//', '', 1); -- replace place 1 pair of '/' with nothing; if utilities.is_set(authority) then -- if anything left (1 or 3+ '/' where authority should be) then return scheme; -- return scheme only making domain nil which will cause an error message end else if not scheme:match ('^news:') then -- except for news:..., MediaWiki won't link URLs that do not have authority indicator; TODO: a better way to do this test? return scheme; -- return scheme only making domain nil which will cause an error message end end domain = domain:gsub ('(%a):%d+', '%1'); -- strip port number if present end return scheme, domain; end --[[--------------------------< L I N K _ P A R A M _ O K >--------------------------------------------------- checks the content of |title-link=, |series-link=, |author-link=, etc. for properly formatted content: no wikilinks, no URLs Link parameters are to hold the title of a Wikipedia article, so none of the WP:TITLESPECIALCHARACTERS are allowed: # < > [ ] | { } _ except the underscore which is used as a space in wiki URLs and # which is used for section links returns false when the value contains any of these characters. When there are no illegal characters, this function returns TRUE if value DOES NOT appear to be a valid URL (the |<param>-link= parameter is ok); else false when value appears to be a valid URL (the |<param>-link= parameter is NOT ok). ]] local function link_param_ok (value) local scheme, domain; if value:find ('[<>%[%]|{}]') then -- if any prohibited characters return false; end scheme, domain = split_url (value); -- get scheme or nil and domain or nil from URL; return not is_url (scheme, domain); -- return true if value DOES NOT appear to be a valid URL end --[[--------------------------< L I N K _ T I T L E _ O K >--------------------------------------------------- Use link_param_ok() to validate |<param>-link= value and its matching |<title>= value. |<title>= may be wiki-linked but not when |<param>-link= has a value. This function emits an error message when that condition exists check <link> for inter-language interwiki-link prefix. prefix must be a MediaWiki-recognized language code and must begin with a colon. ]] local function link_title_ok (link, lorig, title, torig) local orig; if utilities.is_set (link) then -- don't bother if <param>-link doesn't have a value if not link_param_ok (link) then -- check |<param>-link= markup orig = lorig; -- identify the failing link parameter elseif title:find ('%[%[') then -- check |title= for wikilink markup orig = torig; -- identify the failing |title= parameter elseif link:match ('^%a+:') then -- if the link is what looks like an interwiki local prefix = link:match ('^(%a+):'):lower(); -- get the interwiki prefix if cfg.inter_wiki_map[prefix] then -- if prefix is in the map, must have preceding colon orig = lorig; -- flag as error end end end if utilities.is_set (orig) then link = ''; -- unset utilities.set_message ('err_bad_paramlink', orig); -- URL or wikilink in |title= with |title-link=; end return link; -- link if ok, empty string else end --[[--------------------------< C H E C K _ U R L >------------------------------------------------------------ Determines whether a URL string appears to be valid. First we test for space characters. If any are found, return false. Then split the URL into scheme and domain portions, or for protocol-relative (//example.com) URLs, just the domain. Use is_url() to validate the two portions of the URL. If both are valid, or for protocol-relative if domain is valid, return true, else false. Because it is different from a standard URL, and because this module used external_link() to make external links that work for standard and news: links, we validate newsgroup names here. The specification for a newsgroup name is at https://tools.ietf.org/html/rfc5536#section-3.1.4 ]] local function check_url( url_str ) if nil == url_str:match ("^%S+$") then -- if there are any spaces in |url=value it can't be a proper URL return false; end local scheme, domain; scheme, domain = split_url (url_str); -- get scheme or nil and domain or nil from URL; if 'news:' == scheme then -- special case for newsgroups return domain:match('^[%a%d%+%-_]+%.[%a%d%+%-_%.]*[%a%d%+%-_]$'); end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[=[-------------------------< I S _ P A R A M E T E R _ E X T _ W I K I L I N K >---------------------------- Return true if a parameter value has a string that begins and ends with square brackets [ and ] and the first non-space characters following the opening bracket appear to be a URL. The test will also find external wikilinks that use protocol-relative URLs. Also finds bare URLs. The frontier pattern prevents a match on interwiki-links which are similar to scheme:path URLs. The tests that find bracketed URLs are required because the parameters that call this test (currently |title=, |chapter=, |work=, and |publisher=) may have wikilinks and there are articles or redirects like '//Hus' so, while uncommon, |title=[[//Hus]] is possible as might be [[en://Hus]]. ]=] local function is_parameter_ext_wikilink (value) local scheme, domain; if value:match ('%f[%[]%[%a%S*:%S+.*%]') then -- if ext. wikilink with scheme and domain: [xxxx://yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(%a%S*:%S+).*%]')); elseif value:match ('%f[%[]%[//%S+.*%]') then -- if protocol-relative ext. wikilink: [//yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(//%S+).*%]')); elseif value:match ('%a%S*:%S+') then -- if bare URL with scheme; may have leading or trailing plain text scheme, domain = split_url (value:match ('(%a%S*:%S+)')); elseif value:match ('^//%S+') or value:match ('%s//%S+') then -- if protocol-relative bare URL: //yyyyy.zzz; authority indicator (//) must be be preceded nothing or by whitespace scheme, domain = split_url (value:match ('(//%S+)')); -- what is left should be the domain else return false; -- didn't find anything that is obviously a URL end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[[-------------------------< C H E C K _ F O R _ U R L >----------------------------------------------------- loop through a list of parameters and their values. Look at the value and if it has an external link, emit an error message. ]] local function check_for_url (parameter_list, error_list) for k, v in pairs (parameter_list) do -- for each parameter in the list if is_parameter_ext_wikilink (v) then -- look at the value; if there is a URL add an error message table.insert (error_list, utilities.wrap_style ('parameter', k)); end end end --[[--------------------------< S A F E _ F O R _ U R L >------------------------------------------------------ Escape sequences for content that will be used for URL descriptions ]] local function safe_for_url( str ) if str:match( "%[%[.-%]%]" ) ~= nil then utilities.set_message ('err_wikilink_in_url', {}); end return str:gsub( '[%[%]\n]', { ['['] = '&#91;', [']'] = '&#93;', ['\n'] = ' ' } ); end --[[--------------------------< E X T E R N A L _ L I N K >---------------------------------------------------- Format an external link with error checking ]] local function external_link (URL, label, source, access) local err_msg = ''; local domain; local path; local base_url; if not utilities.is_set (label) then label = URL; if utilities.is_set (source) then utilities.set_message ('err_bare_url_missing_title', {utilities.wrap_style ('parameter', source)}); else error (cfg.messages["bare_url_no_origin"]); -- programmer error; valid parameter name does not have matching meta-parameter end end if not check_url (URL) then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); end domain, path = URL:match ('^([/%.%-%+:%a%d]+)([/%?#].*)$'); -- split the URL into scheme plus domain and path if path then -- if there is a path portion path = path:gsub ('[%[%]]', {['['] = '%5b', [']'] = '%5d'}); -- replace '[' and ']' with their percent-encoded values URL = table.concat ({domain, path}); -- and reassemble end base_url = table.concat ({ "[", URL, " ", safe_for_url (label), "]" }); -- assemble a wiki-markup URL if utilities.is_set (access) then -- access level (subscription, registration, limited) base_url = utilities.substitute (cfg.presentation['ext-link-access-signal'], {cfg.presentation[access].class, cfg.presentation[access].title, base_url}); -- add the appropriate icon end return base_url; end --[[--------------------------< D E P R E C A T E D _ P A R A M E T E R >-------------------------------------- Categorize and emit an error message when the citation contains one or more deprecated parameters. The function includes the offending parameter name to the error message. Only one error message is emitted regardless of the number of deprecated parameters in the citation. added_deprecated_cat is a Boolean declared in page scope variables above ]] local function deprecated_parameter(name) if not added_deprecated_cat then added_deprecated_cat = true; -- note that we've added this category utilities.set_message ('err_deprecated_params', {name}); -- add error message end end --[=[-------------------------< K E R N _ Q U O T E S >-------------------------------------------------------- Apply kerning to open the space between the quote mark provided by the module and a leading or trailing quote mark contained in a |title= or |chapter= parameter's value. This function will positive kern either single or double quotes: "'Unkerned title with leading and trailing single quote marks'" " 'Kerned title with leading and trailing single quote marks' " (in real life the kerning isn't as wide as this example) Double single quotes (italic or bold wiki-markup) are not kerned. Replaces Unicode quote marks in plain text or in the label portion of a [[L|D]] style wikilink with typewriter quote marks regardless of the need for kerning. Unicode quote marks are not replaced in simple [[D]] wikilinks. Call this function for chapter titles, for website titles, etc.; not for book titles. ]=] local function kern_quotes (str) local cap = ''; local wl_type, label, link; wl_type, label, link = utilities.is_wikilink (str); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] if 1 == wl_type then -- [[D]] simple wikilink with or without quote marks if mw.ustring.match (str, '%[%[[\"“”\'‘’].+[\"“”\'‘’]%]%]') then -- leading and trailing quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); str = utilities.substitute (cfg.presentation['kern-right'], str); elseif mw.ustring.match (str, '%[%[[\"“”\'‘’].+%]%]') then -- leading quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); elseif mw.ustring.match (str, '%[%[.+[\"“”\'‘’]%]%]') then -- trailing quote marks str = utilities.substitute (cfg.presentation['kern-right'], str); end else -- plain text or [[L|D]]; text in label variable label = mw.ustring.gsub (label, '[“”]', '\"'); -- replace “” (U+201C & U+201D) with " (typewriter double quote mark) label = mw.ustring.gsub (label, '[‘’]', '\''); -- replace ‘’ (U+2018 & U+2019) with ' (typewriter single quote mark) cap = mw.ustring.match (label, "^([\"\'][^\'].+)"); -- match leading double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-left'], cap); end cap = mw.ustring.match (label, "^(.+[^\'][\"\'])$") -- match trailing double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-right'], cap); end if 2 == wl_type then str = utilities.make_wikilink (link, label); -- reassemble the wikilink else str = label; end end return str; end --[[--------------------------< F O R M A T _ S C R I P T _ V A L U E >---------------------------------------- |script-title= holds title parameters that are not written in Latin-based scripts: Chinese, Japanese, Arabic, Hebrew, etc. These scripts should not be italicized and may be written right-to-left. The value supplied by |script-title= is concatenated onto Title after Title has been wrapped in italic markup. Regardless of language, all values provided by |script-title= are wrapped in <bdi>...</bdi> tags to isolate RTL languages from the English left to right. |script-title= provides a unique feature. The value in |script-title= may be prefixed with a two-character ISO 639-1 language code and a colon: |script-title=ja:*** *** (where * represents a Japanese character) Spaces between the two-character code and the colon and the colon and the first script character are allowed: |script-title=ja : *** *** |script-title=ja: *** *** |script-title=ja :*** *** Spaces preceding the prefix are allowed: |script-title = ja:*** *** The prefix is checked for validity. If it is a valid ISO 639-1 language code, the lang attribute (lang="ja") is added to the <bdi> tag so that browsers can know the language the tag contains. This may help the browser render the script more correctly. If the prefix is invalid, the lang attribute is not added. At this time there is no error message for this condition. Supports |script-title=, |script-chapter=, |script-<periodical>= ]] local function format_script_value (script_value, script_param) local lang=''; -- initialize to empty string local name; if script_value:match('^%l%l%l?%s*:') then -- if first 3 or 4 non-space characters are script language prefix lang = script_value:match('^(%l%l%l?)%s*:%s*%S.*'); -- get the language prefix or nil if there is no script if not utilities.is_set (lang) then utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing title part']}); -- prefix without 'title'; add error message return ''; -- script_value was just the prefix so return empty string end -- if we get this far we have prefix and script name = cfg.lang_tag_remap[lang] or mw.language.fetchLanguageName( lang, cfg.this_wiki_code ); -- get language name so that we can use it to categorize if utilities.is_set (name) then -- is prefix a proper ISO 639-1 language code? script_value = script_value:gsub ('^%l+%s*:%s*', ''); -- strip prefix from script -- is prefix one of these language codes? if utilities.in_array (lang, cfg.script_lang_codes) then utilities.add_prop_cat ('script', {name, lang}) else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['unknown language code']}); -- unknown script-language; add error message end lang = ' lang="' .. lang .. '" '; -- convert prefix into a lang attribute else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['invalid language code']}); -- invalid language code; add error message lang = ''; -- invalid so set lang to empty string end else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing prefix']}); -- no language code prefix; add error message end script_value = utilities.substitute (cfg.presentation['bdi'], {lang, script_value}); -- isolate in case script is RTL return script_value; end --[[--------------------------< S C R I P T _ C O N C A T E N A T E >------------------------------------------ Initially for |title= and |script-title=, this function concatenates those two parameter values after the script value has been wrapped in <bdi> tags. ]] local function script_concatenate (title, script, script_param) if utilities.is_set (script) then script = format_script_value (script, script_param); -- <bdi> tags, lang attribute, categorization, etc.; returns empty string on error if utilities.is_set (script) then title = title .. ' ' .. script; -- concatenate title and script title end end return title; end --[[--------------------------< W R A P _ M S G >-------------------------------------------------------------- Applies additional message text to various parameter values. Supplied string is wrapped using a message_list configuration taking one argument. Supports lower case text for {{citation}} templates. Additional text taken from citation_config.messages - the reason this function is similar to but separate from wrap_style(). ]] local function wrap_msg (key, str, lower) if not utilities.is_set ( str ) then return ""; end if true == lower then local msg; msg = cfg.messages[key]:lower(); -- set the message to lower case before return utilities.substitute ( msg, str ); -- including template text else return utilities.substitute ( cfg.messages[key], str ); end end --[[----------------< W I K I S O U R C E _ U R L _ M A K E >------------------- Makes a Wikisource URL from Wikisource interwiki-link. Returns the URL and appropriate label; nil else. str is the value assigned to |chapter= (or aliases) or |title= or |title-link= ]] local function wikisource_url_make (str) local wl_type, D, L; local ws_url, ws_label; local wikisource_prefix = table.concat ({'https://', cfg.this_wiki_code, '.wikisource.org/wiki/'}); wl_type, D, L = utilities.is_wikilink (str); -- wl_type is 0 (not a wikilink), 1 (simple wikilink), 2 (complex wikilink) if 0 == wl_type then -- not a wikilink; might be from |title-link= str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 1 == wl_type then -- simple wikilink: [[Wikisource:ws article]] str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 2 == wl_type then -- non-so-simple wikilink: [[Wikisource:ws article|displayed text]] ([[L|D]]) str = L:match ('^[Ww]ikisource:(.+)') or L:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_label = D; -- get ws article name from display portion of interwiki link ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title without namespace from link portion of wikilink }); end end if ws_url then ws_url = mw.uri.encode (ws_url, 'WIKI'); -- make a usable URL ws_url = ws_url:gsub ('%%23', '#'); -- undo percent-encoding of fragment marker end return ws_url, ws_label, L or D; -- return proper URL or nil and a label or nil end --[[----------------< F O R M A T _ P E R I O D I C A L >----------------------- Format the three periodical parameters: |script-<periodical>=, |<periodical>=, and |trans-<periodical>= into a single Periodical meta-parameter. ]] local function format_periodical (script_periodical, script_periodical_source, periodical, trans_periodical) if not utilities.is_set (periodical) then periodical = ''; -- to be safe for concatenation else periodical = utilities.wrap_style ('italic-title', periodical); -- style end periodical = script_concatenate (periodical, script_periodical, script_periodical_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (trans_periodical) then trans_periodical = utilities.wrap_style ('trans-italic-title', trans_periodical); if utilities.is_set (periodical) then periodical = periodical .. ' ' .. trans_periodical; else -- here when trans-periodical without periodical or script-periodical periodical = trans_periodical; utilities.set_message ('err_trans_missing_title', {'periodical'}); end end return periodical; end --[[------------------< F O R M A T _ C H A P T E R _ T I T L E >--------------- Format the four chapter parameters: |script-chapter=, |chapter=, |trans-chapter=, and |chapter-url= into a single chapter meta- parameter (chapter_url_source used for error messages). ]] local function format_chapter_title (script_chapter, script_chapter_source, chapter, chapter_source, trans_chapter, trans_chapter_source, chapter_url, chapter_url_source, no_quotes, access) local ws_url, ws_label, L = wikisource_url_make (chapter); -- make a wikisource URL and label from a wikisource interwiki link if ws_url then ws_label = ws_label:gsub ('_', ' '); -- replace underscore separators with space characters chapter = ws_label; end if not utilities.is_set (chapter) then chapter = ''; -- to be safe for concatenation else if false == no_quotes then chapter = kern_quotes (chapter); -- if necessary, separate chapter title's leading and trailing quote marks from module provided quote marks chapter = utilities.wrap_style ('quoted-title', chapter); end end chapter = script_concatenate (chapter, script_chapter, script_chapter_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (chapter_url) then chapter = external_link (chapter_url, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate elseif ws_url then chapter = external_link (ws_url, chapter .. '&nbsp;', 'ws link in chapter'); -- adds bare_url_missing_title error if appropriate; space char to move icon away from chap text; TODO: better way to do this? chapter = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, chapter}); end if utilities.is_set (trans_chapter) then trans_chapter = utilities.wrap_style ('trans-quoted-title', trans_chapter); if utilities.is_set (chapter) then chapter = chapter .. ' ' .. trans_chapter; else -- here when trans_chapter without chapter or script-chapter chapter = trans_chapter; chapter_source = trans_chapter_source:match ('trans%-?(.+)'); -- when no chapter, get matching name from trans-<param> utilities.set_message ('err_trans_missing_title', {chapter_source}); end end return chapter; end --[[----------------< H A S _ I N V I S I B L E _ C H A R S >------------------- This function searches a parameter's value for non-printable or invisible characters. The search stops at the first match. This function will detect the visible replacement character when it is part of the Wikisource. Detects but ignores nowiki and math stripmarkers. Also detects other named stripmarkers (gallery, math, pre, ref) and identifies them with a slightly different error message. See also coins_cleanup(). Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker that was detected along with its position (or, for multi-byte characters, the position of its first byte) in the parameter value. ]] local function has_invisible_chars (param, v) local position = ''; -- position of invisible char or starting position of stripmarker local capture; -- used by stripmarker detection to hold name of the stripmarker local stripmarker; -- boolean set true when a stripmarker is found capture = string.match (v, '[%w%p ]*'); -- test for values that are simple ASCII text and bypass other tests if true if capture == v then -- if same there are no Unicode characters return; end for _, invisible_char in ipairs (cfg.invisible_chars) do local char_name = invisible_char[1]; -- the character or group name local pattern = invisible_char[2]; -- the pattern used to find it position, _, capture = mw.ustring.find (v, pattern); -- see if the parameter value contains characters that match the pattern if position and (cfg.invisible_defs.zwj == capture) then -- if we found a zero-width joiner character if mw.ustring.find (v, cfg.indic_script) then -- it's ok if one of the Indic scripts position = nil; -- unset position elseif cfg.emoji_t[mw.ustring.codepoint (v, position+1)] then -- is zwj followed by a character listed in emoji{}? position = nil; -- unset position end end if position then if 'nowiki' == capture or 'math' == capture or -- nowiki and math stripmarkers (not an error condition) ('templatestyles' == capture and utilities.in_array (param, {'id', 'quote'})) then -- templatestyles stripmarker allowed in these parameters stripmarker = true; -- set a flag elseif true == stripmarker and cfg.invisible_defs.del == capture then -- because stripmakers begin and end with the delete char, assume that we've found one end of a stripmarker position = nil; -- unset else local err_msg; if capture and not (cfg.invisible_defs.del == capture or cfg.invisible_defs.zwj == capture) then err_msg = utilities.substitute (cfg.messages.invisible_1, {capture, char_name}); -- <capture> here is stripmarker name else err_msg = utilities.substitute (cfg.messages.invisible_2, char_name); end utilities.set_message ('err_invisible_char', {err_msg, utilities.wrap_style ('parameter', param), position}); -- add error message return; -- and done with this parameter end end end end --[[-------------------< A R G U M E N T _ W R A P P E R >---------------------- Argument wrapper. This function provides support for argument mapping defined in the configuration file so that multiple names can be transparently aliased to single internal variable. ]] local function argument_wrapper ( args ) local origin = {}; return setmetatable({ ORIGIN = function ( self, k ) local dummy = self[k]; -- force the variable to be loaded. return origin[k]; end }, { __index = function ( tbl, k ) if origin[k] ~= nil then return nil; end local args, list, v = args, cfg.aliases[k]; if type( list ) == 'table' then v, origin[k] = utilities.select_one ( args, list, 'err_redundant_parameters' ); if origin[k] == nil then origin[k] = ''; -- Empty string, not nil end elseif list ~= nil then v, origin[k] = args[list], list; else -- maybe let through instead of raising an error? -- v, origin[k] = args[k], k; error( cfg.messages['unknown_argument_map'] .. ': ' .. k); end -- Empty strings, not nil; if v == nil then v = ''; origin[k] = ''; end tbl = rawset( tbl, k, v ); return v; end, }); end --[[--------------------------< N O W R A P _ D A T E >------------------------- When date is YYYY-MM-DD format wrap in nowrap span: <span ...>YYYY-MM-DD</span>. When date is DD MMMM YYYY or is MMMM DD, YYYY then wrap in nowrap span: <span ...>DD MMMM</span> YYYY or <span ...>MMMM DD,</span> YYYY DOES NOT yet support MMMM YYYY or any of the date ranges. ]] local function nowrap_date (date) local cap = ''; local cap2 = ''; if date:match("^%d%d%d%d%-%d%d%-%d%d$") then date = utilities.substitute (cfg.presentation['nowrap1'], date); elseif date:match("^%a+%s*%d%d?,%s+%d%d%d%d$") or date:match ("^%d%d?%s*%a+%s+%d%d%d%d$") then cap, cap2 = string.match (date, "^(.*)%s+(%d%d%d%d)$"); date = utilities.substitute (cfg.presentation['nowrap2'], {cap, cap2}); end return date; end --[[--------------------------< S E T _ T I T L E T Y P E >--------------------- This function sets default title types (equivalent to the citation including |type=<default value>) for those templates that have defaults. Also handles the special case where it is desirable to omit the title type from the rendered citation (|type=none). ]] local function set_titletype (cite_class, title_type) if utilities.is_set (title_type) then if 'none' == cfg.keywords_xlate[title_type] then title_type = ''; -- if |type=none then type parameter not displayed end return title_type; -- if |type= has been set to any other value use that value end return cfg.title_types [cite_class] or ''; -- set template's default title type; else empty string for concatenation end --[[--------------------------< S A F E _ J O I N >----------------------------- Joins a sequence of strings together while checking for duplicate separation characters. ]] local function safe_join( tbl, duplicate_char ) local f = {}; -- create a function table appropriate to type of 'duplicate character' if 1 == #duplicate_char then -- for single byte ASCII characters use the string library functions f.gsub = string.gsub f.match = string.match f.sub = string.sub else -- for multi-byte characters use the ustring library functions f.gsub = mw.ustring.gsub f.match = mw.ustring.match f.sub = mw.ustring.sub end local str = ''; -- the output string local comp = ''; -- what does 'comp' mean? local end_chr = ''; local trim; for _, value in ipairs( tbl ) do if value == nil then value = ''; end if str == '' then -- if output string is empty str = value; -- assign value to it (first time through the loop) elseif value ~= '' then if value:sub(1, 1) == '<' then -- special case of values enclosed in spans and other markup. comp = value:gsub( "%b<>", "" ); -- remove HTML markup (<span>string</span> -> string) else comp = value; end -- typically duplicate_char is sepc if f.sub(comp, 1, 1) == duplicate_char then -- is first character same as duplicate_char? why test first character? -- Because individual string segments often (always?) begin with terminal punct for the -- preceding segment: 'First element' .. 'sepc next element' .. etc.? trim = false; end_chr = f.sub(str, -1, -1); -- get the last character of the output string -- str = str .. "<HERE(enchr=" .. end_chr .. ")" -- debug stuff? if end_chr == duplicate_char then -- if same as separator str = f.sub(str, 1, -2); -- remove it elseif end_chr == "'" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "''" then -- if last three chars of str are sepc'' str = f.sub(str, 1, -4) .. "''"; -- remove them and add back '' elseif f.sub(str, -5, -1) == duplicate_char .. "]]''" then -- if last five chars of str are sepc]]'' trim = true; -- why? why do this and next differently from previous? elseif f.sub(str, -4, -1) == duplicate_char .. "]''" then -- if last four chars of str are sepc]'' trim = true; -- same question end elseif end_chr == "]" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "]]" then -- if last three chars of str are sepc]] wikilink trim = true; elseif f.sub(str, -3, -1) == duplicate_char .. '"]' then -- if last three chars of str are sepc"] quoted external link trim = true; elseif f.sub(str, -2, -1) == duplicate_char .. "]" then -- if last two chars of str are sepc] external link trim = true; elseif f.sub(str, -4, -1) == duplicate_char .. "'']" then -- normal case when |url=something & |title=Title. trim = true; end elseif end_chr == " " then -- if last char of output string is a space if f.sub(str, -2, -1) == duplicate_char .. " " then -- if last two chars of str are <sepc><space> str = f.sub(str, 1, -3); -- remove them both end end if trim then if value ~= comp then -- value does not equal comp when value contains HTML markup local dup2 = duplicate_char; if f.match(dup2, "%A" ) then dup2 = "%" .. dup2; end -- if duplicate_char not a letter then escape it value = f.gsub(value, "(%b<>)" .. dup2, "%1", 1 ) -- remove duplicate_char if it follows HTML markup else value = f.sub(value, 2, -1 ); -- remove duplicate_char when it is first character end end end str = str .. value; -- add it to the output string end end return str; end --[[--------------------------< I S _ S U F F I X >----------------------------- returns true if suffix is properly formed Jr, Sr, or ordinal in the range 1–9. Puncutation not allowed. ]] local function is_suffix (suffix) if utilities.in_array (suffix, {'Jr', 'Sr', 'Jnr', 'Snr', '1st', '2nd', '3rd'}) or suffix:match ('^%dth$') then return true; end return false; end --[[--------------------< I S _ G O O D _ V A N C _ N A M E >------------------- For Vancouver style, author/editor names are supposed to be rendered in Latin (read ASCII) characters. When a name uses characters that contain diacritical marks, those characters are to be converted to the corresponding Latin character. When a name is written using a non-Latin alphabet or logogram, that name is to be transliterated into Latin characters. The module doesn't do this so editors may/must. This test allows |first= and |last= names to contain any of the letters defined in the four Unicode Latin character sets [http://www.unicode.org/charts/PDF/U0000.pdf C0 Controls and Basic Latin] 0041–005A, 0061–007A [http://www.unicode.org/charts/PDF/U0080.pdf C1 Controls and Latin-1 Supplement] 00C0–00D6, 00D8–00F6, 00F8–00FF [http://www.unicode.org/charts/PDF/U0100.pdf Latin Extended-A] 0100–017F [http://www.unicode.org/charts/PDF/U0180.pdf Latin Extended-B] 0180–01BF, 01C4–024F |lastn= also allowed to contain hyphens, spaces, and apostrophes. (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) |firstn= also allowed to contain hyphens, spaces, apostrophes, and periods This original test: if nil == mw.ustring.find (last, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%'%.]+[2-6%a]*$") then was written outside of the code editor and pasted here because the code editor gets confused between character insertion point and cursor position. The test has been rewritten to use decimal character escape sequence for the individual bytes of the Unicode characters so that it is not necessary to use an external editor to maintain this code. \195\128-\195\150 – À-Ö (U+00C0–U+00D6 – C0 controls) \195\152-\195\182 – Ø-ö (U+00D8-U+00F6 – C0 controls) \195\184-\198\191 – ø-ƿ (U+00F8-U+01BF – C0 controls, Latin extended A & B) \199\132-\201\143 – DŽ-ɏ (U+01C4-U+024F – Latin extended B) ]] local function is_good_vanc_name (last, first, suffix, position) if not suffix then if first:find ('[,%s]') then -- when there is a space or comma, might be first name/initials + generational suffix first = first:match ('(.-)[,%s]+'); -- get name/initials suffix = first:match ('[,%s]+(.+)$'); -- get generational suffix end end if utilities.is_set (suffix) then if not is_suffix (suffix) then add_vanc_error (cfg.err_msg_supl.suffix, position); return false; -- not a name with an appropriate suffix end end if nil == mw.ustring.find (last, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%'%.]*$") then add_vanc_error (cfg.err_msg_supl['non-Latin char'], position); return false; -- not a string of Latin characters; Vancouver requires Romanization end; return true; end --[[--------------------------< R E D U C E _ T O _ I N I T I A L S >------------------------------------------ Attempts to convert names to initials in support of |name-list-style=vanc. Names in |firstn= may be separated by spaces or hyphens, or for initials, a period. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35062/. Vancouver style requires family rank designations (Jr, II, III, etc.) to be rendered as Jr, 2nd, 3rd, etc. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35085/. This code only accepts and understands generational suffix in the Vancouver format because Roman numerals look like, and can be mistaken for, initials. This function uses ustring functions because firstname initials may be any of the Unicode Latin characters accepted by is_good_vanc_name (). ]] local function reduce_to_initials (first, position) if first:find (',', 1, true) then return first; -- commas not allowed; abandon end local name, suffix = mw.ustring.match (first, "^(%u+) ([%dJS][%drndth]+)$"); if not name then -- if not initials and a suffix name = mw.ustring.match (first, "^(%u+)$"); -- is it just initials? end if name then -- if first is initials with or without suffix if 3 > mw.ustring.len (name) then -- if one or two initials if suffix then -- if there is a suffix if is_suffix (suffix) then -- is it legitimate? return first; -- one or two initials and a valid suffix so nothing to do else add_vanc_error (cfg.err_msg_supl.suffix, position); -- one or two initials with invalid suffix so error message return first; -- and return first unmolested end else return first; -- one or two initials without suffix; nothing to do end end end -- if here then name has 3 or more uppercase letters so treat them as a word local initials_t, names_t = {}, {}; -- tables to hold name parts and initials local i = 1; -- counter for number of initials names_t = mw.text.split (first, '[%s%-]+'); -- split into a sequence of names and possible suffix while names_t[i] do -- loop through the sequence if 1 < i and names_t[i]:match ('[%dJS][%drndth]+%.?$') then -- if not the first name, and looks like a suffix (may have trailing dot) names_t[i] = names_t[i]:gsub ('%.', ''); -- remove terminal dot if present if is_suffix (names_t[i]) then -- if a legitimate suffix table.insert (initials_t, ' ' .. names_t[i]); -- add a separator space, insert at end of initials sequence break; -- and done because suffix must fall at the end of a name end -- no error message if not a suffix; possibly because of Romanization end if 3 > i then table.insert (initials_t, mw.ustring.sub (names_t[i], 1, 1)); -- insert the initial at end of initials sequence end i = i + 1; -- bump the counter end return table.concat (initials_t); -- Vancouver format does not include spaces. end --[[--------------------------< I N T E R W I K I _ P R E F I X E N _ G E T >---------------------------------- extract interwiki prefixen from <value>. Returns two one or two values: false – no prefixen nil – prefix exists but not recognized project prefix, language prefix – when value has either of: :<project>:<language>:<article> :<language>:<project>:<article> project prefix, nil – when <value> has only a known single-letter prefix nil, language prefix – when <value> has only a known language prefix accepts single-letter project prefixen: 'd' (wikidata), 's' (wikisource), and 'w' (wikipedia) prefixes; at this writing, the other single-letter prefixen (b (wikibook), c (commons), m (meta), n (wikinews), q (wikiquote), and v (wikiversity)) are not supported. ]] local function interwiki_prefixen_get (value, is_link) if not value:find (':%l+:') then -- if no prefix return false; -- abandon; boolean here to distinguish from nil fail returns later end local prefix_patterns_linked_t = { -- sequence of valid interwiki and inter project prefixen '^%[%[:([dsw]):(%l%l+):', -- wikilinked; project and language prefixes '^%[%[:(%l%l+):([dsw]):', -- wikilinked; language and project prefixes '^%[%[:([dsw]):', -- wikilinked; project prefix '^%[%[:(%l%l+):', -- wikilinked; language prefix } local prefix_patterns_unlinked_t = { -- sequence of valid interwiki and inter project prefixen '^:([dsw]):(%l%l+):', -- project and language prefixes '^:(%l%l+):([dsw]):', -- language and project prefixes '^:([dsw]):', -- project prefix '^:(%l%l+):', -- language prefix } local cap1, cap2; for _, pattern in ipairs ((is_link and prefix_patterns_linked_t) or prefix_patterns_unlinked_t) do cap1, cap2 = value:match (pattern); if cap1 then break; -- found a match so stop looking end end if cap1 and cap2 then -- when both then :project:language: or :language:project: (both forms allowed) if 1 == #cap1 then -- length == 1 then :project:language: if cfg.inter_wiki_map[cap2] then -- is language prefix in the interwiki map? return cap1, cap2; -- return interwiki project and interwiki language end else -- here when :language:project: if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return cap2, cap1; -- return interwiki project and interwiki language end end return nil; -- unknown interwiki language elseif not (cap1 or cap2) then -- both are nil? return nil; -- we got something that looks like a project prefix but isn't; return fail elseif 1 == #cap1 then -- here when one capture return cap1, nil; -- length is 1 so return project, nil language else -- here when one capture and its length it more than 1 if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return nil, cap1; -- return nil project, language end end end --[[--------------------------< L I S T _ P E O P L E >-------------------------- Formats a list of people (authors, contributors, editors, interviewers, translators) names in the list will be linked when |<name>-link= has a value |<name>-mask- does NOT have a value; masked names are presumed to have been rendered previously so should have been linked there when |<name>-mask=0, the associated name is not rendered ]] local function list_people (control, people, etal) local sep; local namesep; local format = control.format; local maximum = control.maximum; local name_list = {}; if 'vanc' == format then -- Vancouver-like name styling? sep = cfg.presentation['sep_nl_vanc']; -- name-list separator between names is a comma namesep = cfg.presentation['sep_name_vanc']; -- last/first separator is a space else sep = cfg.presentation['sep_nl']; -- name-list separator between names is a semicolon namesep = cfg.presentation['sep_name']; -- last/first separator is <comma><space> end if sep:sub (-1, -1) ~= " " then sep = sep .. " " end if utilities.is_set (maximum) and maximum < 1 then return "", 0; end -- returned 0 is for EditorCount; not used for other names for i, person in ipairs (people) do if utilities.is_set (person.last) then local mask = person.mask; local one; local sep_one = sep; if utilities.is_set (maximum) and i > maximum then etal = true; break; end if mask then local n = tonumber (mask); -- convert to a number if it can be converted; nil else if n then one = 0 ~= n and string.rep("&mdash;", n) or nil; -- make a string of (n > 0) mdashes, nil else, to replace name person.link = nil; -- don't create link to name if name is replaces with mdash string or has been set nil else one = mask; -- replace name with mask text (must include name-list separator) sep_one = " "; -- modify name-list separator end else one = person.last; -- get surname local first = person.first -- get given name if utilities.is_set (first) then if ("vanc" == format) then -- if Vancouver format one = one:gsub ('%.', ''); -- remove periods from surnames (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) if not person.corporate and is_good_vanc_name (one, first, nil, i) then -- and name is all Latin characters; corporate authors not tested first = reduce_to_initials (first, i); -- attempt to convert first name(s) to initials end end one = one .. namesep .. first; end end if utilities.is_set (person.link) then one = utilities.make_wikilink (person.link, one); -- link author/editor end if one then -- if <one> has a value (name, mdash replacement, or mask text replacement) local proj, tag = interwiki_prefixen_get (one, true); -- get the interwiki prefixen if present if 'w' == proj and ('Wikipedia' == mw.site.namespaces.Project['name']) then proj = nil; -- for stuff like :w:de:<article>, :w is unnecessary TODO: maint cat? end if proj then local proj_name = ({['d'] = cfg.messages.wikidata, ['s'] = cfg.messages.wikisource, ['w'] = cfg.messages.wikipedia})[proj]; -- :w (wikipedia) for linking from a non-wikipedia project if proj_name then one = one .. utilities.wrap_style ('interproj', proj_name); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interproj-linked-name', proj); -- categorize it; <proj> is sort key tag = nil; -- unset; don't do both project and language end end if tag == cfg.this_wiki_code then tag = nil; -- stuff like :en:<article> at en.wiki is pointless TODO: maint cat? end if tag then local lang = cfg.lang_tag_remap[tag] or cfg.mw_languages_by_tag_t[tag]; if lang then -- error messaging done in extract_names() where we know parameter names one = one .. utilities.wrap_style ('interwiki', lang); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interwiki-linked-name', tag); -- categorize it; <tag> is sort key end end table.insert (name_list, one); -- add it to the list of names table.insert (name_list, sep_one); -- add the proper name-list separator end end end local count = #name_list / 2; -- (number of names + number of separators) divided by 2 if 0 < count then if 1 < count and not etal then if 'amp' == format then name_list[#name_list-2] = " & "; -- replace last separator with ampersand text elseif 'and' == format then if 2 == count then name_list[#name_list-2] = cfg.presentation.sep_nl_and; -- replace last separator with 'and' text else name_list[#name_list-2] = cfg.presentation.sep_nl_end; -- replace last separator with '(sep) and' text end end end name_list[#name_list] = nil; -- erase the last separator end local result = table.concat (name_list); -- construct list if etal and utilities.is_set (result) then -- etal may be set by |display-authors=etal but we might not have a last-first list result = result .. sep .. cfg.messages['et al']; -- we've got a last-first list and etal so add et al. end return result, count; -- return name-list string and count of number of names (count used for editor names only) end --[[--------------------< M A K E _ C I T E R E F _ I D >----------------------- Generates a CITEREF anchor ID if we have at least one name or a date. Otherwise returns an empty string. namelist is one of the contributor-, author-, or editor-name lists chosen in that order. year is Year or anchor_year. ]] local function make_citeref_id (namelist, year) local names={}; -- a table for the one to four names and year for i,v in ipairs (namelist) do -- loop through the list and take up to the first four last names names[i] = v.last if i == 4 then break end -- if four then done end table.insert (names, year); -- add the year at the end local id = table.concat(names); -- concatenate names and year for CITEREF id if utilities.is_set (id) then -- if concatenation is not an empty string return "CITEREF" .. id; -- add the CITEREF portion else return ''; -- return an empty string; no reason to include CITEREF id in this citation end end --[[--------------------------< C I T E _ C L A S S _A T T R I B U T E _M A K E >------------------------------ construct <cite> tag class attribute for this citation. <cite_class> – config.CitationClass from calling template <mode> – value from |mode= parameter ]] local function cite_class_attribute_make (cite_class, mode) local class_t = {}; table.insert (class_t, 'citation'); -- required for blue highlight if 'citation' ~= cite_class then table.insert (class_t, cite_class); -- identify this template for user css table.insert (class_t, utilities.is_set (mode) and mode or 'cs1'); -- identify the citation style for user css or javascript else table.insert (class_t, utilities.is_set (mode) and mode or 'cs2'); -- identify the citation style for user css or javascript end for _, prop_key in ipairs (z.prop_keys_t) do table.insert (class_t, prop_key); -- identify various properties for user css or javascript end return table.concat (class_t, ' '); -- make a big string and done end --[[---------------------< N A M E _ H A S _ E T A L >-------------------------- Evaluates the content of name parameters (author, editor, etc.) for variations on the theme of et al. If found, the et al. is removed, a flag is set to true and the function returns the modified name and the flag. This function never sets the flag to false but returns its previous state because it may have been set by previous passes through this function or by the associated |display-<names>=etal parameter ]] local function name_has_etal (name, etal, nocat, param) if utilities.is_set (name) then -- name can be nil in which case just return local patterns = cfg.et_al_patterns; -- get patterns from configuration for _, pattern in ipairs (patterns) do -- loop through all of the patterns if name:match (pattern) then -- if this 'et al' pattern is found in name name = name:gsub (pattern, ''); -- remove the offending text etal = true; -- set flag (may have been set previously here or by |display-<names>=etal) if not nocat then -- no categorization for |vauthors= utilities.set_message ('err_etal', {param}); -- and set an error if not added end end end end return name, etal; end --[[---------------------< N A M E _ I S _ N U M E R I C >---------------------- Add an error message and category when <name> parameter value does not contain letters. Add a maintenance category when <name> parameter value has numeric characters mixed with characters that are not numeric characters; could be letters and/or punctuation characters. This function will only emit one error and one maint message for the current template. Does not emit both error and maint messages/categories for the same parameter value. returns nothing ]] local function name_is_numeric (name, name_alias, list_name) local patterns = { '^%D+%d', -- <name> must have digits preceded by other characters '^%D*%d+%D+', -- <name> must have digits followed by other characters } if not added_numeric_name_errs and mw.ustring.match (name, '^[%A]+$') then -- if we have not already set an error message and <name> does not have any alpha characters utilities.set_message ('err_numeric_names', name_alias); -- add an error message added_numeric_name_errs = true; -- set the flag so we emit only one error message return; -- when here no point in further testing; abandon end if not added_numeric_name_maint then -- if we have already set a maint message for _, pattern in ipairs (patterns) do -- spin through list of patterns if mw.ustring.match (name, pattern) then -- digits preceded or followed by anything but digits; %D+ includes punctuation utilities.set_message ('maint_numeric_names', cfg.special_case_translation [list_name]); -- add a maint cat for this template added_numeric_name_maint = true; -- set the flag so we emit only one maint message return; -- when here no point in further testing; abandon end end end end --[[-----------------< N A M E _ H A S _ M U L T _ N A M E S >------------------ Evaluates the content of last/surname (authors etc.) parameters for multiple names. Multiple names are indicated if there is more than one comma or any "unescaped" semicolons. Escaped semicolons are ones used as part of selected HTML entities. If the condition is met, the function adds the multiple name maintenance category. Same test for first except that commas should not appear in given names (MOS:JR says that the generational suffix does not take a separator character). Titles, degrees, postnominals, affiliations, all normally comma separated don't belong in a citation. <name> – name parameter value <list_name> – AuthorList, EditorList, etc <limit> – number of allowed commas; 1 (default) for surnames; 0 for given names returns nothing ]] local function name_has_mult_names (name, list_name, limit) local _, commas, semicolons, nbsps; limit = limit and limit or 1; if utilities.is_set (name) then _, commas = name:gsub (',', ''); -- count the number of commas _, semicolons = name:gsub (';', ''); -- count the number of semicolons -- nbsps probably should be its own separate count rather than merged in -- some way with semicolons because Lua patterns do not support the -- grouping operator that regex does, which means there is no way to add -- more entities to escape except by adding more counts with the new -- entities _, nbsps = name:gsub ('&nbsp;',''); -- count nbsps -- There is exactly 1 semicolon per &nbsp; entity, so subtract nbsps -- from semicolons to 'escape' them. If additional entities are added, -- they also can be subtracted. if limit < commas or 0 < (semicolons - nbsps) then utilities.set_message ('maint_mult_names', cfg.special_case_translation [list_name]); -- add a maint message end end end --[=[-------------------------< I S _ G E N E R I C >---------------------------------------------------------- Compares values assigned to various parameters according to the string provided as <item> in the function call. <item> can have on of two values: 'generic_names' – for name-holding parameters: |last=, |first=, |editor-last=, etc 'generic_titles' – for |title= There are two types of generic tests. The 'accept' tests look for a pattern that should not be rejected by the 'reject' test. For example, |author=[[John Smith (author)|Smith, John]] would be rejected by the 'author' reject test. But piped wikilinks with 'author' disambiguation should not be rejected so the 'accept' test prevents that from happening. Accept tests are always performed before reject tests. Each of the 'accept' and 'reject' sequence tables hold tables for en.wiki (['en']) and local.wiki (['local']) that each can hold a test sequence table The sequence table holds, at index [1], a test pattern, and, at index [2], a boolean control value. The control value tells string.find() or mw.ustring.find() to do plain-text search (true) or a pattern search (false). The intent of all this complexity is to make these searches as fast as possible so that we don't run out of processing time on very large articles. Returns true when a reject test finds the pattern or string false when an accept test finds the pattern or string nil else ]=] local function is_generic (item, value, wiki) local test_val; local str_lower = { -- use string.lower() for en.wiki (['en']) and use mw.ustring.lower() or local.wiki (['local']) ['en'] = string.lower, ['local'] = mw.ustring.lower, } local str_find = { -- use string.find() for en.wiki (['en']) and use mw.ustring.find() or local.wiki (['local']) ['en'] = string.find, ['local'] = mw.ustring.find, } local function test (val, test_t, wiki) -- local function to do the testing; <wiki> selects lower() and find() functions val = test_t[2] and str_lower[wiki](value) or val; -- when <test_t[2]> set to 'true', plaintext search using lowercase value return str_find[wiki] (val, test_t[1], 1, test_t[2]); -- return nil when not found or matched end local test_types_t = {'accept', 'reject'}; -- test accept patterns first, then reject patterns local wikis_t = {'en', 'local'}; -- do tests for each of these keys; en.wiki first, local.wiki second for _, test_type in ipairs (test_types_t) do -- for each test type for _, generic_value in pairs (cfg.special_case_translation[item][test_type]) do -- spin through the list of generic value fragments to accept or reject for _, wiki in ipairs (wikis_t) do if generic_value[wiki] then if test (value, generic_value[wiki], wiki) then -- go do the test return ('reject' == test_type); -- param value rejected, return true; false else end end end end end end --[[--------------------------< N A M E _ I S _ G E N E R I C >------------------------------------------------ calls is_generic() to determine if <name> is a 'generic name' listed in cfg.generic_names; <name_alias> is the parameter name used in error messaging ]] local function name_is_generic (name, name_alias) if not added_generic_name_errs and is_generic ('generic_names', name) then utilities.set_message ('err_generic_name', name_alias); -- set an error message added_generic_name_errs = true; end end --[[--------------------------< N A M E _ C H E C K S >-------------------------------------------------------- This function calls various name checking functions used to validate the content of the various name-holding parameters. ]] local function name_checks (last, first, list_name, last_alias, first_alias) local accept_name; if utilities.is_set (last) then last, accept_name = utilities.has_accept_as_written (last); -- remove accept-this-as-written markup when it wraps all of <last> if not accept_name then -- <last> not wrapped in accept-as-written markup name_has_mult_names (last, list_name); -- check for multiple names in the parameter name_is_numeric (last, last_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (last, last_alias); -- check for names found in the generic names list end end if utilities.is_set (first) then first, accept_name = utilities.has_accept_as_written (first); -- remove accept-this-as-written markup when it wraps all of <first> if not accept_name then -- <first> not wrapped in accept-as-written markup name_has_mult_names (first, list_name, 0); -- check for multiple names in the parameter; 0 is number of allowed commas in a given name name_is_numeric (first, first_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (first, first_alias); -- check for names found in the generic names list end local wl_type, D = utilities.is_wikilink (first); if 0 ~= wl_type then first = D; utilities.set_message ('err_bad_paramlink', first_alias); end end return last, first; -- done end --[[----------------------< E X T R A C T _ N A M E S >------------------------- Gets name list from the input arguments Searches through args in sequential order to find |lastn= and |firstn= parameters (or their aliases), and their matching link and mask parameters. Stops searching when both |lastn= and |firstn= are not found in args after two sequential attempts: found |last1=, |last2=, and |last3= but doesn't find |last4= and |last5= then the search is done. This function emits an error message when there is a |firstn= without a matching |lastn=. When there are 'holes' in the list of last names, |last1= and |last3= are present but |last2= is missing, an error message is emitted. |lastn= is not required to have a matching |firstn=. When an author or editor parameter contains some form of 'et al.', the 'et al.' is stripped from the parameter and a flag (etal) returned that will cause list_people() to add the static 'et al.' text from Module:Citation/CS1/Configuration. This keeps 'et al.' out of the template's metadata. When this occurs, an error is emitted. ]] local function extract_names(args, list_name) local names = {}; -- table of names local last; -- individual name components local first; local link; local mask; local i = 1; -- loop counter/indexer local n = 1; -- output table indexer local count = 0; -- used to count the number of times we haven't found a |last= (or alias for authors, |editor-last or alias for editors) local etal = false; -- return value set to true when we find some form of et al. in an author parameter local last_alias, first_alias, link_alias; -- selected parameter aliases used in error messaging while true do last, last_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'err_redundant_parameters', i ); -- search through args for name components beginning at 1 first, first_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'err_redundant_parameters', i ); link, link_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ); mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); if last then -- error check |lastn= alias for unknown interwiki link prefix; done here because this is where we have the parameter name local project, language = interwiki_prefixen_get (last, true); -- true because we expect interwiki links in |lastn= to be wikilinked if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', last_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? last = utilities.remove_wiki_link (last); -- remove wikilink markup; show display value only end end if link then -- error check |linkn= alias for unknown interwiki link prefix local project, language = interwiki_prefixen_get (link, false); -- false because wiki links in |author-linkn= is an error if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', link_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? link = nil; -- unset so we don't link link_alias = nil; end end last, etal = name_has_etal (last, etal, false, last_alias); -- find and remove variations on et al. first, etal = name_has_etal (first, etal, false, first_alias); -- find and remove variations on et al. last, first = name_checks (last, first, list_name, last_alias, first_alias); -- multiple names, extraneous annotation, etc. checks if first and not last then -- if there is a firstn without a matching lastn local alias = first_alias:find ('given', 1, true) and 'given' or 'first'; -- get first or given form of the alias utilities.set_message ('err_first_missing_last', { first_alias, -- param name of alias missing its mate first_alias:gsub (alias, {['first'] = 'last', ['given'] = 'surname'}), -- make param name appropriate to the alias form }); -- add this error message elseif not first and not last then -- if both firstn and lastn aren't found, are we done? count = count + 1; -- number of times we haven't found last and first if 2 <= count then -- two missing names and we give up break; -- normal exit or there is a two-name hole in the list; can't tell which end else -- we have last with or without a first local result; link = link_title_ok (link, link_alias, last, last_alias); -- check for improper wiki-markup if first then link = link_title_ok (link, link_alias, first, first_alias); -- check for improper wiki-markup end names[n] = {last = last, first = first, link = link, mask = mask, corporate = false}; -- add this name to our names list (corporate for |vauthors= only) n = n + 1; -- point to next location in the names table if 1 == count then -- if the previous name was missing utilities.set_message ('err_missing_name', {list_name:match ("(%w+)List"):lower(), i - 1}); -- add this error message end count = 0; -- reset the counter, we're looking for two consecutive missing names end i = i + 1; -- point to next args location end return names, etal; -- all done, return our list of names and the etal flag end --[[--------------------------< N A M E _ T A G _ G E T >------------------------------------------------------ attempt to decode |language=<lang_param> and return language name and matching tag; nil else. This function looks for: <lang_param> as a tag in cfg.lang_tag_remap{} <lang_param> as a name in cfg.lang_name_remap{} <lang_param> as a name in cfg.mw_languages_by_name_t <lang_param> as a tag in cfg.mw_languages_by_tag_t when those fail, presume that <lang_param> is an IETF-like tag that MediaWiki does not recognize. Strip all script, region, variant, whatever subtags from <lang_param> to leave just a two or three character language tag and look for the new <lang_param> in cfg.mw_languages_by_tag_t{} on success, returns name (in properly capitalized form) and matching tag (in lowercase); on failure returns nil ]] local function name_tag_get (lang_param) local lang_param_lc = mw.ustring.lower (lang_param); -- use lowercase as an index into the various tables local name; local tag; name = cfg.lang_tag_remap[lang_param_lc]; -- assume <lang_param_lc> is a tag; attempt to get remapped language name if name then -- when <name>, <lang_param> is a tag for a remapped language name if cfg.lang_name_remap[name:lower()][2] ~= lang_param_lc then utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added return name, cfg.lang_name_remap[name:lower()][2]; -- so return name and tag from lang_name_remap[name]; special case to xlate sr-ec and sr-el to sr-cyrl and sr-latn end return name, lang_param_lc; -- so return <name> from remap and <lang_param_lc> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- still assuming that <lang_param_lc> is a tag; strip script, region, variant subtags name = cfg.lang_tag_remap[tag]; -- attempt to get remapped language name with language subtag only if name then -- when <name>, <tag> is a tag for a remapped language name return name, tag; -- so return <name> from remap and <tag> end if cfg.lang_name_remap[lang_param_lc] then -- not a remapped tag, assume <lang_param_lc> is a name; attempt to get remapped language tag return cfg.lang_name_remap[lang_param_lc][1], cfg.lang_name_remap[lang_param_lc][2]; -- for this <lang_param_lc>, return a (possibly) new name and appropriate tag end name = cfg.mw_languages_by_tag_t[lang_param_lc]; -- assume that <lang_param_lc> is a tag; attempt to get its matching language name if name then return name, lang_param_lc; -- <lang_param_lc> is a tag so return it and <name> end tag = cfg.mw_languages_by_name_t[lang_param_lc]; -- assume that <lang_param_lc> is a language name; attempt to get its matching tag if tag then return cfg.mw_languages_by_tag_t[tag], tag; -- <lang_param_lc> is a name so return the name from the table and <tag> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- is <lang_param_lc> an IETF-like tag that MediaWiki doesn't recognize? <tag> gets the language subtag; nil else if tag then name = cfg.mw_languages_by_tag_t[tag]; -- attempt to get a language name using the shortened <tag> if name then return name, tag; -- <lang_param_lc> is an unrecognized IETF-like tag so return <name> and language subtag end end end --[[-------------------< L A N G U A G E _ P A R A M E T E R >------------------ Gets language name from a provided two- or three-character ISO 639 code. If a code is recognized by MediaWiki, use the returned name; if not, then use the value that was provided with the language parameter. When |language= contains a recognized language (either code or name), the page is assigned to the category for that code: Category:Norwegian-language sources (no). For valid three-character code languages, the page is assigned to the single category for '639-2' codes: Category:CS1 ISO 639-2 language sources. Languages that are the same as the local wiki are not categorized. MediaWiki does not recognize three-character equivalents of two-character codes: code 'ar' is recognized but code 'ara' is not. This function supports multiple languages in the form |language=nb, French, th where the language names or codes are separated from each other by commas with optional space characters. ]] local function language_parameter (lang) local tag; -- some form of IETF-like language tag; language subtag with optional region, sript, vatiant, etc subtags local lang_subtag; -- ve populates |language= with mostly unecessary region subtags the MediaWiki does not recognize; this is the base language subtag local name; -- the language name local language_list = {}; -- table of language names to be rendered local names_t = {}; -- table made from the value assigned to |language= local this_wiki_name = mw.language.fetchLanguageName (cfg.this_wiki_code, cfg.this_wiki_code); -- get this wiki's language name names_t = mw.text.split (lang, '%s*,%s*'); -- names should be a comma separated list for _, lang in ipairs (names_t) do -- reuse lang here because we don't yet know if lang is a language name or a language tag name, tag = name_tag_get (lang); -- attempt to get name/tag pair for <lang>; <name> has proper capitalization; <tag> is lowercase if utilities.is_set (tag) then lang_subtag = tag:gsub ('^(%a%a%a?)%-.*', '%1'); -- for categorization, strip any IETF-like tags from language tag if cfg.this_wiki_code ~= lang_subtag then -- when the language is not the same as this wiki's language if 2 == lang_subtag:len() then -- and is a two-character tag utilities.add_prop_cat ('foreign-lang-source', {name, tag}, lang_subtag); -- categorize it; tag appended to allow for multiple language categorization else -- or is a recognized language (but has a three-character tag) utilities.add_prop_cat ('foreign-lang-source-2', {lang_subtag}, lang_subtag); -- categorize it differently TODO: support multiple three-character tag categories per cs1|2 template? end elseif cfg.local_lang_cat_enable then -- when the language and this wiki's language are the same and categorization is enabled utilities.add_prop_cat ('local-lang-source', {name, lang_subtag}); -- categorize it end else name = lang; -- return whatever <lang> has so that we show something utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added end table.insert (language_list, name); name = ''; -- so we can reuse it end name = utilities.make_sep_list (#language_list, language_list); if (1 == #language_list) and (lang_subtag == cfg.this_wiki_code) then -- when only one language, find lang name in this wiki lang name; for |language=en-us, 'English' in 'American English' return ''; -- if one language and that language is this wiki's return an empty string (no annotation) end return (" " .. wrap_msg ('language', name)); -- otherwise wrap with '(in ...)' --[[ TODO: should only return blank or name rather than full list so we can clean up the bunched parenthetical elements Language, Type, Format ]] end --[[-----------------------< S E T _ C S _ S T Y L E >-------------------------- Gets the default CS style configuration for the given mode. Returns default separator and either postscript as passed in or the default. In CS1, the default postscript and separator are '.'. In CS2, the default postscript is the empty string and the default separator is ','. ]] local function set_cs_style (postscript, mode) if utilities.is_set(postscript) then -- emit a maintenance message if user postscript is the default cs1 postscript -- we catch the opposite case for cs2 in set_style if mode == 'cs1' and postscript == cfg.presentation['ps_' .. mode] then utilities.set_message ('maint_postscript'); end else postscript = cfg.presentation['ps_' .. mode]; end return cfg.presentation['sep_' .. mode], postscript; end --[[--------------------------< S E T _ S T Y L E >----------------------------- Sets the separator and postscript styles. Checks the |mode= first and the #invoke CitationClass second. Removes the postscript if postscript == none. ]] local function set_style (mode, postscript, cite_class) local sep; if 'cs2' == mode then sep, postscript = set_cs_style (postscript, 'cs2'); elseif 'cs1' == mode then sep, postscript = set_cs_style (postscript, 'cs1'); elseif 'citation' == cite_class then sep, postscript = set_cs_style (postscript, 'cs2'); else sep, postscript = set_cs_style (postscript, 'cs1'); end if cfg.keywords_xlate[postscript:lower()] == 'none' then -- emit a maintenance message if user postscript is the default cs2 postscript -- we catch the opposite case for cs1 in set_cs_style if 'cs2' == mode or ('cs1' ~= mode and 'citation' == cite_class) then -- {{citation |title=Title |mode=cs1 |postscript=none}} should not emit maint message utilities.set_message ('maint_postscript'); end postscript = ''; end return sep, postscript end --[=[-------------------------< I S _ P D F >----------------------------------- Determines if a URL has the file extension that is one of the PDF file extensions used by [[MediaWiki:Common.css]] when applying the PDF icon to external links. returns true if file extension is one of the recognized extensions, else false ]=] local function is_pdf (url) return url:match ('%.pdf$') or url:match ('%.PDF$') or url:match ('%.pdf[%?#]') or url:match ('%.PDF[%?#]') or url:match ('%.PDF&#035') or url:match ('%.pdf&#035'); end --[[--------------------------< S T Y L E _ F O R M A T >----------------------- Applies CSS style to |format=, |chapter-format=, etc. Also emits an error message if the format parameter does not have a matching URL parameter. If the format parameter is not set and the URL contains a file extension that is recognized as a PDF document by MediaWiki's commons.css, this code will set the format parameter to (PDF) with the appropriate styling. ]] local function style_format (format, url, fmt_param, url_param) if utilities.is_set (format) then format = utilities.wrap_style ('format', format); -- add leading space, parentheses, resize if not utilities.is_set (url) then utilities.set_message ('err_format_missing_url', {fmt_param, url_param}); -- add an error message end elseif is_pdf (url) then -- format is not set so if URL is a PDF file then format = utilities.wrap_style ('format', 'PDF'); -- set format to PDF else format = ''; -- empty string for concatenation end return format; end --[[---------------------< G E T _ D I S P L A Y _ N A M E S >------------------ Returns a number that defines the number of names displayed for author and editor name lists and a Boolean flag to indicate when et al. should be appended to the name list. When the value assigned to |display-xxxxors= is a number greater than or equal to zero, return the number and the previous state of the 'etal' flag (false by default but may have been set to true if the name list contains some variant of the text 'et al.'). When the value assigned to |display-xxxxors= is the keyword 'etal', return a number that is one greater than the number of authors in the list and set the 'etal' flag true. This will cause the list_people() to display all of the names in the name list followed by 'et al.' In all other cases, returns nil and the previous state of the 'etal' flag. inputs: max: A['DisplayAuthors'] or A['DisplayEditors'], etc; a number or some flavor of etal count: #a or #e list_name: 'authors' or 'editors' etal: author_etal or editor_etal This function sets an error message when |display-xxxxors= value greater than or equal to number of names but not when <max> comes from {{cs1 config}} global settings. When using global settings, <param> is set to the keyword 'cs1 config' which is used to supress the normal error. Error is suppressed because it is to be expected that some citations in an article will have the same or fewer names that the limit specified in {{cs1 config}}. ]] local function get_display_names (max, count, list_name, etal, param) if utilities.is_set (max) then if 'etal' == max:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings max = count + 1; -- number of authors + 1 so display all author name plus et al. etal = true; -- overrides value set by extract_names() elseif max:match ('^%d+$') then -- if is a string of numbers max = tonumber (max); -- make it a number if (max >= count) and ('cs1 config' ~= param) then -- error when local |display-xxxxors= value greater than or equal to number of names; not an error when using global setting utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; end else -- not a valid keyword or number utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; -- unset; as if |display-xxxxors= had not been set end end return max, etal; end --[[----------< E X T R A _ T E X T _ I N _ P A G E _ C H E C K >--------------- Adds error if |page=, |pages=, |quote-page=, |quote-pages= has what appears to be some form of p. or pp. abbreviation in the first characters of the parameter content. check page for extraneous p, p., pp, pp., pg, pg. at start of parameter value: good pattern: '^P[^%.P%l]' matches when page begins PX or P# but not Px where x and X are letters and # is a digit bad pattern: '^[Pp][PpGg]' matches when page begins pp, pP, Pp, PP, pg, pG, Pg, PG ]] local function extra_text_in_page_check (val, name) if not val:match (cfg.vol_iss_pg_patterns.good_ppattern) then for _, pattern in ipairs (cfg.vol_iss_pg_patterns.bad_ppatterns) do -- spin through the selected sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message ('err_extra_text_pages', name); -- add error message return; -- and done end end end end --[[--------------------------< E X T R A _ T E X T _ I N _ V O L _ I S S _ C H E C K >------------------------ Adds error if |volume= or |issue= has what appears to be some form of redundant 'type' indicator. Applies to both; this function looks for issue text in both |issue= and |volume= and looks for volume-like text in |voluem= and |issue=. For |volume=: 'V.', or 'Vol.' (with or without the dot) abbreviations or 'Volume' in the first characters of the parameter content (all case insensitive). 'V' and 'v' (without the dot) are presumed to be roman numerals so are allowed. For |issue=: 'No.', 'I.', 'Iss.' (with or without the dot) abbreviations, or 'Issue' in the first characters of the parameter content (all case insensitive); numero styling: 'n°' with degree sign U+00B0, and № precomposed numero sign U+2116. Single character values ('v', 'i', 'n') allowed when not followed by separator character ('.', ':', '=', or whitespace character) – param values are trimmed of whitespace by MediaWiki before delivered to the module. <val> is |volume= or |issue= parameter value <name> is |volume= or |issue= parameter name for error message <selector> is 'v' for |volume=, 'i' for |issue= sets error message on failure; returns nothing ]] local function extra_text_in_vol_iss_check (val, name, selector) if not utilities.is_set (val) then return; end local handler = 'v' == selector and 'err_extra_text_volume' or 'err_extra_text_issue'; local accept_val; val, accept_val = utilities.has_accept_as_written (val); --if accept_val then -- if uncomment this, |volume=((vol. 1)) suppresses error -- return; --end --val = mw.text.unstripNoWiki (val); -- if uncomment this, |volume=<nowiki>vol. 1</nowiki> shows error val = val:lower(); -- force parameter value to lower case for _, pattern in ipairs (cfg.vol_iss_pg_patterns.vi_patterns_t) do -- spin through the sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message (handler, name); -- add error message return; -- and done end end end --[=[-------------------------< G E T _ V _ N A M E _ T A B L E >---------------------------------------------- split apart a |vauthors= or |veditors= parameter. This function allows for corporate names, wrapped in doubled parentheses to also have commas; in the old version of the code, the doubled parentheses were included in the rendered citation and in the metadata. Individual author names may be wikilinked |vauthors=Jones AB, [[E. B. White|White EB]], ((Black, Brown, and Co.)) ]=] local function get_v_name_table (vparam, output_table, output_link_table) local _, accept = utilities.has_accept_as_written (vparam); if accept then utilities.add_prop_cat ('vanc-accept'); -- add properties category end local name_table = mw.text.split(vparam, "%s*,%s*"); -- names are separated by commas local wl_type, label, link; -- wl_type not used here; just a placeholder local i = 1; while name_table[i] do if name_table[i]:match ('^%(%(.*[^%)][^%)]$') then -- first segment of corporate with one or more commas; this segment has the opening doubled parentheses local name = name_table[i]; i = i + 1; -- bump indexer to next segment while name_table[i] do name = name .. ', ' .. name_table[i]; -- concatenate with previous segments if name_table[i]:match ('^.*%)%)$') then -- if this table member has the closing doubled parentheses break; -- and done reassembling so end i = i + 1; -- bump indexer end table.insert (output_table, name); -- and add corporate name to the output table table.insert (output_link_table, ''); -- no wikilink else wl_type, label, link = utilities.is_wikilink (name_table[i]); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] table.insert (output_table, label); -- add this name if 1 == wl_type then table.insert (output_link_table, label); -- simple wikilink [[D]] else table.insert (output_link_table, link); -- no wikilink or [[L|D]]; add this link if there is one, else empty string end end i = i + 1; end return output_table; end --[[--------------------------< P A R S E _ V A U T H O R S _ V E D I T O R S >-------------------------------- This function extracts author / editor names from |vauthors= or |veditors= and finds matching |xxxxor-maskn= and |xxxxor-linkn= in args. It then returns a table of assembled names just as extract_names() does. Author / editor names in |vauthors= or |veditors= must be in Vancouver system style. Corporate or institutional names may sometimes be required and because such names will often fail the is_good_vanc_name() and other format compliance tests, are wrapped in doubled parentheses ((corporate name)) to suppress the format tests. Supports generational suffixes Jr, 2nd, 3rd, 4th–6th. This function sets the Vancouver error when a required comma is missing and when there is a space between an author's initials. ]] local function parse_vauthors_veditors (args, vparam, list_name) local names = {}; -- table of names assembled from |vauthors=, |author-maskn=, |author-linkn= local v_name_table = {}; local v_link_table = {}; -- when name is wikilinked, targets go in this table local etal = false; -- return value set to true when we find some form of et al. vauthors parameter local last, first, link, mask, suffix; local corporate = false; vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period) v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); -- names are separated by commas for i, v_name in ipairs(v_name_table) do first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor local accept_name; v_name, accept_name = utilities.has_accept_as_written (v_name); -- remove accept-this-as-written markup when it wraps all of <v_name> if accept_name then last = v_name; corporate = true; -- flag used in list_people() elseif string.find(v_name, "%s") then if v_name:find('[;%.]') then -- look for commonly occurring punctuation characters; add_vanc_error (cfg.err_msg_supl.punctuation, i); end local lastfirstTable = {} lastfirstTable = mw.text.split(v_name, "%s+") first = table.remove(lastfirstTable); -- removes and returns value of last element in table which should be initials or generational suffix if not mw.ustring.match (first, '^%u+$') then -- mw.ustring here so that later we will catch non-Latin characters suffix = first; -- not initials so assume that whatever we got is a generational suffix first = table.remove(lastfirstTable); -- get what should be the initials from the table end last = table.concat(lastfirstTable, ' ') -- returns a string that is the concatenation of all other names that are not initials and generational suffix if not utilities.is_set (last) then first = ''; -- unset last = v_name; -- last empty because something wrong with first add_vanc_error (cfg.err_msg_supl.name, i); end if mw.ustring.match (last, '%a+%s+%u+%s+%a+') then add_vanc_error (cfg.err_msg_supl['missing comma'], i); -- matches last II last; the case when a comma is missing end if mw.ustring.match (v_name, ' %u %u$') then -- this test is in the wrong place TODO: move or replace with a more appropriate test add_vanc_error (cfg.err_msg_supl.initials, i); -- matches a space between two initials end else last = v_name; -- last name or single corporate name? Doesn't support multiword corporate names? do we need this? end if utilities.is_set (first) then if not mw.ustring.match (first, "^%u?%u$") then -- first shall contain one or two upper-case letters, nothing else add_vanc_error (cfg.err_msg_supl.initials, i); -- too many initials; mixed case initials (which may be ok Romanization); hyphenated initials end is_good_vanc_name (last, first, suffix, i); -- check first and last before restoring the suffix which may have a non-Latin digit if utilities.is_set (suffix) then first = first .. ' ' .. suffix; -- if there was a suffix concatenate with the initials suffix = ''; -- unset so we don't add this suffix to all subsequent names end else if not corporate then is_good_vanc_name (last, '', nil, i); end end link = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ) or v_link_table[i]; mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); names[i] = {last = last, first = first, link = link, mask = mask, corporate = corporate}; -- add this assembled name to our names list end return names, etal; -- all done, return our list of names end --[[--------------------------< S E L E C T _ A U T H O R _ E D I T O R _ S O U R C E >------------------------ Select one of |authors=, |authorn= / |lastn / firstn=, or |vauthors= as the source of the author name list or select one of |editorn= / editor-lastn= / |editor-firstn= or |veditors= as the source of the editor name list. Only one of these appropriate three will be used. The hierarchy is: |authorn= (and aliases) highest and |authors= lowest; |editorn= (and aliases) highest and |veditors= lowest (support for |editors= withdrawn) When looking for |authorn= / |editorn= parameters, test |xxxxor1= and |xxxxor2= (and all of their aliases); stops after the second test which mimicks the test used in extract_names() when looking for a hole in the author name list. There may be a better way to do this, I just haven't discovered what that way is. Emits an error message when more than one xxxxor name source is provided. In this function, vxxxxors = vauthors or veditors; xxxxors = authors as appropriate. ]] local function select_author_editor_source (vxxxxors, xxxxors, args, list_name) local lastfirst = false; if utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 1 ) or -- do this twice in case we have a |first1= without a |last1=; this ... utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 1 ) or -- ... also catches the case where |first= is used with |vauthors= utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 2 ) or utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 2 ) then lastfirst = true; end if (utilities.is_set (vxxxxors) and true == lastfirst) or -- these are the three error conditions (utilities.is_set (vxxxxors) and utilities.is_set (xxxxors)) or (true == lastfirst and utilities.is_set (xxxxors)) then utilities.set_message ('err_redundant_parameters', utilities.substitute (cfg.special_case_translation.name_list_params, ('AuthorList' == list_name) and cfg.special_case_translation.author or cfg.special_case_translation.editor)); -- add error message end if true == lastfirst then return 1 end; -- return a number indicating which author name source to use if utilities.is_set (vxxxxors) then return 2 end; if utilities.is_set (xxxxors) then return 3 end; return 1; -- no authors so return 1; this allows missing author name test to run in case there is a first without last end --[[--------------------------< I S _ V A L I D _ P A R A M E T E R _ V A L U E >------------------------------ This function is used to validate a parameter's assigned value for those parameters that have only a limited number of allowable values (yes, y, true, live, dead, etc.). When the parameter value has not been assigned a value (missing or empty in the source template) the function returns the value specified by ret_val. If the parameter value is one of the list of allowed values returns the translated value; else, emits an error message and returns the value specified by ret_val. TODO: explain <invert> ]] local function is_valid_parameter_value (value, name, possible, ret_val, invert) if not utilities.is_set (value) then return ret_val; -- an empty parameter is ok end if (not invert and utilities.in_array (value, possible)) then -- normal; <value> is in <possible> table return cfg.keywords_xlate[value]; -- return translation of parameter keyword elseif invert and not utilities.in_array (value, possible) then -- invert; <value> is not in <possible> table return value; -- return <value> as it is else utilities.set_message ('err_invalid_param_val', {name, value}); -- not an allowed value so add error message return ret_val; end end --[[--------------------------< T E R M I N A T E _ N A M E _ L I S T >---------------------------------------- This function terminates a name list (author, contributor, editor) with a separator character (sepc) and a space when the last character is not a sepc character or when the last three characters are not sepc followed by two closing square brackets (close of a wikilink). When either of these is true, the name_list is terminated with a single space character. ]] local function terminate_name_list (name_list, sepc) if (string.sub (name_list, -3, -1) == sepc .. '. ') then -- if already properly terminated return name_list; -- just return the name list elseif (string.sub (name_list, -1, -1) == sepc) or (string.sub (name_list, -3, -1) == sepc .. ']]') then -- if last name in list ends with sepc char return name_list .. " "; -- don't add another else return name_list .. sepc .. ' '; -- otherwise terminate the name list end end --[[-------------------------< F O R M A T _ V O L U M E _ I S S U E >----------------------------------------- returns the concatenation of the formatted volume and issue (or journal article number) parameters as a single string; or formatted volume or formatted issue, or an empty string if neither are set. ]] local function format_volume_issue (volume, issue, article, cite_class, origin, sepc, lower) if not utilities.is_set (volume) and not utilities.is_set (issue) and not utilities.is_set (article) then return ''; end -- same condition as in format_pages_sheets() local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); local is_numeric_vol = volume and (volume:match ('^[MDCLXVI]+$') or volume:match ('^%d+$')); -- is only uppercase roman numerals or only digits? local is_long_vol = volume and (4 < mw.ustring.len(volume)); -- is |volume= value longer than 4 characters? if volume and (not is_numeric_vol and is_long_vol) then -- when not all digits or Roman numerals, is |volume= longer than 4 characters? utilities.add_prop_cat ('long-vol'); -- yes, add properties cat end if is_journal then -- journal-style formatting local vol = ''; if utilities.is_set (volume) then if is_numeric_vol then -- |volume= value all digits or all uppercase Roman numerals? vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, volume}); -- render in bold face elseif is_long_vol then -- not all digits or Roman numerals; longer than 4 characters? vol = utilities.substitute (cfg.messages['j-vol'], {sepc, utilities.hyphen_to_dash (volume)}); -- not bold else -- four or fewer characters vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, utilities.hyphen_to_dash (volume)}); -- bold end end vol = vol .. (utilities.is_set (issue) and utilities.substitute (cfg.messages['j-issue'], issue) or '') vol = vol .. (utilities.is_set (article) and utilities.substitute (cfg.messages['j-article-num'], article) or '') return vol; end if 'podcast' == cite_class and utilities.is_set (issue) then return wrap_msg ('issue', {sepc, issue}, lower); end if 'conference' == cite_class and utilities.is_set (article) then -- |article-number= supported only in journal and conference cites if utilities.is_set (volume) and utilities.is_set (article) then -- both volume and article number return wrap_msg ('vol-art', {sepc, utilities.hyphen_to_dash (volume), article}, lower); elseif utilities.is_set (article) then -- article number alone; when volume alone, handled below return wrap_msg ('art', {sepc, article}, lower); end end -- all other types of citation if utilities.is_set (volume) and utilities.is_set (issue) then return wrap_msg ('vol-no', {sepc, utilities.hyphen_to_dash (volume), issue}, lower); elseif utilities.is_set (volume) then return wrap_msg ('vol', {sepc, utilities.hyphen_to_dash (volume)}, lower); else return wrap_msg ('issue', {sepc, issue}, lower); end end --[[-------------------------< F O R M A T _ P A G E S _ S H E E T S >----------------------------------------- adds static text to one of |page(s)= or |sheet(s)= values and returns it with all of the others set to empty strings. The return order is: page, pages, sheet, sheets Singular has priority over plural when both are provided. ]] local function format_pages_sheets (page, pages, sheet, sheets, cite_class, origin, sepc, nopp, lower) if 'map' == cite_class then -- only cite map supports sheet(s) as in-source locators if utilities.is_set (sheet) then if 'journal' == origin then return '', '', wrap_msg ('j-sheet', sheet, lower), ''; else return '', '', wrap_msg ('sheet', {sepc, sheet}, lower), ''; end elseif utilities.is_set (sheets) then if 'journal' == origin then return '', '', '', wrap_msg ('j-sheets', sheets, lower); else return '', '', '', wrap_msg ('sheets', {sepc, sheets}, lower); end end end local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); if utilities.is_set (page) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], page), '', '', ''; elseif not nopp then return utilities.substitute (cfg.messages['p-prefix'], {sepc, page}), '', '', ''; else return utilities.substitute (cfg.messages['nopp'], {sepc, page}), '', '', ''; end elseif utilities.is_set (pages) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], pages), '', '', ''; elseif tonumber(pages) ~= nil and not nopp then -- if pages is only digits, assume a single page number return '', utilities.substitute (cfg.messages['p-prefix'], {sepc, pages}), '', ''; elseif not nopp then return '', utilities.substitute (cfg.messages['pp-prefix'], {sepc, pages}), '', ''; else return '', utilities.substitute (cfg.messages['nopp'], {sepc, pages}), '', ''; end end return '', '', '', ''; -- return empty strings end --[[--------------------------< I N S O U R C E _ L O C _ G E T >---------------------------------------------- returns one of the in-source locators: page, pages, or at. If any of these are interwiki links to Wikisource, returns the label portion of the interwiki-link as plain text for use in COinS. This COinS thing is done because here we convert an interwiki-link to an external link and add an icon span around that; get_coins_pages() doesn't know about the span. TODO: should it? TODO: add support for sheet and sheets?; streamline; TODO: make it so that this function returns only one of the three as the single in-source (the return value assigned to a new name)? ]] local function insource_loc_get (page, page_orig, pages, pages_orig, at) local ws_url, ws_label, coins_pages, L; -- for Wikisource interwiki-links; TODO: this corrupts page metadata (span remains in place after cleanup; fix there?) if utilities.is_set (page) then if utilities.is_set (pages) or utilities.is_set (at) then pages = ''; -- unset the others at = ''; end extra_text_in_page_check (page, page_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (page); -- make ws URL from |page= interwiki link; link portion L becomes tooltip label if ws_url then page = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in page'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? page = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, page}); coins_pages = ws_label; end elseif utilities.is_set (pages) then if utilities.is_set (at) then at = ''; -- unset end extra_text_in_page_check (pages, pages_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (pages); -- make ws URL from |pages= interwiki link; link portion L becomes tooltip label if ws_url then pages = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in pages'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? pages = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, pages}); coins_pages = ws_label; end elseif utilities.is_set (at) then ws_url, ws_label, L = wikisource_url_make (at); -- make ws URL from |at= interwiki link; link portion L becomes tooltip label if ws_url then at = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in at'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? at = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, at}); coins_pages = ws_label; end end return page, pages, at, coins_pages; end --[[--------------------------< I S _ U N I Q U E _ A R C H I V E _ U R L >------------------------------------ add error message when |archive-url= value is same as |url= or chapter-url= (or alias...) value ]] local function is_unique_archive_url (archive, url, c_url, source, date) if utilities.is_set (archive) then if archive == url or archive == c_url then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); -- add error message return '', ''; -- unset |archive-url= and |archive-date= because same as |url= or |chapter-url= end end return archive, date; end --[=[-------------------------< A R C H I V E _ U R L _ C H E C K >-------------------------------------------- Check archive.org URLs to make sure they at least look like they are pointing at valid archives and not to the save snapshot URL or to calendar pages. When the archive URL is 'https://web.archive.org/save/' (or http://...) archive.org saves a snapshot of the target page in the URL. That is something that Wikipedia should not allow unwitting readers to do. When the archive.org URL does not have a complete timestamp, archive.org chooses a snapshot according to its own algorithm or provides a calendar 'search' result. [[WP:ELNO]] discourages links to search results. This function looks at the value assigned to |archive-url= and returns empty strings for |archive-url= and |archive-date= and an error message when: |archive-url= holds an archive.org save command URL |archive-url= is an archive.org URL that does not have a complete timestamp (YYYYMMDDhhmmss 14 digits) in the correct place otherwise returns |archive-url= and |archive-date= There are two mostly compatible archive.org URLs: //web.archive.org/<timestamp>... -- the old form //web.archive.org/web/<timestamp>... -- the new form The old form does not support or map to the new form when it contains a display flag. There are four identified flags ('id_', 'js_', 'cs_', 'im_') but since archive.org ignores others following the same form (two letters and an underscore) we don't check for these specific flags but we do check the form. This function supports a preview mode. When the article is rendered in preview mode, this function may return a modified archive URL: for save command errors, return undated wildcard (/*/) for timestamp errors when the timestamp has a wildcard, return the URL unmodified for timestamp errors when the timestamp does not have a wildcard, return with timestamp limited to six digits plus wildcard (/yyyymm*/) A secondary function is to return an archive-url timestamp from those urls that have them (archive.org and archive.today). The timestamp is used by validation.archive_date_check() to see if the value in |archive-date= matches the timestamp in the archive url. ]=] local function archive_url_check (url, date) local err_msg = ''; -- start with the error message empty local path, timestamp, flag; -- portions of the archive.org URL local function is_ts_date_valid (timestamp, origin_date) -- local function to validate archive url taimestamp date; time ignored local y, m, d = timestamp:match ('(%d%d%d%d)(%d%d)(%d%d)'); -- split into parts if y and validation.is_valid_date (y, m, d) and (tonumber (y) >= origin_date) then -- <origin_date> is 1996 for archive.org; 2012 for archive.today return true; end end timestamp = url:match ('//archive.today/(%d%d%d%d%d%d%d%d%d%d%d%d%d%d)/') or -- get timestamp from archive.today urls url:match ('//archive.today/(%d%d%d%d%.%d%d%.%d%d%-%d%d%d%d%d%d)/'); -- this timestamp needs cleanup if timestamp then -- if this is an archive.today url ... timestamp = timestamp:gsub ('[%.%-]', ''); -- strip dots and dashes if not is_ts_date_valid (timestamp, 2012) then -- is ymd portion of timestamp a valid date? utilities.set_message ('err_archive_url', {cfg.err_msg_supl.timestamp}); -- no; set error message; if is_preview_mode then return url, date; -- preview mode so return ArchiveURL, ArchiveDate; suppress timestamp because invalid else return '', ''; -- return empty strings for ArchiveURL and ArchiveDate end else return url, date, timestamp; -- return ArchiveURL, ArchiveDate, and timestamp (dots and dashes removed) from |archive-url=, and done end end -- here for archive.org urls if (not url:match('//web%.archive%.org/')) and (not url:match('//liveweb%.archive%.org/')) then -- also deprecated liveweb Wayback machine URL return url, date; -- not an archive.org archive, return ArchiveURL and ArchiveDate end if url:match('//web%.archive%.org/save/') then -- if a save command URL, we don't want to allow saving of the target page err_msg = cfg.err_msg_supl.save; url = url:gsub ('(//web%.archive%.org)/save/', '%1/*/', 1); -- for preview mode: modify ArchiveURL elseif url:match('//liveweb%.archive%.org/') then err_msg = cfg.err_msg_supl.liveweb; else path, timestamp, flag = url:match('//web%.archive%.org/([^%d]*)(%d+)([^/]*)/'); -- split out some of the URL parts for evaluation if not path then -- malformed in some way; pattern did not match err_msg = cfg.err_msg_supl.timestamp; elseif 14 ~= timestamp:len() then -- path and flag optional, must have 14-digit timestamp here err_msg = cfg.err_msg_supl.timestamp; if '*' ~= flag then local replacement = timestamp:match ('^%d%d%d%d%d%d') or timestamp:match ('^%d%d%d%d'); -- get the first 6 (YYYYMM) or first 4 digits (YYYY) if replacement then -- nil if there aren't at least 4 digits (year) replacement = replacement .. string.rep ('0', 14 - replacement:len()); -- year or yearmo (4 or 6 digits) zero-fill to make 14-digit timestamp url=url:gsub ('(//web%.archive%.org/[^%d]*)%d[^/]*', '%1' .. replacement .. '*', 1) -- for preview, modify ts to 14 digits plus splat for calendar display end end elseif not is_ts_date_valid (timestamp, 1996) then -- is ymd portion of timestamp a valid date? err_msg = cfg.err_msg_supl.timestamp; timestamp = nil; -- unset because invalid elseif utilities.is_set (path) and 'web/' ~= path then -- older archive URLs do not have the extra 'web/' path element err_msg = cfg.err_msg_supl.path; elseif utilities.is_set (flag) and not utilities.is_set (path) then -- flag not allowed with the old form URL (without the 'web/' path element) err_msg = cfg.err_msg_supl.flag; elseif utilities.is_set (flag) and not flag:match ('%a%a_') then -- flag if present must be two alpha characters and underscore (requires 'web/' path element) err_msg = cfg.err_msg_supl.flag; else return url, date, timestamp; -- return ArchiveURL, ArchiveDate, and timestamp from |archive-url= end end -- if here, something not right so utilities.set_message ('err_archive_url', {err_msg}); -- add error message and if is_preview_mode then return url, date, timestamp; -- preview mode so return ArchiveURL, ArchiveDate, and timestamp from |archive-url= else return '', ''; -- return empty strings for ArchiveURL and ArchiveDate end end --[[--------------------------< P L A C E _ C H E C K >-------------------------------------------------------- check |place=, |publication-place=, |location= to see if these params include digits. This function added because many editors misuse location to specify the in-source location (|page(s)= and |at= are supposed to do that) returns the original parameter value without modification; added maint cat when parameter value contains digits ]] local function place_check (param_val) if not utilities.is_set (param_val) then -- parameter empty or omitted return param_val; -- return that empty state end if mw.ustring.find (param_val, '%d') then -- not empty, are there digits in the parameter value utilities.set_message ('maint_location'); -- yep, add maint cat end return param_val; -- and done end --[[--------------------------< I S _ A R C H I V E D _ C O P Y >---------------------------------------------- compares |title= to 'Archived copy' (placeholder added by bots that can't find proper title); if matches, return true; nil else ]] local function is_archived_copy (title) title = mw.ustring.lower(title); -- switch title to lower case if title:find (cfg.special_case_translation.archived_copy.en) then -- if title is 'Archived copy' return true; elseif cfg.special_case_translation.archived_copy['local'] then if mw.ustring.find (title, cfg.special_case_translation.archived_copy['local']) then -- mw.ustring() because might not be Latin script return true; end end end --[[--------------------------< D I S P L A Y _ N A M E S _ S E L E C T >-------------------------------------- for any of the |display-authors=, |display-editors=, etc parameters, select either the local or global setting. When both are present, look at <local_display_names> value. When the value is some sort of 'et al.'string, special handling is required. When {{cs1 config}} has |display-<namelist>= AND this template has |display-<namelist>=etal AND: the number of names specified by <number_of_names> is: greater than the number specified in the global |display-<namelist>= parameter (<global_display_names>) use global |display-<namelist>= parameter value set overridden maint category less than or equal to the number specified in the global |display-<namelist>= parameter use local |display-<namelist>= parameter value The purpose of this function is to prevent categorizing a template that has fewer names than the global setting to keep the etal annotation specified by <local_display_names>. ]] local function display_names_select (global_display_names, local_display_names, param_name, number_of_names, test) if global_display_names and utilities.is_set (local_display_names) then -- when both if 'etal' == local_display_names:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings number_of_names = tonumber (number_of_names); -- convert these to numbers for comparison local global_display_names_num = tonumber (global_display_names); -- <global_display_names> not set when parameter value is not digits if number_of_names > global_display_names_num then -- template has more names than global config allows to be displayed? utilities.set_message ('maint_overridden_setting'); -- set a maint message because global is overriding local |display-<namelist>=etal return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local because fewer names so let <local_display_names> control end end -- here when <global_display_names> and <local_display_names> both numbers; <global_display_names> controls utilities.set_message ('maint_overridden_setting'); -- set a maint message return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) end -- here when only one of <global_display_names> or <local_display_names> set if global_display_names then return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local end end --[[--------------------------< M O D E _ S E T >-------------------------------------------------------------- fetch global mode setting from {{cs1 config}} (if present) or from |mode= (if present); global setting overrides local |mode= parameter value. When both are present, emit maintenance message ]] local function mode_set (Mode, Mode_origin) local mode; if cfg.global_cs1_config_t['Mode'] then -- global setting in {{cs1 config}}; nil when empty or assigned value invalid mode = is_valid_parameter_value (cfg.global_cs1_config_t['Mode'], 'cs1 config: mode', cfg.keywords_lists['mode'], ''); -- error messaging 'param' here is a hoax else mode = is_valid_parameter_value (Mode, Mode_origin, cfg.keywords_lists['mode'], ''); end if cfg.global_cs1_config_t['Mode'] and utilities.is_set (Mode) then -- when template has |mode=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end return mode; end --[[--------------------------< Q U O T E _ M A K E >---------------------------------------------------------- create quotation from |quote=, |trans-quote=, and/or script-quote= with or without |quote-page= or |quote-pages= when any of those three quote parameters are set, this function unsets <PostScript>. When none of those parameters are set, |quote-page= and |quote-pages= are unset to nil so that they are not included in the template's metadata ]] local function quote_make (quote, trans_quote, script_quote, quote_page, quote_pages, nopp, sepc, postscript) if utilities.is_set (quote) or utilities.is_set (trans_quote) or utilities.is_set (script_quote) then if utilities.is_set (quote) then if quote:sub(1, 1) == '"' and quote:sub(-1, -1) == '"' then -- if first and last characters of quote are quote marks quote = quote:sub(2, -2); -- strip them off end end quote = kern_quotes (quote); -- kern if needed quote = utilities.wrap_style ('quoted-text', quote ); -- wrap in <q>...</q> tags if utilities.is_set (script_quote) then quote = script_concatenate (quote, script_quote, 'script-quote'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after quote is wrapped end if utilities.is_set (trans_quote) then if trans_quote:sub(1, 1) == '"' and trans_quote:sub(-1, -1) == '"' then -- if first and last characters of |trans-quote are quote marks trans_quote = trans_quote:sub(2, -2); -- strip them off end quote = quote .. " " .. utilities.wrap_style ('trans-quoted-title', trans_quote ); end if utilities.is_set (quote_page) or utilities.is_set (quote_pages) then -- add page prefix local quote_prefix = ''; if utilities.is_set (quote_page) then extra_text_in_page_check (quote_page, 'quote-page'); -- add to maint cat if |quote-page= value begins with what looks like p., pp., etc. if not nopp then quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_page}), '', '', ''; else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_page}), '', '', ''; end elseif utilities.is_set (quote_pages) then extra_text_in_page_check (quote_pages, 'quote-pages'); -- add to maint cat if |quote-pages= value begins with what looks like p., pp., etc. if tonumber(quote_pages) ~= nil and not nopp then -- if only digits, assume single page quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_pages}), '', ''; elseif not nopp then quote_prefix = utilities.substitute (cfg.messages['pp-prefix'], {sepc, quote_pages}), '', ''; else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_pages}), '', ''; end end quote = quote_prefix .. ": " .. quote; else quote = sepc .. " " .. quote; end postscript = ""; -- cs1|2 does not supply terminal punctuation when |quote= is set elseif utilities.is_set (quote_page) or utilities.is_set (quote_pages) then quote_page = nil; -- unset; these require |quote=; TODO: error message? quote_pages = nil; end return quote, quote_page, quote_pages, postscript; end --[[--------------------------< C H E C K _ P U B L I S H E R _ N A M E >-------------------------------------- look for variations of '<text>: <text>' that might be '<location>: <publisher>' in |publisher= parameter value. when found, emit a maintenance message; return nil else <publisher> is the value assigned to |publisher= or |institution= ]] local function check_publisher_name (publisher) local patterns_t = { '^[%w%s]+%s*:%s*[%w%s]+$', -- plain text <location>: <publisher> '^%[+[%w%s:|]+%]+%s*:%s*[%w%s]+$', -- partially wikilinked [[<location>]]: <publisher> '^[%w%s]+%s*:%s*%[+[%w%s:|]+%]+$', -- partially wikilinked <location>: [[<publisher>]] '^%[+[%w%s:|]+%]+%s*:%s*%[+[%w%s:|]+%]+$', -- wikilinked [[<location>]]: [[<publisher>]] } for _, pattern in ipairs (patterns_t) do -- spin through the patterns_t sequence if mw.ustring.match (publisher, pattern) then -- does this pattern match? utilities.set_message ('maint_publisher_location'); -- set a maint message return; -- and done end end end --[[--------------------------< I S _ P A G E _ A R T _ N U M >------------------------------------------------ compare the trailing (rightmost) characters of the |doi= value against the whole value assigned to |page(s)=. return boolean true when: |page(s)= has exactly 8 digits and a dot between the fourth and fifth digits matches the trailing 9 characters of the |doi= value: |page=12345678 → |page=1234.5678 matches |doi=10.xxxx/yyyy1234.5678 |page(s)= is 5 or more characters and matches |doi= values's trailing characters |page(s)= begins with a lowercase 'e' and |page(s)= without the 'e' matches |doi= values's trailing characters: |page=e12345 → |page=12345 matches |doi=10.xxxx/yyyy12345 |page(s)= begins with a uppercase 'CD' followed by (typically) six digits matches |doi= values that ends with 'CDxxxxxx.pubx' (where 'x' is any single digit) return nil when |page(s)= values: are ranges separated by underscore, hyphen, emdash, endash, figure dash, or minus character are comma- or semicolon-separated lists of pages have external urls (has text 'http') are digit-only values less than 10000 do not match |doi= values's trailing characters ]] local function is_page_art_num (page, doi) if not (utilities.is_set (page) and utilities.is_set (doi)) then -- both required return; -- abandon; nothing to do end if page:match ('[,;_−–—‒%-]') then -- when |page(s)= might be a page range or a separated list of pages return; -- abandon end page = page:lower(); -- because doi names are case insensitive doi = doi:lower(); -- force these to lowercase for testing if page:match ('http') then -- when |page(s)= appears to hold a url return; -- abandon end if tonumber (page) then -- is |page(s)= digits only if 10000 > tonumber (page) then -- when |page(s)= less than 10000 return; -- abandon end if doi:match (page .. '$') then -- digits only page number match the last digits in |doi=? return true; end if 8 == page:len() then -- special case when |page(s)= is exactly 8 digits local dot_page = page:gsub ('(%d%d%d%d)(%d%d%d%d)', '%1.%2'); -- make a |page=xxxx.yyyy version commonly used in |doi= if doi:match (dot_page .. '$') then -- 8-digit dotted page number match the last characters in |doi=? return true; end end else -- here when |page(s)= is alpha-numeric if 4 < page:len() then -- when |page(s)= is five or more characters if doi:match (page .. '$') then -- alpha-numeric page match the last characters in |doi=? return true; end local epage = page:match ('^e([%w]+)$'); -- if first character of |page= is 'e', remove it if epage and doi:match (epage .. '$') then -- page number match the last characters in |doi=? return true; end local cdpage = page:match ('^cd%d+$'); -- if first characters of |page= are 'CD' and last characters are digits (typically 6 digits) if cdpage and doi:match (cdpage .. '%.pub%d$') then -- page number matches doi 'CDxxxxxx.pubx' where 'x' is a digit return true; end end end end --[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------ This is the main function doing the majority of the citation formatting. ]] local function citation0( config, args ) --[[ Load Input Parameters The argument_wrapper facilitates the mapping of multiple aliases to single internal variable. ]] local A = argument_wrapper ( args ); local i -- Pick out the relevant fields from the arguments. Different citation templates -- define different field names for the same underlying things. local author_etal; local a = {}; -- authors list from |lastn= / |firstn= pairs or |vauthors= local Authors; local NameListStyle; if cfg.global_cs1_config_t['NameListStyle'] then -- global setting in {{cs1 config}} overrides local |name-list-style= parameter value; nil when empty or assigned value invalid NameListStyle = is_valid_parameter_value (cfg.global_cs1_config_t['NameListStyle'], 'cs1 config: name-list-style', cfg.keywords_lists['name-list-style'], ''); -- error messaging 'param' here is a hoax else NameListStyle = is_valid_parameter_value (A['NameListStyle'], A:ORIGIN('NameListStyle'), cfg.keywords_lists['name-list-style'], ''); end if cfg.global_cs1_config_t['NameListStyle'] and utilities.is_set (A['NameListStyle']) then -- when template has |name-list-style=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end local Collaboration = A['Collaboration']; do -- to limit scope of selected local selected = select_author_editor_source (A['Vauthors'], A['Authors'], args, 'AuthorList'); if 1 == selected then a, author_etal = extract_names (args, 'AuthorList'); -- fetch author list from |authorn= / |lastn= / |firstn=, |author-linkn=, and |author-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be a, author_etal = parse_vauthors_veditors (args, A['Vauthors'], 'AuthorList'); -- fetch author list from |vauthors=, |author-linkn=, and |author-maskn= elseif 3 == selected then Authors = A['Authors']; -- use content of |people= or |credits=; |authors= is deprecated; TODO: constrain |people= and |credits= to cite av media, episode, serial? end if utilities.is_set (Collaboration) then author_etal = true; -- so that |display-authors=etal not required end end local editor_etal; local e = {}; -- editors list from |editor-lastn= / |editor-firstn= pairs or |veditors= do -- to limit scope of selected local selected = select_author_editor_source (A['Veditors'], nil, args, 'EditorList'); -- support for |editors= withdrawn if 1 == selected then e, editor_etal = extract_names (args, 'EditorList'); -- fetch editor list from |editorn= / |editor-lastn= / |editor-firstn=, |editor-linkn=, and |editor-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be e, editor_etal = parse_vauthors_veditors (args, args.veditors, 'EditorList'); -- fetch editor list from |veditors=, |editor-linkn=, and |editor-maskn= end end local Chapter = A['Chapter']; -- done here so that we have access to |contribution= from |chapter= aliases local Chapter_origin = A:ORIGIN ('Chapter'); local Contribution; -- because contribution is required for contributor(s) if 'contribution' == Chapter_origin then Contribution = Chapter; -- get the name of the contribution end local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (A['Periodical']) then -- |contributor= and |contribution= only supported in book cites c = extract_names (args, 'ContributorList'); -- fetch contributor list from |contributorn= / |contributor-lastn=, -firstn=, -linkn=, -maskn= if 0 < #c then if not utilities.is_set (Contribution) then -- |contributor= requires |contribution= utilities.set_message ('err_contributor_missing_required_param', 'contribution'); -- add missing contribution error message c = {}; -- blank the contributors' table; it is used as a flag later end if 0 == #a then -- |contributor= requires |author= utilities.set_message ('err_contributor_missing_required_param', 'author'); -- add missing author error message c = {}; -- blank the contributors' table; it is used as a flag later end end else -- if not a book cite if utilities.select_one (args, cfg.aliases['ContributorList-Last'], 'err_redundant_parameters', 1 ) then -- are there contributor name list parameters? utilities.set_message ('err_contributor_ignored'); -- add contributor ignored error message end Contribution = nil; -- unset end local Title = A['Title']; local TitleLink = A['TitleLink']; local auto_select = ''; -- default is auto local accept_link; TitleLink, accept_link = utilities.has_accept_as_written (TitleLink, true); -- test for accept-this-as-written markup if (not accept_link) and utilities.in_array (TitleLink, {'none', 'pmc', 'doi'}) then -- check for special keywords auto_select = TitleLink; -- remember selection for later TitleLink = ''; -- treat as if |title-link= would have been empty end TitleLink = link_title_ok (TitleLink, A:ORIGIN ('TitleLink'), Title, 'title'); -- check for wiki-markup in |title-link= or wiki-markup in |title= when |title-link= is set local Section = ''; -- {{cite map}} only; preset to empty string for concatenation if not used if 'map' == config.CitationClass and 'section' == Chapter_origin then Section = A['Chapter']; -- get |section= from |chapter= alias list; |chapter= and the other aliases not supported in {{cite map}} Chapter = ''; -- unset for now; will be reset later from |map= if present end local Periodical = A['Periodical']; local Periodical_origin = A:ORIGIN('Periodical'); local ScriptPeriodical = A['ScriptPeriodical']; local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical'); local TransPeriodical = A['TransPeriodical']; local TransPeriodical_origin = A:ORIGIN ('TransPeriodical'); if (utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical))) then local param; if utilities.is_set (Periodical) then -- get a parameter name from one of these periodical related meta-parameters Periodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = Periodical_origin -- get parameter name for error messaging elseif utilities.is_set (TransPeriodical) then TransPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = TransPeriodical_origin; -- get parameter name for error messaging elseif utilities.is_set (ScriptPeriodical) then ScriptPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = ScriptPeriodical_origin; -- get parameter name for error messaging end if utilities.is_set (param) then -- if we found one utilities.set_message ('err_periodical_ignored', {param}); -- emit an error message end end if utilities.is_set (Periodical) then local i; Periodical, i = utilities.strip_apostrophe_markup (Periodical); -- strip apostrophe markup so that metadata isn't contaminated if i then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {Periodical_origin}); end end if 'mailinglist' == config.CitationClass then -- special case for {{cite mailing list}} if utilities.is_set (Periodical) and utilities.is_set (A ['MailingList']) then -- both set emit an error TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', Periodical_origin) .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'mailinglist')}); end Periodical = A ['MailingList']; -- error or no, set Periodical to |mailinglist= value because this template is {{cite mailing list}} Periodical_origin = A:ORIGIN('MailingList'); end -- web and news not tested for now because of -- Wikipedia:Administrators%27_noticeboard#Is_there_a_semi-automated_tool_that_could_fix_these_annoying_"Cite_Web"_errors? if not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) then -- 'periodical' templates require periodical parameter -- local p = {['journal'] = 'journal', ['magazine'] = 'magazine', ['news'] = 'newspaper', ['web'] = 'website'}; -- for error message local p = {['journal'] = 'journal', ['magazine'] = 'magazine'}; -- for error message if p[config.CitationClass] then utilities.set_message ('err_missing_periodical', {config.CitationClass, p[config.CitationClass]}); end end local Volume; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) then if not utilities.in_array (Periodical_origin, cfg.citation_no_volume_t) then -- {{citation}} does not render |volume= when these parameters are used Volume = A['Volume']; -- but does for all other 'periodicals' end elseif utilities.is_set (ScriptPeriodical) then if 'script-website' ~= ScriptPeriodical_origin then -- {{citation}} does not render volume for |script-website= Volume = A['Volume']; -- but does for all other 'periodicals' end else Volume = A['Volume']; -- and does for non-'periodical' cites end elseif utilities.in_array (config.CitationClass, cfg.templates_using_volume) then -- render |volume= for cs1 according to the configuration settings Volume = A['Volume']; end extra_text_in_vol_iss_check (Volume, A:ORIGIN ('Volume'), 'v'); local Issue; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) and utilities.in_array (Periodical_origin, cfg.citation_issue_t) then -- {{citation}} may render |issue= when these parameters are used Issue = A['Issue']; end elseif utilities.in_array (config.CitationClass, cfg.templates_using_issue) then -- conference & map books do not support issue; {{citation}} listed here because included in settings table if not (utilities.in_array (config.CitationClass, {'conference', 'map', 'citation'}) and not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical))) then Issue = A['Issue']; end end local ArticleNumber; if utilities.in_array (config.CitationClass, {'journal', 'conference'}) or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then ArticleNumber = A['ArticleNumber']; end extra_text_in_vol_iss_check (Issue, A:ORIGIN ('Issue'), 'i'); Issue = utilities.hyphen_to_dash (Issue); local Page; local Pages; local At; local QuotePage; local QuotePages; if not utilities.in_array (config.CitationClass, cfg.templates_not_using_page) then -- TODO: rewrite to emit ignored parameter error message? Page = A['Page']; Pages = utilities.hyphen_to_dash (A['Pages']); At = A['At']; QuotePage = A['QuotePage']; QuotePages = utilities.hyphen_to_dash (A['QuotePages']); end local NoPP = is_valid_parameter_value (A['NoPP'], A:ORIGIN('NoPP'), cfg.keywords_lists['yes_true_y'], nil); local Mode = mode_set (A['Mode'], A:ORIGIN('Mode')); -- separator character and postscript local sepc, PostScript = set_style (Mode:lower(), A['PostScript'], config.CitationClass); local Quote; Quote, QuotePage, QuotePages, PostScript = quote_make (A['Quote'], A['TransQuote'], A['ScriptQuote'], QuotePage, QuotePages, NoPP, sepc, PostScript); local Edition = A['Edition']; local PublicationPlace = place_check (A['PublicationPlace'], A:ORIGIN('PublicationPlace')); local Place = place_check (A['Place'], A:ORIGIN('Place')); local PublisherName = A['PublisherName']; local PublisherName_origin = A:ORIGIN('PublisherName'); if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then local i = 0; PublisherName, i = utilities.strip_apostrophe_markup (PublisherName); -- strip apostrophe markup so that metadata isn't contaminated; publisher is never italicized if i and (0 < i) then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {PublisherName_origin}); end end if ('document' == config.CitationClass) and not utilities.is_set (PublisherName) then utilities.set_message ('err_missing_publisher', {config.CitationClass, 'publisher'}); end local Newsgroup = A['Newsgroup']; -- TODO: strip apostrophe markup? local Newsgroup_origin = A:ORIGIN('Newsgroup'); if 'newsgroup' == config.CitationClass then if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then -- general use parameter |publisher= not allowed in cite newsgroup utilities.set_message ('err_parameter_ignored', {PublisherName_origin}); end PublisherName = nil; -- ensure that this parameter is unset for the time being; will be used again after COinS end if 'book' == config.CitationClass or 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then local accept; PublisherName, accept = utilities.has_accept_as_written (PublisherName); -- check for and remove accept-as-written markup from |publisher= wrapped if not accept then -- when no accept-as-written markup check_publisher_name (PublisherName); -- emit maint message when |publisher= might be prefixed with publisher's location end end local URL = A['URL']; -- TODO: better way to do this for URL, ChapterURL, and MapURL? local UrlAccess = is_valid_parameter_value (A['UrlAccess'], A:ORIGIN('UrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (URL) and utilities.is_set (UrlAccess) then UrlAccess = nil; utilities.set_message ('err_param_access_requires_param', 'url'); end local ChapterURL = A['ChapterURL']; local ChapterUrlAccess = is_valid_parameter_value (A['ChapterUrlAccess'], A:ORIGIN('ChapterUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (ChapterURL) and utilities.is_set (ChapterUrlAccess) then ChapterUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {A:ORIGIN('ChapterUrlAccess'):gsub ('%-access', '')}); end local MapUrlAccess = is_valid_parameter_value (A['MapUrlAccess'], A:ORIGIN('MapUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (A['MapURL']) and utilities.is_set (MapUrlAccess) then MapUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {'map-url'}); end local this_page = mw.title.getCurrentTitle(); -- also used for COinS and for language local no_tracking_cats = is_valid_parameter_value (A['NoTracking'], A:ORIGIN('NoTracking'), cfg.keywords_lists['yes_true_y'], nil); -- check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories if not utilities.is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page if cfg.uncategorized_namespaces[this_page.namespace] then -- is this page's namespace id one of the uncategorized namespace ids? no_tracking_cats = "true"; -- set no_tracking_cats end for _, v in ipairs (cfg.uncategorized_subpages) do -- cycle through page name patterns if this_page.text:match (v) then -- test page name against each pattern no_tracking_cats = "true"; -- set no_tracking_cats break; -- bail out if one is found end end end -- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it) utilities.select_one (args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'err_redundant_parameters'); -- this is a dummy call simply to get the error message and category local coins_pages; Page, Pages, At, coins_pages = insource_loc_get (Page, A:ORIGIN('Page'), Pages, A:ORIGIN('Pages'), At); if utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- both |publication-place= and |place= (|location=) allowed if different utilities.add_prop_cat ('location-test'); -- add property cat to evaluate how often PublicationPlace and Place are used together if PublicationPlace == Place then Place = ''; -- unset; don't need both if they are the same end elseif not utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- when only |place= (|location=) is set ... PublicationPlace = Place; -- promote |place= (|location=) to |publication-place end if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same local URL_origin = A:ORIGIN('URL'); -- get name of parameter that holds URL local ChapterURL_origin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL local ScriptChapter = A['ScriptChapter']; local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); local Format = A['Format']; local ChapterFormat = A['ChapterFormat']; local TransChapter = A['TransChapter']; local TransChapter_origin = A:ORIGIN ('TransChapter'); local TransTitle = A['TransTitle']; local ScriptTitle = A['ScriptTitle']; --[[ Parameter remapping for cite encyclopedia: When the citation has these parameters: |encyclopedia= and |title= then map |title= to |article= and |encyclopedia= to |title= for rendering |encyclopedia= and |article= then map |encyclopedia= to |title= for rendering |trans-title= maps to |trans-chapter= when |title= is re-mapped |url= maps to |chapter-url= when |title= is remapped All other combinations of |encyclopedia=, |title=, and |article= are not modified ]] local Encyclopedia = A['Encyclopedia']; -- used as a flag by this module and by ~/COinS local ScriptEncyclopedia = A['ScriptEncyclopedia']; local TransEncyclopedia = A['TransEncyclopedia']; if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then -- emit error message when Encyclopedia set but template is other than {{cite encyclopedia}} or {{citation}} if 'encyclopaedia' ~= config.CitationClass and 'citation' ~= config.CitationClass then if utilities.is_set (Encyclopedia) then utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('Encyclopedia')}); else utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('ScriptEncyclopedia')}); end Encyclopedia = nil; -- unset these because not supported by this template ScriptEncyclopedia = nil; TransEncyclopedia = nil; end elseif utilities.is_set (TransEncyclopedia) then utilities.set_message ('err_trans_missing_title', {'encyclopedia'}); end if ('encyclopaedia' == config.CitationClass) or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Periodical) and utilities.is_set (Encyclopedia) then -- when both parameters set emit an error message; {{citation}} only; Periodical not allowed in {{cite encyclopedia}} utilities.set_message ('err_periodical_ignored', {Periodical_origin}); end if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then Periodical = Encyclopedia; -- error or no, set Periodical to Encyclopedia for rendering; {{citation}} could (not legitimately) have both; use Encyclopedia Periodical_origin = A:ORIGIN ('Encyclopedia'); ScriptPeriodical = ScriptEncyclopedia; ScriptPeriodical_origin = A:ORIGIN ('ScriptEncyclopedia'); if utilities.is_set (Title) or utilities.is_set (ScriptTitle) then if not utilities.is_set (Chapter) then Chapter = Title; -- |encyclopedia= and |title= are set so map |title= params to |article= params for rendering ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle') TransChapter = TransTitle; ChapterURL = URL; ChapterURL_origin = URL_origin; ChapterUrlAccess = UrlAccess; ChapterFormat = Format; if not utilities.is_set (ChapterURL) and utilities.is_set (TitleLink) then Chapter = utilities.make_wikilink (TitleLink, Chapter); end Title = Periodical; -- now map |encyclopedia= params to |title= params for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; URL = ''; Format = ''; TitleLink = ''; end elseif utilities.is_set (Chapter) or utilities.is_set (ScriptChapter) then -- |title= not set Title = Periodical; -- |encyclopedia= set and |article= set so map |encyclopedia= to |title= for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; end end end -- special case for cite techreport. local ID = A['ID']; if (config.CitationClass == "techreport") then -- special case for cite techreport if utilities.is_set (A['Number']) then -- cite techreport uses 'number', which other citations alias to 'issue' if not utilities.is_set (ID) then -- can we use ID for the "number"? ID = A['Number']; -- yes, use it else -- ID has a value so emit error message utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'id') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'number')}); end end end -- Account for the oddity that is {{cite conference}}, before generation of COinS data. local ChapterLink -- = A['ChapterLink']; -- deprecated as a parameter but still used internally by cite episode local Conference = A['Conference']; local BookTitle = A['BookTitle']; local TransTitle_origin = A:ORIGIN ('TransTitle'); if 'conference' == config.CitationClass then if utilities.is_set (BookTitle) then Chapter = Title; Chapter_origin = 'title'; -- ChapterLink = TitleLink; -- |chapter-link= is deprecated ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; URL_origin = ''; ChapterFormat = Format; TransChapter = TransTitle; TransChapter_origin = TransTitle_origin; Title = BookTitle; Format = ''; -- TitleLink = ''; TransTitle = ''; URL = ''; end elseif 'speech' ~= config.CitationClass then Conference = ''; -- not cite conference or cite speech so make sure this is empty string end local cs2_lower = function (text) -- if mode is cs2, use lower case if (sepc ~= '.') then return text:lower(); end return text; end local use_lowercase = ( sepc == ',' ); -- controls capitalization of certain static text -- cite map oddities local Cartography = ""; local Scale = ""; local Sheet = A['Sheet'] or ''; local Sheets = A['Sheets'] or ''; if config.CitationClass == "map" then if utilities.is_set (Chapter) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'map') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', Chapter_origin)}); -- add error message end Chapter = A['Map']; Chapter_origin = A:ORIGIN('Map'); ChapterURL = A['MapURL']; ChapterURL_origin = A:ORIGIN('MapURL'); TransChapter = A['TransMap']; ScriptChapter = A['ScriptMap'] ScriptChapter_origin = A:ORIGIN('ScriptMap') ChapterUrlAccess = MapUrlAccess; ChapterFormat = A['MapFormat']; Cartography = A['Cartography']; if utilities.is_set ( Cartography ) then Cartography = sepc .. " " .. wrap_msg ('cartography', Cartography, use_lowercase); end Scale = A['Scale']; if utilities.is_set ( Scale ) then Scale = sepc .. " " .. Scale; end end -- Account for the oddities that are {{cite episode}} and {{cite serial}}, before generation of COinS data. local Series = A['Series']; if 'episode' == config.CitationClass or 'serial' == config.CitationClass then local SeriesLink = A['SeriesLink']; SeriesLink = link_title_ok (SeriesLink, A:ORIGIN ('SeriesLink'), Series, 'series'); -- check for wiki-markup in |series-link= or wiki-markup in |series= when |series-link= is set local Network = A['Network']; local Station = A['Station']; local s, n = {}, {}; -- do common parameters first if utilities.is_set (Network) then table.insert(n, Network); end if utilities.is_set (Station) then table.insert(n, Station); end ID = table.concat(n, sepc .. ' '); if 'episode' == config.CitationClass then -- handle the oddities that are strictly {{cite episode}} local Season = A['Season']; local SeriesNumber = A['SeriesNumber']; if utilities.is_set (Season) and utilities.is_set (SeriesNumber) then -- these are mutually exclusive so if both are set TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'season') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'seriesno')}); -- add error message SeriesNumber = ''; -- unset; prefer |season= over |seriesno= end -- assemble a table of parts concatenated later into Series if utilities.is_set (Season) then table.insert(s, wrap_msg ('season', Season, use_lowercase)); end if utilities.is_set (SeriesNumber) then table.insert(s, wrap_msg ('seriesnum', SeriesNumber, use_lowercase)); end if utilities.is_set (Issue) then table.insert(s, wrap_msg ('episode', Issue, use_lowercase)); end Issue = ''; -- unset because this is not a unique parameter Chapter = Title; -- promote title parameters to chapter ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle'); ChapterLink = TitleLink; -- alias |episode-link= TransChapter = TransTitle; ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; ChapterFormat = Format; Title = Series; -- promote series to title TitleLink = SeriesLink; Series = table.concat(s, sepc .. ' '); -- this is concatenation of season, seriesno, episode number if utilities.is_set (ChapterLink) and not utilities.is_set (ChapterURL) then -- link but not URL Chapter = utilities.make_wikilink (ChapterLink, Chapter); elseif utilities.is_set (ChapterLink) and utilities.is_set (ChapterURL) then -- if both are set, URL links episode; Series = utilities.make_wikilink (ChapterLink, Series); end URL = ''; -- unset TransTitle = ''; ScriptTitle = ''; Format = ''; else -- now oddities that are cite serial Issue = ''; -- unset because this parameter no longer supported by the citation/core version of cite serial Chapter = A['Episode']; -- TODO: make |episode= available to cite episode someday? if utilities.is_set (Series) and utilities.is_set (SeriesLink) then Series = utilities.make_wikilink (SeriesLink, Series); end Series = utilities.wrap_style ('italic-title', Series); -- series is italicized end end -- end of {{cite episode}} stuff -- handle type parameter for those CS1 citations that have default values local TitleType = A['TitleType']; local Degree = A['Degree']; if utilities.in_array (config.CitationClass, {'AV-media-notes', 'document', 'interview', 'mailinglist', 'map', 'podcast', 'pressrelease', 'report', 'speech', 'techreport', 'thesis'}) then TitleType = set_titletype (config.CitationClass, TitleType); if utilities.is_set (Degree) and "Thesis" == TitleType then -- special case for cite thesis TitleType = Degree .. ' ' .. cfg.title_types ['thesis']:lower(); end end if utilities.is_set (TitleType) then -- if type parameter is specified TitleType = utilities.substitute ( cfg.messages['type'], TitleType); -- display it in parentheses -- TODO: Hack on TitleType to fix bunched parentheses problem end -- legacy: promote PublicationDate to Date if neither Date nor Year are set. local Date = A['Date']; local Date_origin; -- to hold the name of parameter promoted to Date; required for date error messaging local PublicationDate = A['PublicationDate']; local Year = A['Year']; if utilities.is_set (Year) then validation.year_check (Year); -- returns nothing; emits maint message when |year= doesn't hold a 'year' value end if not utilities.is_set (Date) then Date = Year; -- promote Year to Date Year = nil; -- make nil so Year as empty string isn't used for CITEREF if not utilities.is_set (Date) and utilities.is_set (PublicationDate) then -- use PublicationDate when |date= and |year= are not set Date = PublicationDate; -- promote PublicationDate to Date PublicationDate = ''; -- unset, no longer needed Date_origin = A:ORIGIN('PublicationDate'); -- save the name of the promoted parameter else Date_origin = A:ORIGIN('Year'); -- save the name of the promoted parameter end else Date_origin = A:ORIGIN('Date'); -- not a promotion; name required for error messaging end if PublicationDate == Date then PublicationDate = ''; end -- if PublicationDate is same as Date, don't display in rendered citation --[[ Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates. This must be done before we do COinS because here is where we get the date used in the metadata. Date validation supporting code is in Module:Citation/CS1/Date_validation ]] local DF = is_valid_parameter_value (A['DF'], A:ORIGIN('DF'), cfg.keywords_lists['df'], ''); if not utilities.is_set (DF) then DF = cfg.global_df; -- local |df= if present overrides global df set by {{use xxx date}} template end local ArchiveURL; local ArchiveDate; local ArchiveFormat = A['ArchiveFormat']; local archive_url_timestamp; -- timestamp from wayback machine url ArchiveURL, ArchiveDate, archive_url_timestamp = archive_url_check (A['ArchiveURL'], A['ArchiveDate']) ArchiveFormat = style_format (ArchiveFormat, ArchiveURL, 'archive-format', 'archive-url'); ArchiveURL, ArchiveDate = is_unique_archive_url (ArchiveURL, URL, ChapterURL, A:ORIGIN('ArchiveURL'), ArchiveDate); -- add error message when URL or ChapterURL == ArchiveURL local AccessDate = A['AccessDate']; local COinS_date = {}; -- holds date info extracted from |date= for the COinS metadata by Module:Date verification local DoiBroken = A['DoiBroken']; local Embargo = A['Embargo']; local anchor_year; -- used in the CITEREF identifier do -- create defined block to contain local variables error_message, date_parameters_list, mismatch local error_message = ''; -- AirDate has been promoted to Date so not necessary to check it local date_parameters_list = { ['access-date'] = {val = AccessDate, name = A:ORIGIN ('AccessDate')}, ['archive-date'] = {val = ArchiveDate, name = A:ORIGIN ('ArchiveDate')}, ['date'] = {val = Date, name = Date_origin}, ['doi-broken-date'] = {val = DoiBroken, name = A:ORIGIN ('DoiBroken')}, ['pmc-embargo-date'] = {val = Embargo, name = A:ORIGIN ('Embargo')}, ['publication-date'] = {val = PublicationDate, name = A:ORIGIN ('PublicationDate')}, ['year'] = {val = Year, name = A:ORIGIN ('Year')}, }; local error_list = {}; anchor_year, Embargo = validation.dates(date_parameters_list, COinS_date, error_list); if utilities.is_set (Year) and utilities.is_set (Date) then -- both |date= and |year= not normally needed; validation.year_date_check (Year, A:ORIGIN ('Year'), Date, A:ORIGIN ('Date'), error_list); end if 0 == #error_list then -- error free dates only; 0 when error_list is empty local modified = false; -- flag if utilities.is_set (DF) then -- if we need to reformat dates modified = validation.reformat_dates (date_parameters_list, DF); -- reformat to DF format, use long month names if appropriate end if true == validation.date_hyphen_to_dash (date_parameters_list) then -- convert hyphens to dashes where appropriate modified = true; utilities.set_message ('maint_date_format'); -- hyphens were converted so add maint category end -- for those wikis that can and want to have English date names translated to the local language; not supported at en.wiki if cfg.date_name_auto_xlate_enable and validation.date_name_xlate (date_parameters_list, cfg.date_digit_auto_xlate_enable ) then utilities.set_message ('maint_date_auto_xlated'); -- add maint cat modified = true; end if modified then -- if the date_parameters_list values were modified AccessDate = date_parameters_list['access-date'].val; -- overwrite date holding parameters with modified values ArchiveDate = date_parameters_list['archive-date'].val; Date = date_parameters_list['date'].val; DoiBroken = date_parameters_list['doi-broken-date'].val; PublicationDate = date_parameters_list['publication-date'].val; end if archive_url_timestamp and utilities.is_set (ArchiveDate) then validation.archive_date_check (ArchiveDate, archive_url_timestamp, DF); -- does YYYYMMDD in archive_url_timestamp match date in ArchiveDate end else utilities.set_message ('err_bad_date', {utilities.make_sep_list (#error_list, error_list)}); -- add this error message end end -- end of do if utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) or -- {{cite book}}, {{cite encyclopedia}}; TODO: {{cite conference}} and others? ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) or -- {{citation}} as an encylopedia citation ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then -- {{citation}} as a book citation if utilities.is_set (PublicationPlace) then if not utilities.is_set (PublisherName) then local date = COinS_date.rftdate and tonumber (COinS_date.rftdate:match ('%d%d%d%d')); -- get year portion of COinS date (because in Arabic numerals); convert string to number if date and (1850 <= date) then -- location has no publisher; if date is 1850 or later utilities.set_message ('maint_location_no_publisher'); -- add maint cat end else -- PublisherName has a value if cfg.keywords_xlate['none'] == PublisherName then -- if that value is 'none' (only for book and encyclopedia citations) PublisherName = ''; -- unset end end end end local ID_list = {}; -- sequence table of rendered identifiers local ID_list_coins = {}; -- table of identifiers and their values from args; key is same as cfg.id_handlers's key local Class = A['Class']; -- arxiv class identifier local ID_support = { {A['ASINTLD'], 'ASIN', 'err_asintld_missing_asin', A:ORIGIN ('ASINTLD')}, {DoiBroken, 'DOI', 'err_doibroken_missing_doi', A:ORIGIN ('DoiBroken')}, {Embargo, 'PMC', 'err_embargo_missing_pmc', A:ORIGIN ('Embargo')}, } ID_list, ID_list_coins = identifiers.identifier_lists_get (args, { DoiBroken = DoiBroken, -- for |doi= ASINTLD = A['ASINTLD'], -- for |asin= Embargo = Embargo, -- for |pmc= Class = Class, -- for |arxiv= CitationClass = config.CitationClass, -- for |arxiv= Year=anchor_year, -- for |isbn= }, ID_support); if 'citation' == config.CitationClass then -- catch ve/citoid malformed book cites in {{citation}} templates for _, id in ipairs (ID_list) do -- search through the ID_list sequence looking for an ISBN identifier string if id:find ('ISBN', 3, true) then -- plain find, start at index 3 ([[ISBN) if utilities.is_set (Periodical) then -- when a |work= alias is set utilities.set_message ('maint_work_isbn'); -- add maint cat end end end end -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, {{cite ssrn}}, before generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv=, |citeseerx=, |medrxiv=, |ssrn= required for their templates if not (args[cfg.id_handlers[config.CitationClass:upper()].parameters[1]] or -- can't use ID_list_coins k/v table here because invalid parameters omitted args[cfg.id_handlers[config.CitationClass:upper()].parameters[2]]) then -- which causes unexpected parameter missing error message utilities.set_message ('err_' .. config.CitationClass .. '_missing'); -- add error message end Periodical = ({['arxiv'] = 'arXiv', ['biorxiv'] = 'bioRxiv', ['citeseerx'] = 'CiteSeerX', ['medrxiv'] = 'medRxiv', ['ssrn'] = 'Social Science Research Network'})[config.CitationClass]; end -- Link the title of the work if no |url= was provided, but we have a |pmc= or a |doi= with |doi-access=free if config.CitationClass == "journal" and not utilities.is_set (URL) and not utilities.is_set (TitleLink) and not utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) then -- TODO: remove 'none' once existing citations have been switched to 'off', so 'none' can be used as token for "no title" instead if 'none' ~= cfg.keywords_xlate[auto_select] then -- if auto-linking not disabled if identifiers.auto_link_urls[auto_select] then -- manual selection URL = identifiers.auto_link_urls[auto_select]; -- set URL to be the same as identifier's external link URL_origin = cfg.id_handlers[auto_select:upper()].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['pmc'] then -- auto-select PMC URL = identifiers.auto_link_urls['pmc']; -- set URL to be the same as the PMC external link if not embargoed URL_origin = cfg.id_handlers['PMC'].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['doi'] then -- auto-select DOI URL = identifiers.auto_link_urls['doi']; URL_origin = cfg.id_handlers['DOI'].parameters[1]; end end if utilities.is_set (URL) then -- set when using an identifier-created URL if utilities.is_set (AccessDate) then -- |access-date= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_accessdate_missing_url'); -- add an error message AccessDate = ''; -- unset end if utilities.is_set (ArchiveURL) then -- |archive-url= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_archive_missing_url'); -- add an error message ArchiveURL = ''; -- unset end end end -- At this point fields may be nil if they weren't specified in the template use. We can use that fact. -- Test if citation has no title if not utilities.is_set (Title) and not utilities.is_set (TransTitle) and not utilities.is_set (ScriptTitle) then -- has special case for cite episode utilities.set_message ('err_citation_missing_title', {'episode' == config.CitationClass and 'series' or 'title'}); end if utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) and utilities.in_array (config.CitationClass, {'journal', 'citation'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and ('journal' == Periodical_origin or 'script-journal' == ScriptPeriodical_origin) then -- special case for journal cites Title = ''; -- set title to empty string utilities.set_message ('maint_untitled'); -- add maint cat end if 'journal' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then if is_page_art_num (((utilities.is_set (Page) and Page) or (utilities.is_set (Pages) and Pages)) or nil, ID_list_coins['DOI']) then -- does |page(s)= look like it holds an article number utilities.set_message ('maint_page_art_num'); -- add maint cat end end -- COinS metadata (see <http://ocoins.info/>) for automated parsing of citation information. -- handle the oddity that is cite encyclopedia and {{citation |encyclopedia=something}}. Here we presume that -- when Periodical, Title, and Chapter are all set, then Periodical is the book (encyclopedia) title, Title -- is the article title, and Chapter is a section within the article. So, we remap local coins_chapter = Chapter; -- default assuming that remapping not required local coins_title = Title; -- et tu if 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Chapter) and utilities.is_set (Title) and utilities.is_set (Periodical) then -- if all are used then coins_chapter = Title; -- remap coins_title = Periodical; end end local coins_author = a; -- default for coins rft.au if 0 < #c then -- but if contributor list coins_author = c; -- use that instead end -- this is the function call to COinS() local OCinSoutput = metadata.COinS({ ['Periodical'] = utilities.strip_apostrophe_markup (Periodical), -- no markup in the metadata ['Encyclopedia'] = Encyclopedia, -- just a flag; content ignored by ~/COinS ['Chapter'] = metadata.make_coins_title (coins_chapter, ScriptChapter), -- Chapter and ScriptChapter stripped of bold / italic / accept-as-written markup ['Degree'] = Degree; -- cite thesis only ['Title'] = metadata.make_coins_title (coins_title, ScriptTitle), -- Title and ScriptTitle stripped of bold / italic / accept-as-written markup ['PublicationPlace'] = PublicationPlace, ['Date'] = COinS_date.rftdate, -- COinS_date.* has correctly formatted date values if Date is valid; ['Season'] = COinS_date.rftssn, ['Quarter'] = COinS_date.rftquarter, ['Chron'] = COinS_date.rftchron, ['Series'] = Series, ['Volume'] = Volume, ['Issue'] = Issue, ['ArticleNumber'] = ArticleNumber, ['Pages'] = coins_pages or metadata.get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At, QuotePage, QuotePages}, 7)), -- pages stripped of external links ['Edition'] = Edition, ['PublisherName'] = PublisherName or Newsgroup, -- any apostrophe markup already removed from PublisherName ['URL'] = first_set ({ChapterURL, URL}, 2), ['Authors'] = coins_author, ['ID_list'] = ID_list_coins, ['RawPage'] = this_page.prefixedText, }, config.CitationClass); -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, and {{cite ssrn}} AFTER generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- we have set rft.jtitle in COinS to arXiv, bioRxiv, CiteSeerX, medRxiv, or ssrn now unset so it isn't displayed Periodical = ''; -- periodical not allowed in these templates; if article has been published, use cite journal end -- special case for cite newsgroup. Do this after COinS because we are modifying Publishername to include some static text if 'newsgroup' == config.CitationClass and utilities.is_set (Newsgroup) then PublisherName = utilities.substitute (cfg.messages['newsgroup'], external_link( 'news:' .. Newsgroup, Newsgroup, Newsgroup_origin, nil )); end local Editors; local EditorCount; -- used only for choosing {ed.) or (eds.) annotation at end of editor name-list local Contributors; -- assembled contributors name list local contributor_etal; local Translators; -- assembled translators name list local translator_etal; local t = {}; -- translators list from |translator-lastn= / translator-firstn= pairs t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= local Interviewers; local interviewers_list = {}; interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters local interviewer_etal; -- Now perform various field substitutions. -- We also add leading spaces and surrounding markup and punctuation to the -- various parts of the citation, but only when they are non-nil. do local last_first_list; local control = { format = NameListStyle, -- empty string, '&', 'amp', 'and', or 'vanc' maximum = nil, -- as if display-authors or display-editors not set mode = Mode }; do -- do editor name list first because the now unsupported coauthors used to modify control table local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayEditors'], A['DisplayEditors'], A:ORIGIN ('DisplayEditors'), #e); control.maximum, editor_etal = get_display_names (display_names, #e, 'editors', editor_etal, param); Editors, EditorCount = list_people (control, e, editor_etal); if 1 == EditorCount and (true == editor_etal or 1 < #e) then -- only one editor displayed but includes etal then EditorCount = 2; -- spoof to display (eds.) annotation end end do -- now do interviewers local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayInterviewers'], A['DisplayInterviewers'], A:ORIGIN ('DisplayInterviewers'), #interviewers_list); control.maximum, interviewer_etal = get_display_names (display_names, #interviewers_list, 'interviewers', interviewer_etal, param); Interviewers = list_people (control, interviewers_list, interviewer_etal); end do -- now do translators local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayTranslators'], A['DisplayTranslators'], A:ORIGIN ('DisplayTranslators'), #t); control.maximum, translator_etal = get_display_names (display_names, #t, 'translators', translator_etal, param); Translators = list_people (control, t, translator_etal); end do -- now do contributors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayContributors'], A['DisplayContributors'], A:ORIGIN ('DisplayContributors'), #c); control.maximum, contributor_etal = get_display_names (display_names, #c, 'contributors', contributor_etal, param); Contributors = list_people (control, c, contributor_etal); end do -- now do authors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayAuthors'], A['DisplayAuthors'], A:ORIGIN ('DisplayAuthors'), #a, author_etal); control.maximum, author_etal = get_display_names (display_names, #a, 'authors', author_etal, param); last_first_list = list_people (control, a, author_etal); if utilities.is_set (Authors) then Authors, author_etal = name_has_etal (Authors, author_etal, false, 'authors'); -- find and remove variations on et al. if author_etal then Authors = Authors .. ' ' .. cfg.messages['et al']; -- add et al. to authors parameter end else Authors = last_first_list; -- either an author name list or an empty string end end -- end of do if utilities.is_set (Authors) and utilities.is_set (Collaboration) then Authors = Authors .. ' (' .. Collaboration .. ')'; -- add collaboration after et al. end end local ConferenceFormat = A['ConferenceFormat']; local ConferenceURL = A['ConferenceURL']; ConferenceFormat = style_format (ConferenceFormat, ConferenceURL, 'conference-format', 'conference-url'); Format = style_format (Format, URL, 'format', 'url'); -- special case for chapter format so no error message or cat when chapter not supported if not (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia))) then ChapterFormat = style_format (ChapterFormat, ChapterURL, 'chapter-format', 'chapter-url'); end if not utilities.is_set (URL) then if utilities.in_array (config.CitationClass, {"web", "podcast", "mailinglist"}) or -- |url= required for cite web, cite podcast, and cite mailinglist ('citation' == config.CitationClass and ('website' == Periodical_origin or 'script-website' == ScriptPeriodical_origin)) then -- and required for {{citation}} with |website= or |script-website= utilities.set_message ('err_cite_web_url'); end -- do we have |accessdate= without either |url= or |chapter-url=? if utilities.is_set (AccessDate) and not utilities.is_set (ChapterURL) then -- ChapterURL may be set when URL is not set; utilities.set_message ('err_accessdate_missing_url'); AccessDate = ''; end end local UrlStatus = is_valid_parameter_value (A['UrlStatus'], A:ORIGIN('UrlStatus'), cfg.keywords_lists['url-status'], ''); local OriginalURL local OriginalURL_origin local OriginalFormat local OriginalAccess; UrlStatus = UrlStatus:lower(); -- used later when assembling archived text if utilities.is_set ( ArchiveURL ) then if utilities.is_set (ChapterURL) then -- if chapter-url= is set apply archive url to it OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text OriginalURL_origin = ChapterURL_origin; -- name of |chapter-url= parameter for error messages OriginalFormat = ChapterFormat; -- and original |chapter-format= if 'live' ~= UrlStatus then ChapterURL = ArchiveURL -- swap-in the archive's URL ChapterURL_origin = A:ORIGIN('ArchiveURL') -- name of |archive-url= parameter for error messages ChapterFormat = ArchiveFormat or ''; -- swap in archive's format ChapterUrlAccess = nil; -- restricted access levels do not make sense for archived URLs end elseif utilities.is_set (URL) then OriginalURL = URL; -- save copy of original source URL OriginalURL_origin = URL_origin; -- name of URL parameter for error messages OriginalFormat = Format; -- and original |format= OriginalAccess = UrlAccess; if 'live' ~= UrlStatus then -- if URL set then |archive-url= applies to it URL = ArchiveURL -- swap-in the archive's URL URL_origin = A:ORIGIN('ArchiveURL') -- name of archive URL parameter for error messages Format = ArchiveFormat or ''; -- swap in archive's format UrlAccess = nil; -- restricted access levels do not make sense for archived URLs end end elseif utilities.is_set (UrlStatus) then -- if |url-status= is set when |archive-url= is not set utilities.set_message ('maint_url_status'); -- add maint cat end if utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or -- if any of the 'periodical' cites except encyclopedia ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) then local chap_param; if utilities.is_set (Chapter) then -- get a parameter name from one of these chapter related meta-parameters chap_param = A:ORIGIN ('Chapter') elseif utilities.is_set (TransChapter) then chap_param = A:ORIGIN ('TransChapter') elseif utilities.is_set (ChapterURL) then chap_param = A:ORIGIN ('ChapterURL') elseif utilities.is_set (ScriptChapter) then chap_param = ScriptChapter_origin; else utilities.is_set (ChapterFormat) chap_param = A:ORIGIN ('ChapterFormat') end if utilities.is_set (chap_param) then -- if we found one utilities.set_message ('err_chapter_ignored', {chap_param}); -- add error message Chapter = ''; -- and set them to empty string to be safe with concatenation TransChapter = ''; ChapterURL = ''; ScriptChapter = ''; ChapterFormat = ''; end else -- otherwise, format chapter / article title local no_quotes = false; -- default assume that we will be quoting the chapter parameter value if utilities.is_set (Contribution) and 0 < #c then -- if this is a contribution with contributor(s) if utilities.in_array (Contribution:lower(), cfg.keywords_lists.contribution) then -- and a generic contribution title no_quotes = true; -- then render it unquoted end end Chapter = format_chapter_title (ScriptChapter, ScriptChapter_origin, Chapter, Chapter_origin, TransChapter, TransChapter_origin, ChapterURL, ChapterURL_origin, no_quotes, ChapterUrlAccess); -- Contribution is also in Chapter if utilities.is_set (Chapter) then Chapter = Chapter .. ChapterFormat ; if 'map' == config.CitationClass and utilities.is_set (TitleType) then Chapter = Chapter .. ' ' .. TitleType; -- map annotation here; not after title end Chapter = Chapter .. sepc .. ' '; elseif utilities.is_set (ChapterFormat) then -- |chapter= not set but |chapter-format= is so ... Chapter = ChapterFormat .. sepc .. ' '; -- ... ChapterFormat has error message, we want to see it end end -- Format main title local plain_title = false; local accept_title; Title, accept_title = utilities.has_accept_as_written (Title, true); -- remove accept-this-as-written markup when it wraps all of <Title> if accept_title and ('' == Title) then -- only support forced empty for now "(())" Title = cfg.messages['notitle']; -- replace by predefined "No title" message -- TODO: utilities.set_message ( 'err_redundant_parameters', ...); -- issue proper error message instead of muting ScriptTitle = ''; -- just mute for now TransTitle = ''; -- just mute for now plain_title = true; -- suppress text decoration for descriptive title utilities.set_message ('maint_untitled'); -- add maint cat end if not accept_title then -- <Title> not wrapped in accept-as-written markup if '...' == Title:sub (-3) then -- if ellipsis is the last three characters of |title= Title = Title:gsub ('(%.%.%.)%.+$', '%1'); -- limit the number of dots to three elseif not mw.ustring.find (Title, '%.%s*%a%.$') and -- end of title is not a 'dot-(optional space-)letter-dot' initialism ... not mw.ustring.find (Title, '%s+%a%.$') then -- ...and not a 'space-letter-dot' initial (''Allium canadense'' L.) Title = mw.ustring.gsub(Title, '%' .. sepc .. '$', ''); -- remove any trailing separator character; sepc and ms.ustring() here for languages that use multibyte separator characters end if utilities.is_set (ArchiveURL) and is_archived_copy (Title) then utilities.set_message ('maint_archived_copy'); -- add maintenance category before we modify the content of Title end if is_generic ('generic_titles', Title) then utilities.set_message ('err_generic_title'); -- set an error message end end if (not plain_title) and (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'document', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) or ('map' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)))) then -- special case for cite map when the map is in a periodical treat as an article Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from module provided quote marks Title = utilities.wrap_style ('quoted-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); elseif plain_title or ('report' == config.CitationClass) then -- no styling for cite report and descriptive titles (otherwise same as above) Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); -- for cite report, use this form for trans-title else Title = utilities.wrap_style ('italic-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-italic-title', TransTitle); end if utilities.is_set (TransTitle) then if utilities.is_set (Title) then TransTitle = " " .. TransTitle; else utilities.set_message ('err_trans_missing_title', {'title'}); end end if utilities.is_set (Title) then -- TODO: is this the right place to be making Wikisource URLs? if utilities.is_set (TitleLink) and utilities.is_set (URL) then utilities.set_message ('err_wikilink_in_url'); -- set an error message because we can't have both TitleLink = ''; -- unset end if not utilities.is_set (TitleLink) and utilities.is_set (URL) then Title = external_link (URL, Title, URL_origin, UrlAccess) .. TransTitle .. Format; URL = ''; -- unset these because no longer needed Format = ""; elseif utilities.is_set (TitleLink) and not utilities.is_set (URL) then local ws_url; ws_url = wikisource_url_make (TitleLink); -- ignore ws_label return; not used here if ws_url then Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title-link'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], TitleLink, Title}); Title = Title .. TransTitle; else Title = utilities.make_wikilink (TitleLink, Title) .. TransTitle; end else local ws_url, ws_label, L; -- Title has italic or quote markup by the time we get here which causes is_wikilink() to return 0 (not a wikilink) ws_url, ws_label, L = wikisource_url_make (Title:gsub('^[\'"]*(.-)[\'"]*$', '%1')); -- make ws URL from |title= interwiki link (strip italic or quote markup); link portion L becomes tooltip label if ws_url then Title = Title:gsub ('%b[]', ws_label); -- replace interwiki link with ws_label to retain markup Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, Title}); Title = Title .. TransTitle; else Title = Title .. TransTitle; end end else Title = TransTitle; end if utilities.is_set (Place) then Place = " " .. wrap_msg ('written', Place, use_lowercase) .. sepc .. " "; end local ConferenceURL_origin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL if utilities.is_set (Conference) then if utilities.is_set (ConferenceURL) then Conference = external_link( ConferenceURL, Conference, ConferenceURL_origin, nil ); end Conference = sepc .. " " .. Conference .. ConferenceFormat; elseif utilities.is_set (ConferenceURL) then Conference = sepc .. " " .. external_link( ConferenceURL, nil, ConferenceURL_origin, nil ); end local Position = ''; if not utilities.is_set (Position) then local Minutes = A['Minutes']; local Time = A['Time']; if utilities.is_set (Minutes) then if utilities.is_set (Time) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'minutes') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'time')}); end Position = utilities.substitute (cfg.messages.minutes, Minutes); else if utilities.is_set (Time) then local TimeCaption = A['TimeCaption'] if not utilities.is_set (TimeCaption) then TimeCaption = cs2_lower(cfg.messages['event']); end Position = " " .. TimeCaption .. " " .. Time; end end else Position = " " .. Position; At = ''; end Page, Pages, Sheet, Sheets = format_pages_sheets (Page, Pages, Sheet, Sheets, config.CitationClass, Periodical_origin, sepc, NoPP, use_lowercase); At = utilities.is_set (At) and (sepc .. " " .. At) or ""; Position = utilities.is_set (Position) and (sepc .. " " .. Position) or ""; if config.CitationClass == 'map' then local Sections = A['Sections']; -- Section (singular) is an alias of Chapter so set earlier local Inset = A['Inset']; if utilities.is_set ( Inset ) then Inset = sepc .. " " .. wrap_msg ('inset', Inset, use_lowercase); end if utilities.is_set ( Sections ) then Section = sepc .. " " .. wrap_msg ('sections', Sections, use_lowercase); elseif utilities.is_set ( Section ) then Section = sepc .. " " .. wrap_msg ('section', Section, use_lowercase); end At = At .. Inset .. Section; end local Others = A['Others']; if utilities.is_set (Others) and 0 == #a and 0 == #e then -- add maint cat when |others= has value and used without |author=, |editor= if config.CitationClass == "AV-media-notes" or config.CitationClass == "audio-visual" then -- special maint for AV/M which has a lot of 'false' positives right now utilities.set_message ('maint_others_avm') else utilities.set_message ('maint_others'); end end Others = utilities.is_set (Others) and (sepc .. " " .. Others) or ""; if utilities.is_set (Translators) then Others = safe_join ({sepc .. ' ', wrap_msg ('translated', Translators, use_lowercase), Others}, sepc); end if utilities.is_set (Interviewers) then Others = safe_join ({sepc .. ' ', wrap_msg ('interview', Interviewers, use_lowercase), Others}, sepc); end local TitleNote = A['TitleNote']; TitleNote = utilities.is_set (TitleNote) and (sepc .. " " .. TitleNote) or ""; if utilities.is_set (Edition) then if Edition:match ('%f[%a][Ee]d%n?%.?$') or Edition:match ('%f[%a][Ee]dition$') then -- Ed, ed, Ed., ed., Edn, edn, Edn., edn. utilities.set_message ('err_extra_text_edition'); -- add error message end Edition = " " .. wrap_msg ('edition', Edition); else Edition = ''; end Series = utilities.is_set (Series) and wrap_msg ('series', {sepc, Series}) or ""; -- not the same as SeriesNum local Agency = A['Agency'] or ''; -- |agency= is supported by {{cite magazine}}, {{cite news}}, {{cite press release}}, {{cite web}}, and certain {{citation}} templates if utilities.is_set (Agency) then -- this testing done here because {{citation}} supports 'news' citations if utilities.in_array (config.CitationClass, {'magazine', 'news', 'pressrelease', 'web'}) or ('citation' == config.CitationClass and utilities.in_array (Periodical_origin, {"magazine", "newspaper", "work"})) then Agency = wrap_msg ('agency', {sepc, Agency}); -- format for rendering else Agency = ''; -- unset; not supported utilities.set_message ('err_parameter_ignored', {'agency'}); -- add error message end end Volume = format_volume_issue (Volume, Issue, ArticleNumber, config.CitationClass, Periodical_origin, sepc, use_lowercase); if utilities.is_set (AccessDate) then local retrv_text = " " .. cfg.messages['retrieved']; AccessDate = nowrap_date (AccessDate); -- wrap in nowrap span if date in appropriate format retrv_text = cs2_lower(retrv_text); -- if mode is cs2, lower case AccessDate = utilities.substitute (retrv_text, AccessDate); -- add retrieved text AccessDate = utilities.substitute (cfg.presentation['accessdate'], {sepc, AccessDate}); -- allow editors to hide accessdates end if utilities.is_set (ID) then ID = sepc .. " " .. ID; end local Docket = A['Docket']; if "thesis" == config.CitationClass and utilities.is_set (Docket) then ID = sepc .. " Docket " .. Docket .. ID; end if "report" == config.CitationClass and utilities.is_set (Docket) then -- for cite report when |docket= is set ID = sepc .. ' ' .. Docket; -- overwrite ID even if |id= is set end if utilities.is_set (URL) then URL = " " .. external_link( URL, nil, URL_origin, UrlAccess ); end -- We check length of PostScript here because it will have been nuked by -- the quote parameters. We'd otherwise emit a message even if there wasn't -- a displayed postscript. -- TODO: Should the max size (1) be configurable? -- TODO: Should we check a specific pattern? if utilities.is_set(PostScript) and mw.ustring.len(PostScript) > 1 then utilities.set_message ('maint_postscript') end local Archived; if utilities.is_set (ArchiveURL) then if not utilities.is_set (ArchiveDate) then -- ArchiveURL set but ArchiveDate not set utilities.set_message ('err_archive_missing_date'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end else if utilities.is_set (ArchiveDate) then -- ArchiveURL not set but ArchiveDate is set utilities.set_message ('err_archive_date_missing_url'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end end if utilities.is_set (ArchiveURL) then local arch_text; if "live" == UrlStatus then if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cfg.messages['archived-live'], { external_link( ArchiveURL, cs2_lower(cfg.messages['archived']), A:ORIGIN('ArchiveURL'), nil) .. ArchiveFormat, ArchiveDate } ); else Archived = ''; end if not utilities.is_set (OriginalURL) then utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (OriginalURL) then -- UrlStatus is empty, 'dead', 'unfit', 'usurped', 'bot: unknown' if utilities.in_array (UrlStatus, {'unfit', 'usurped', 'bot: unknown'}) then Archived = sepc .. ' ' .. utilities.substitute ( cs2_lower(cfg.messages['archived-unfit']), ArchiveDate); if 'bot: unknown' == UrlStatus then utilities.set_message ('maint_bot_unknown'); -- and add a category if not already added else utilities.add_prop_cat ('unfit'); -- and add a category if not already added end else -- UrlStatus is empty, 'dead' if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cs2_lower(cfg.messages['archived-dead']), { external_link( OriginalURL, cfg.messages['original'], OriginalURL_origin, OriginalAccess ) .. OriginalFormat, ArchiveDate } ); else Archived = ''; -- unset for concatenation end end else -- OriginalUrl not set utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (ArchiveFormat) then Archived = ArchiveFormat; -- if set and ArchiveURL not set ArchiveFormat has error message else Archived = ''; end local TranscriptURL = A['TranscriptURL'] local TranscriptFormat = A['TranscriptFormat']; TranscriptFormat = style_format (TranscriptFormat, TranscriptURL, 'transcript-format', 'transcripturl'); local Transcript = A['Transcript']; local TranscriptURL_origin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL if utilities.is_set (Transcript) then if utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, Transcript, TranscriptURL_origin, nil ); end Transcript = sepc .. ' ' .. Transcript .. TranscriptFormat; elseif utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, nil, TranscriptURL_origin, nil ); end local Publisher; if utilities.is_set (PublicationDate) then PublicationDate = wrap_msg ('published', PublicationDate); end if utilities.is_set (PublisherName) then if utilities.is_set (PublicationPlace) then Publisher = sepc .. " " .. PublicationPlace .. ": " .. PublisherName .. PublicationDate; else Publisher = sepc .. " " .. PublisherName .. PublicationDate; end elseif utilities.is_set (PublicationPlace) then Publisher= sepc .. " " .. PublicationPlace .. PublicationDate; else Publisher = PublicationDate; end -- Several of the above rely upon detecting this as nil, so do it last. if (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical)) then if utilities.is_set (Title) or utilities.is_set (TitleNote) then Periodical = sepc .. " " .. format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); else Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); end end local Language = A['Language']; if utilities.is_set (Language) then Language = language_parameter (Language); -- format, categories, name from ISO639-1, etc. else Language=''; -- language not specified so make sure this is an empty string; --[[ TODO: need to extract the wrap_msg from language_parameter so that we can solve parentheses bunching problem with Format/Language/TitleType ]] end --[[ Handle the oddity that is cite speech. This code overrides whatever may be the value assigned to TitleNote (through |department=) and forces it to be " (Speech)" so that the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided). ]] if "speech" == config.CitationClass then -- cite speech only TitleNote = TitleType; -- move TitleType to TitleNote so that it renders ahead of |event= TitleType = ''; -- and unset if utilities.is_set (Periodical) then -- if Periodical, perhaps because of an included |website= or |journal= parameter if utilities.is_set (Conference) then -- and if |event= is set Conference = Conference .. sepc .. " "; -- then add appropriate punctuation to the end of the Conference variable before rendering end end end -- Piece all bits together at last. Here, all should be non-nil. -- We build things this way because it is more efficient in LUA -- not to keep reassigning to the same string variable over and over. local tcommon; local tcommon2; -- used for book cite when |contributor= is set if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (Periodical) then -- special cases for book cites if utilities.is_set (Contributors) then -- when we are citing foreword, preface, introduction, etc. tcommon = safe_join ({Title, TitleNote}, sepc); -- author and other stuff will come after this and before tcommon2 tcommon2 = safe_join ({TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); else tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); end elseif 'map' == config.CitationClass then -- special cases for cite map if utilities.is_set (Chapter) then -- map in a book; TitleType is part of Chapter tcommon = safe_join ({Title, Edition, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); elseif utilities.is_set (Periodical) then -- map in a periodical tcommon = safe_join ({Title, TitleType, Periodical, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); else -- a sheet or stand-alone map tcommon = safe_join ({Title, TitleType, Edition, Scale, Series, Language, Cartography, Others, Publisher}, sepc); end elseif 'episode' == config.CitationClass then -- special case for cite episode tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Edition, Publisher}, sepc); else -- all other CS1 templates tcommon = safe_join ({Title, TitleNote, Conference, Periodical, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc); end if #ID_list > 0 then ID_list = safe_join( { sepc .. " ", table.concat( ID_list, sepc .. " " ), ID }, sepc ); else ID_list = ID; end local Via = A['Via']; Via = utilities.is_set (Via) and wrap_msg ('via', Via) or ''; local idcommon; if 'audio-visual' == config.CitationClass or 'episode' == config.CitationClass then -- special case for cite AV media & cite episode position transcript idcommon = safe_join( { ID_list, URL, Archived, Transcript, AccessDate, Via, Quote }, sepc ); else idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, Quote }, sepc ); end local text; local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; local OrigDate = A['OrigDate']; OrigDate = utilities.is_set (OrigDate) and wrap_msg ('origdate', OrigDate) or ''; if utilities.is_set (Date) then if utilities.is_set (Authors) or utilities.is_set (Editors) then -- date follows authors or editors when authors not set Date = " (" .. Date .. ")" .. OrigDate .. sepc .. " "; -- in parentheses else -- neither of authors and editors set if (string.sub(tcommon, -1, -1) == sepc) then -- if the last character of tcommon is sepc Date = " " .. Date .. OrigDate; -- Date does not begin with sepc else Date = sepc .. " " .. Date .. OrigDate; -- Date begins with sepc end end end if utilities.is_set (Authors) then if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Authors termination Authors = terminate_name_list (Authors, sepc); -- when no date, terminate with 0 or 1 sepc and a space end if utilities.is_set (Editors) then local in_text = ''; local post_text = ''; if utilities.is_set (Chapter) and 0 == #c then in_text = cfg.messages['in'] .. ' '; in_text = cs2_lower(in_text); -- lowercase for cs2 end if EditorCount <= 1 then post_text = ' (' .. cfg.messages['editor'] .. ')'; -- be consistent with no-author, no-date case else post_text = ' (' .. cfg.messages['editors'] .. ')'; end Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space end if utilities.is_set (Contributors) then -- book cite and we're citing the intro, preface, etc. local by_text = sepc .. ' ' .. cfg.messages['by'] .. ' '; by_text = cs2_lower(by_text); -- lowercase for cs2 Authors = by_text .. Authors; -- author follows title so tweak it here if utilities.is_set (Editors) and utilities.is_set (Date) then -- when Editors make sure that Authors gets terminated Authors = terminate_name_list (Authors, sepc); -- terminate with 0 or 1 sepc and a space end if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Contributors termination Contributors = terminate_name_list (Contributors, sepc); -- terminate with 0 or 1 sepc and a space end text = safe_join( {Contributors, Date, Chapter, tcommon, Authors, Place, Editors, tcommon2, pgtext, idcommon }, sepc ); else text = safe_join( {Authors, Date, Chapter, Place, Editors, tcommon, pgtext, idcommon }, sepc ); end elseif utilities.is_set (Editors) then if utilities.is_set (Date) then if EditorCount <= 1 then Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editor']; else Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editors']; end else if EditorCount <= 1 then Editors = Editors .. " (" .. cfg.messages['editor'] .. ")" .. sepc .. " " else Editors = Editors .. " (" .. cfg.messages['editors'] .. ")" .. sepc .. " " end end text = safe_join( {Editors, Date, Chapter, Place, tcommon, pgtext, idcommon}, sepc ); else if utilities.in_array (config.CitationClass, {"journal", "citation"}) and utilities.is_set (Periodical) then text = safe_join( {Chapter, Place, tcommon, pgtext, Date, idcommon}, sepc ); else text = safe_join( {Chapter, Place, tcommon, Date, pgtext, idcommon}, sepc ); end end if utilities.is_set (PostScript) and PostScript ~= sepc then text = safe_join( {text, sepc}, sepc ); -- Deals with italics, spaces, etc. if '.' == sepc then -- remove final seperator if present text = text:gsub ('%' .. sepc .. '$', ''); -- dot must be escaped here else text = mw.ustring.gsub (text, sepc .. '$', ''); -- using ustring for non-dot sepc (likely a non-Latin character) end end text = safe_join( {text, PostScript}, sepc ); -- Now enclose the whole thing in a <cite> element local options_t = {}; options_t.class = cite_class_attribute_make (config.CitationClass, Mode); local Ref = is_valid_parameter_value (A['Ref'], A:ORIGIN('Ref'), cfg.keywords_lists['ref'], nil, true); -- nil when |ref=harv; A['Ref'] else if 'none' ~= cfg.keywords_xlate[(Ref and Ref:lower()) or ''] then local namelist_t = {}; -- holds selected contributor, author, editor name list local year = first_set ({Year, anchor_year}, 2); -- Year first for legacy citations and for YMD dates that require disambiguation if #c > 0 then -- if there is a contributor list namelist_t = c; -- select it elseif #a > 0 then -- or an author list namelist_t = a; elseif #e > 0 then -- or an editor list namelist_t = e; end local citeref_id; if #namelist_t > 0 then -- if there are names in namelist_t citeref_id = make_citeref_id (namelist_t, year); -- go make the CITEREF anchor if mw.uri.anchorEncode (citeref_id) == ((Ref and mw.uri.anchorEncode (Ref)) or '') then -- Ref may already be encoded (by {{sfnref}}) so citeref_id must be encoded before comparison utilities.set_message ('maint_ref_duplicates_default'); end else citeref_id = ''; -- unset end options_t.id = Ref or citeref_id; end if string.len (text:gsub('%b<>', '')) <= 2 then -- remove html and html-like tags; then get length of what remains; z.error_cats_t = {}; -- blank the categories list z.error_msgs_t = {}; -- blank the error messages list OCinSoutput = nil; -- blank the metadata string text = ''; -- blank the the citation utilities.set_message ('err_empty_citation'); -- set empty citation message and category end local render_t = {}; -- here we collect the final bits for concatenation into the rendered citation if is_preview_mode then -- when in preview mode if not utilities.is_set (options_t.id) then -- and when this template has not created an anchor ID math.randomseed (tonumber (mw.getLanguage ('en'):formatDate ('U')) * 10000 + os.clock() * 10000); options_t.id = 'CITEREF_temp_preview_id_' .. math.random (100000, 999999); -- create temporary anchor ID for preview mode end end if utilities.is_set (options_t.id) then -- here we wrap the rendered citation in <cite ...>...</cite> tags options_t.id = mw.uri.anchorEncode(options_t.id); -- do this here; also used when adding preview warning messages table.insert (render_t, utilities.substitute (cfg.presentation['cite-id'], {options_t.id, mw.text.nowiki(options_t.class), text})); -- when |ref= is set or when there is a namelist else table.insert (render_t, utilities.substitute (cfg.presentation['cite'], {mw.text.nowiki(options_t.class), text})); -- when |ref=none or when namelist_t empty and |ref= is missing or is empty end if OCinSoutput then -- blanked when citation is 'empty' so don't bother to add boilerplate metadata span table.insert (render_t, utilities.substitute (cfg.presentation['ocins'], OCinSoutput)); -- format and append metadata to the citation end local template_name = cfg.citation_class_map_t[config.CitationClass]; local template_link = '[[Template:' .. template_name .. '|' .. template_name .. ']]'; local msg_prefix = '<code class="cs1-code">{{' .. template_link .. '}}</code>: '; --local warn_link = '[[#' .. options_t.id .. ']]'; if 0 ~= #z.error_msgs_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_e, {template_link, options_t.id})); table.insert (render_t, ' '); -- insert a space between citation and its error messages table.sort (z.error_msgs_t); -- sort the error messages list; sorting includes wrapping <span> and <code> tags; hidden-error sorts ahead of visible-error local hidden = true; -- presume that the only error messages emited by this template are hidden for _, v in ipairs (z.error_msgs_t) do -- spin through the list of error messages if v:find ('cs1-visible-error', 1, true) then -- look for the visible error class name hidden = false; -- found one; so don't hide the error message prefix break; -- and done because no need to look further end end z.error_msgs_t[1] = table.concat ({utilities.error_comment (msg_prefix, hidden), z.error_msgs_t[1]}); -- add error message prefix to first error message to prevent extraneous punctuation table.insert (render_t, table.concat (z.error_msgs_t, '; ')); -- make a big string of error messages and add it to the rendering end if 0 ~= #z.maint_cats_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_m, {template_link, options_t.id})); table.sort (z.maint_cats_t); -- sort the maintenance messages list local maint_msgs_t = {}; -- here we collect all of the maint messages if 0 == #z.error_msgs_t then -- if no error messages table.insert (maint_msgs_t, msg_prefix); -- insert message prefix in maint message livery end for _, v in ipairs( z.maint_cats_t ) do -- append maintenance categories table.insert (maint_msgs_t, -- assemble new maint message and add it to the maint_msgs_t table table.concat ({v, ' (', utilities.substitute (cfg.messages[':cat wikilink'], v), ')'}) ); end table.insert (render_t, utilities.substitute (cfg.presentation['hidden-maint'], table.concat (maint_msgs_t, ' '))); -- wrap the group of maint messages with proper presentation and save end if not no_tracking_cats then local sort_key; local cat_wikilink = 'cat wikilink'; if cfg.enable_sort_keys then -- when namespace sort keys enabled local namespace_number = mw.title.getCurrentTitle().namespace; -- get namespace number for this wikitext sort_key = (0 ~= namespace_number and (cfg.name_space_sort_keys[namespace_number] or cfg.name_space_sort_keys.other)) or nil; -- get sort key character; nil for mainspace cat_wikilink = (not sort_key and 'cat wikilink') or 'cat wikilink sk'; -- make <cfg.messages> key end for _, v in ipairs (z.error_cats_t) do -- append error categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end if cfg.id_limits_data_load_fail then -- boolean true when load failed utilities.set_message ('maint_id_limit_load_fail'); -- done here because this maint cat emits no message end for _, v in ipairs (z.maint_cats_t) do -- append maintenance categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end for _, v in ipairs (z.prop_cats_t) do -- append properties categories table.insert (render_t, utilities.substitute (cfg.messages['cat wikilink'], v)); -- no sort keys end end return table.concat (render_t); -- make a big string and done end --[[--------------------------< V A L I D A T E >-------------------------------------------------------------- Looks for a parameter's name in one of several whitelists. Parameters in the whitelist can have three values: true - active, supported parameters false - deprecated, supported parameters nil - unsupported parameters ]] local function validate (name, cite_class, empty) local name = tostring (name); local enum_name; -- parameter name with enumerator (if any) replaced with '#' local state; local function state_test (state, name) -- local function to do testing of state values if true == state then return true; end -- valid actively supported parameter if false == state then if empty then return nil; end -- empty deprecated parameters are treated as unknowns deprecated_parameter (name); -- parameter is deprecated but still supported return true; end if 'tracked' == state then local base_name = name:gsub ('%d', ''); -- strip enumerators from parameter names that have them to get the base name utilities.add_prop_cat ('tracked-param', {base_name}, base_name); -- add a properties category; <base_name> modifies <key> return true; end return nil; end if name:find ('#') then -- # is a cs1|2 reserved character so parameters with # not permitted return nil; end -- replace enumerator digit(s) with # (|last25= becomes |last#=) (mw.ustring because non-Western 'local' digits) enum_name = mw.ustring.gsub (name, '%d+$', '#'); -- where enumerator is last charaters in parameter name (these to protect |s2cid=) enum_name = mw.ustring.gsub (enum_name, '%d+([%-l])', '#%1'); -- where enumerator is in the middle of the parameter name; |author#link= is the oddity if 'document' == cite_class then -- special case for {{cite document}} state = whitelist.document_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end return false; end if utilities.in_array (cite_class, whitelist.preprint_template_list_t) then -- limited parameter sets allowed for these templates state = whitelist.limited_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end state = whitelist.preprint_arguments_t[cite_class][name]; -- look in the parameter-list for the template identified by cite_class if true == state_test (state, name) then return true; end return false; -- not supported because not found or name is set to nil end -- end limited parameter-set templates if utilities.in_array (cite_class, whitelist.unique_param_template_list_t) then -- template-specific parameters for templates that accept parameters from the basic argument list state = whitelist.unique_arguments_t[cite_class][name]; -- look in the template-specific parameter-lists for the template identified by cite_class if true == state_test (state, name) then return true; end end -- if here, fall into general validation state = whitelist.common_parameters_t[enum_name]; -- all other templates; all normal parameters allowed; this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end return false; -- not supported because not found or name is set to nil end --[=[-------------------------< I N T E R _ W I K I _ C H E C K >---------------------------------------------- check <value> for inter-language interwiki-link markup. <prefix> must be a MediaWiki-recognized language code. when these values have the form (without leading colon): [[<prefix>:link|label]] return label as plain-text [[<prefix>:link]] return <prefix>:link as plain-text return value as is else ]=] local function inter_wiki_check (parameter, value) local prefix = value:match ('%[%[(%a+):'); -- get an interwiki prefix if one exists local _; if prefix and cfg.inter_wiki_map[prefix:lower()] then -- if prefix is in the map, needs preceding colon so utilities.set_message ('err_bad_paramlink', parameter); -- emit an error message _, value, _ = utilities.is_wikilink (value); -- extract label portion from wikilink end return value; end --[[--------------------------< M I S S I N G _ P I P E _ C H E C K >------------------------------------------ Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal sign, compare the alphanumeric string to the list of cs1|2 parameters. If found, then the string is possibly a parameter that is missing its pipe. There are two tests made: {{cite ... |title=Title access-date=2016-03-17}} -- the first parameter has a value and whitespace separates that value from the missing pipe parameter name {{cite ... |title=access-date=2016-03-17}} -- the first parameter has no value (whitespace after the first = is trimmed by MediaWiki) cs1|2 shares some parameter names with XML/HTML attributes: class=, title=, etc. To prevent false positives XML/HTML tags are removed before the search. If a missing pipe is detected, this function adds the missing pipe maintenance category. ]] local function missing_pipe_check (parameter, value) local capture; value = value:gsub ('%b<>', ''); -- remove XML/HTML tags because attributes: class=, title=, etc. capture = value:match ('%s+(%a[%w%-]+)%s*=') or value:match ('^(%a[%w%-]+)%s*='); -- find and categorize parameters with possible missing pipes if capture and validate (capture) then -- if the capture is a valid parameter name utilities.set_message ('err_missing_pipe', parameter); end end --[[--------------------------< H A S _ E X T R A N E O U S _ P U N C T >-------------------------------------- look for extraneous terminal punctuation in most parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_punc (param, value) if 'number' == type (param) then return; end param = param:gsub ('%d+', '#'); -- enumerated name-list mask params allow terminal punct; normalize if cfg.punct_skip[param] then return; -- parameter name found in the skip table so done end if value:match ('[,;:]$') then utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end if value:match ('^=') then -- sometimes an extraneous '=' character appears ... utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end end --[[--------------------------< H A S _ T W L _ U R L >-------------------------------------------------------- look for The Wikipedia Library urls in url-holding parameters. TWL urls are accessible only for readers who are active extended confirmed Wikipedia editors. This function sets an error message when such urls are discovered and when appropriate, sets the |<param>-url-access=subscription. returns nothing. looks for: '.wikipedialibrary.idm.oclc.org' ]] local function has_twl_url (url_params_t, cite_args_t) local url_error_t = {}; -- sequence of url-holding parameters that have a TWL url for param, value in pairs (url_params_t) do if value:find ('%.wikipedialibrary%.idm%.oclc%.org') then -- has the TWL base url? table.insert (url_error_t, param); -- add parameter name to the error list end end if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); -- sor for error messaging for i, param in ipairs (url_error_t) do if cfg.url_access_map_t[param] then -- if <param> has a matching -access parameter cite_args_t[cfg.url_access_map_t[param]] = cfg.keywords_xlate.subscription; -- set |<param>-url-access=subscription end url_error_t[i] = utilities.wrap_style ('parameter', param); -- make the parameter pretty for error message end utilities.set_message ('err_param_has_twl_url', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< H A S _ E X T R A N E O U S _ U R L >------------------------------------------ look for extraneous url parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_url (non_url_param_t) local url_error_t = {}; check_for_url (non_url_param_t, url_error_t); -- extraneous url check if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); utilities.set_message ('err_param_has_ext_link', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< _ C I T A T I O N >------------------------------------------------------------ Module entry point frame – from template call (citation()); may be nil when called from another module args_t – table of all cs1|2 parameters in the template (the parent frame) config_t – table of template-supplied parameter (the #invoke frame) ]] local function _citation (frame, args_t, config_t) -- save a copy in case we need to display an error message in preview mode if not frame then frame = mw.getCurrentFrame(); -- if called from another module, get a frame for frame-provided functions end -- i18n: set the name that your wiki uses to identify sandbox subpages from sandbox template invoke (or can be set here) local sandbox = ((config_t.SandboxPath and '' ~= config_t.SandboxPath) and config_t.SandboxPath) or '/sandbox'; -- sandbox path from {{#invoke:Citation/CS1/sandbox|citation|SandboxPath=/...}} is_sandbox = nil ~= string.find (frame:getTitle(), sandbox, 1, true); -- is this invoke the sandbox module? sandbox = is_sandbox and sandbox or ''; -- use i18n sandbox to load sandbox modules when this module is the sandox; live modules else cfg = mw.loadData ('Module:Citation/CS1/Configuration' .. sandbox); -- load sandbox versions of support modules when {{#invoke:Citation/CS1/sandbox|...}}; live modules else whitelist = mw.loadData ('Module:Citation/CS1/Whitelist' .. sandbox); utilities = require ('Module:Citation/CS1/Utilities' .. sandbox); validation = require ('Module:Citation/CS1/Date_validation' .. sandbox); identifiers = require ('Module:Citation/CS1/Identifiers' .. sandbox); metadata = require ('Module:Citation/CS1/COinS' .. sandbox); utilities.set_selected_modules (cfg); -- so that functions in Utilities can see the selected cfg tables identifiers.set_selected_modules (cfg, utilities); -- so that functions in Identifiers can see the selected cfg tables and selected Utilities module validation.set_selected_modules (cfg, utilities); -- so that functions in Date validataion can see selected cfg tables and the selected Utilities module metadata.set_selected_modules (cfg, utilities); -- so that functions in COinS can see the selected cfg tables and selected Utilities module z = utilities.z; -- table of error and category tables in Module:Citation/CS1/Utilities local cite_args_t = {}; -- because args_t is the parent (template) frame args (which cannot be modified); params and their values will be placed here is_preview_mode = not utilities.is_set (frame:preprocess ('{{REVISIONID}}')); local suggestions = {}; -- table where we store suggestions if we need to loadData them local error_text; -- used as a flag local capture; -- the single supported capture when matching unknown parameters using patterns local empty_unknowns = {}; -- sequence table to hold empty unknown params for error message listing for k, v in pairs (args_t) do -- get parameters from the parent (template) frame v = mw.ustring.gsub (v, '^%s*(.-)%s*$', '%1'); -- trim leading/trailing whitespace; when v is only whitespace, becomes empty string if v ~= '' then if ('string' == type (k)) then k = mw.ustring.gsub (k, '%d', cfg.date_names.local_digits); -- for enumerated parameters, translate 'local' digits to Western 0-9 end if not validate( k, config_t.CitationClass ) then if type (k) ~= 'string' then -- exclude empty numbered parameters if v:match("%S+") ~= nil then error_text = utilities.set_message ('err_text_ignored', {v}); end elseif validate (k:lower(), config_t.CitationClass) then error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, k:lower()}); -- suggest the lowercase version of the parameter else if nil == suggestions.suggestions then -- if this table is nil then we need to load it suggestions = mw.loadData ('Module:Citation/CS1/Suggestions' .. sandbox); --load sandbox version of suggestion module when {{#invoke:Citation/CS1/sandbox|...}}; live module else end for pattern, param in pairs (suggestions.patterns) do -- loop through the patterns to see if we can suggest a proper parameter capture = k:match (pattern); -- the whole match if no capture in pattern else the capture if a match if capture then -- if the pattern matches param = utilities.substitute (param, capture); -- add the capture to the suggested parameter (typically the enumerator) if validate (param, config_t.CitationClass) then -- validate the suggestion to make sure that the suggestion is supported by this template (necessary for limited parameter lists) error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, param}); -- set the suggestion error message else error_text = utilities.set_message ('err_parameter_ignored', {k}); -- suggested param not supported by this template v = ''; -- unset end end end if not utilities.is_set (error_text) then -- couldn't match with a pattern, is there an explicit suggestion? if (suggestions.suggestions[ k:lower() ] ~= nil) and validate (suggestions.suggestions[ k:lower() ], config_t.CitationClass) then utilities.set_message ('err_parameter_ignored_suggest', {k, suggestions.suggestions[ k:lower() ]}); else utilities.set_message ('err_parameter_ignored', {k}); v = ''; -- unset value assigned to unrecognized parameters (this for the limited parameter lists) end end end end cite_args_t[k] = v; -- save this parameter and its value elseif not utilities.is_set (v) then -- for empty parameters if not validate (k, config_t.CitationClass, true) then -- is this empty parameter a valid parameter k = ('' == k) and cfg.err_msg_supl.empty_str or k; -- when k is empty string (or was space(s) trimmed to empty string), replace with descriptive text table.insert (empty_unknowns, utilities.wrap_style ('parameter', k)); -- format for error message and add to the list end end end if 0 ~= #empty_unknowns then -- create empty unknown error message utilities.set_message ('err_param_unknown_empty', { 1 == #empty_unknowns and '' or 's', utilities.make_sep_list (#empty_unknowns, empty_unknowns) }); end local non_url_param_t = {}; -- table of parameters and values that are not url-holding parameters local url_param_t = {}; -- table of url-holding paramters and their values for k, v in pairs (cite_args_t) do if 'string' == type (k) then -- don't evaluate positional parameters has_invisible_chars (k, v); -- look for invisible characters end has_extraneous_punc (k, v); -- look for extraneous terminal punctuation in parameter values missing_pipe_check (k, v); -- do we think that there is a parameter that is missing a pipe? cite_args_t[k] = inter_wiki_check (k, v); -- when language interwiki-linked parameter missing leading colon replace with wiki-link label if 'string' == type (k) then -- when parameter k is not positional if not cfg.url_skip[k] then -- and not in url skip table non_url_param_t[k] = v; -- make a parameter/value list for extraneous url check else -- and is in url skip table (a url-holding parameter) url_param_t[k] = v; -- make a parameter/value list to check for values that are The Wikipedia Library url end end end has_extraneous_url (non_url_param_t); -- look for url in parameter values where a url does not belong has_twl_url (url_param_t, cite_args_t); -- look for url-holding parameters that hold a The Wikipedia Library url return table.concat ({ frame:extensionTag ('templatestyles', '', {src='Module:Citation/CS1' .. sandbox .. '/styles.css'}), citation0 (config_t, cite_args_t) }); end --[[--------------------------< C I T A T I O N >-------------------------------------------------------------- Template entry point ]] local function citation (frame) local config_t = {}; -- table to store parameters from the module {{#invoke:}} local args_t = frame:getParent().args; -- get template's preset parameters for k, v in pairs (frame.args) do -- get parameters from the {{#invoke}} frame config_t[k] = v; -- args_t[k] = v; -- crude debug support that allows us to render a citation from module {{#invoke:}}; skips parameter validation; TODO: keep? end return _citation (frame, args_t, config_t) end --[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------ ]] return { citation = citation, -- template entry point _citation = _citation, -- module entry point } b6icf6so4rruzgetip2bn0h321incx1 736732 736731 2026-01-17T19:44:59Z en>Trappist the monk 0 736732 Scribunto text/plain require ('strict'); --[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- each of these counts against the Lua upvalue limit ]] local validation; -- functions in Module:Citation/CS1/Date_validation local utilities; -- functions in Module:Citation/CS1/Utilities local z = {}; -- table of tables in Module:Citation/CS1/Utilities local identifiers; -- functions and tables in Module:Citation/CS1/Identifiers local metadata; -- functions in Module:Citation/CS1/COinS local cfg = {}; -- table of configuration tables that are defined in Module:Citation/CS1/Configuration local whitelist = {}; -- table of tables listing valid template parameter names; defined in Module:Citation/CS1/Whitelist --[[------------------< P A G E S C O P E V A R I A B L E S >--------------- declare variables here that have page-wide scope that are not brought in from other modules; that are created here and used here ]] local added_deprecated_cat; -- Boolean flag so that the category is added only once local added_vanc_errs; -- Boolean flag so we only emit one Vancouver error / category local added_generic_name_errs; -- Boolean flag so we only emit one generic name error / category and stop testing names once an error is encountered local added_numeric_name_errs; -- Boolean flag so we only emit one numeric name error / category and stop testing names once an error is encountered local added_numeric_name_maint; -- Boolean flag so we only emit one numeric name maint category and stop testing names once a category has been emitted local is_preview_mode; -- true when article is in preview mode; false when using 'Preview page with this template' (previewing the module) local is_sandbox; -- true when using sandbox modules to render citation --[[--------------------------< F I R S T _ S E T >------------------------------------------------------------ Locates and returns the first set value in a table of values where the order established in the table, left-to-right (or top-to-bottom), is the order in which the values are evaluated. Returns nil if none are set. This version replaces the original 'for _, val in pairs do' and a similar version that used ipairs. With the pairs version the order of evaluation could not be guaranteed. With the ipairs version, a nil value would terminate the for-loop before it reached the actual end of the list. ]] local function first_set (list, count) local i = 1; while i <= count do -- loop through all items in list if utilities.is_set( list[i] ) then return list[i]; -- return the first set list member end i = i + 1; -- point to next end end --[[--------------------------< A D D _ V A N C _ E R R O R >---------------------------------------------------- Adds a single Vancouver system error message to the template's output regardless of how many error actually exist. To prevent duplication, added_vanc_errs is nil until an error message is emitted. added_vanc_errs is a Boolean declared in page scope variables above ]] local function add_vanc_error (source, position) if added_vanc_errs then return end added_vanc_errs = true; -- note that we've added this category utilities.set_message ('err_vancouver', {source, position}); end --[[--------------------------< I S _ S C H E M E >------------------------------------------------------------ does this thing that purports to be a URI scheme seem to be a valid scheme? The scheme is checked to see if it is in agreement with http://tools.ietf.org/html/std66#section-3.1 which says: Scheme names consist of a sequence of characters beginning with a letter and followed by any combination of letters, digits, plus ("+"), period ("."), or hyphen ("-"). returns true if it does, else false ]] local function is_scheme (scheme) return scheme and scheme:match ('^%a[%a%d%+%.%-]*:'); -- true if scheme is set and matches the pattern end --[=[-------------------------< I S _ D O M A I N _ N A M E >-------------------------------------------------- Does this thing that purports to be a domain name seem to be a valid domain name? Syntax defined here: http://tools.ietf.org/html/rfc1034#section-3.5 BNF defined here: https://tools.ietf.org/html/rfc4234 Single character names are generally reserved; see https://tools.ietf.org/html/draft-ietf-dnsind-iana-dns-01#page-15; see also [[Single-letter second-level domain]] list of TLDs: https://www.iana.org/domains/root/db RFC 952 (modified by RFC 1123) requires the first and last character of a hostname to be a letter or a digit. Between the first and last characters the name may use letters, digits, and the hyphen. Also allowed are IPv4 addresses. IPv6 not supported domain is expected to be stripped of any path so that the last character in the last character of the TLD. tld is two or more alpha characters. Any preceding '//' (from splitting a URL with a scheme) will be stripped here. Perhaps not necessary but retained in case it is necessary for IPv4 dot decimal. There are several tests: the first character of the whole domain name including subdomains must be a letter or a digit internationalized domain name (ASCII characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the TLD) see https://tools.ietf.org/html/rfc3490 single-letter/digit second-level domains in the .org, .cash, and .today TLDs q, x, and z SL domains in the .com TLD i and q SL domains in the .net TLD single-letter SL domains in the ccTLDs (where the ccTLD is two letters) two-character SL domains in gTLDs (where the gTLD is two or more letters) three-plus-character SL domains in gTLDs (where the gTLD is two or more letters) IPv4 dot-decimal address format; TLD not allowed returns true if domain appears to be a proper name and TLD or IPv4 address, else false ]=] local function is_domain_name (domain) if not domain then return false; -- if not set, abandon end domain = domain:gsub ('^//', ''); -- strip '//' from domain name if present; done here so we only have to do it once if not domain:match ('^[%w]') then -- first character must be letter or digit return false; end if domain:match ('^%a+:') then -- hack to detect things that look like s:Page:Title where Page: is namespace at Wikisource return false; end local patterns = { -- patterns that look like URLs '%f[%w][%w][%w%-]+[%w]%.%a%a+$', -- three or more character hostname.hostname or hostname.tld '%f[%w][%w][%w%-]+[%w]%.xn%-%-[%w]+$', -- internationalized domain name with ACE prefix '%f[%a][qxz]%.com$', -- assigned one character .com hostname (x.com times out 2015-12-10) '%f[%a][iq]%.net$', -- assigned one character .net hostname (q.net registered but not active 2015-12-10) '%f[%w][%w]%.%a%a$', -- one character hostname and ccTLD (2 chars) '%f[%w][%w][%w]%.%a%a+$', -- two character hostname and TLD '^%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?', -- IPv4 address '[%a%d]+%:?' -- IPv6 address } for _, pattern in ipairs (patterns) do -- loop through the patterns list if domain:match (pattern) then return true; -- if a match then we think that this thing that purports to be a URL is a URL end end for _, d in ipairs (cfg.single_letter_2nd_lvl_domains_t) do -- look for single letter second level domain names for these top level domains if domain:match ('%f[%w][%w]%.' .. d) then return true end end return false; -- no matches, we don't know what this thing is end --[[--------------------------< I S _ U R L >------------------------------------------------------------------ returns true if the scheme and domain parts of a URL appear to be a valid URL; else false. This function is the last step in the validation process. This function is separate because there are cases that are not covered by split_url(), for example is_parameter_ext_wikilink() which is looking for bracketted external wikilinks. ]] local function is_url (scheme, domain) if utilities.is_set (scheme) then -- if scheme is set check it and domain return is_scheme (scheme) and is_domain_name (domain); else return is_domain_name (domain); -- scheme not set when URL is protocol-relative end end --[[--------------------------< S P L I T _ U R L >------------------------------------------------------------ Split a URL into a scheme, authority indicator, and domain. First remove Fully Qualified Domain Name terminator (a dot following TLD) (if any) and any path(/), query(?) or fragment(#). If protocol-relative URL, return nil scheme and domain else return nil for both scheme and domain. When not protocol-relative, get scheme, authority indicator, and domain. If there is an authority indicator (one or more '/' characters immediately following the scheme's colon), make sure that there are only 2. Any URL that does not have news: scheme must have authority indicator (//). TODO: are there other common schemes like news: that don't use authority indicator? Strip off any port and path; ]] local function split_url (url_str) local scheme, authority, domain; url_str = url_str:gsub ('([%a%d])%.?[/%?#].*$', '%1'); -- strip FQDN terminator and path(/), query(?), fragment (#) (the capture prevents false replacement of '//') if url_str:match ('^//%S*') then -- if there is what appears to be a protocol-relative URL domain = url_str:match ('^//(%S*)') elseif url_str:match ('%S-:/*%S+') then -- if there is what appears to be a scheme, optional authority indicator, and domain name scheme, authority, domain = url_str:match ('(%S-:)(/*)(%S+)'); -- extract the scheme, authority indicator, and domain portions if utilities.is_set (authority) then authority = authority:gsub ('//', '', 1); -- replace place 1 pair of '/' with nothing; if utilities.is_set(authority) then -- if anything left (1 or 3+ '/' where authority should be) then return scheme; -- return scheme only making domain nil which will cause an error message end else if not scheme:match ('^news:') then -- except for news:..., MediaWiki won't link URLs that do not have authority indicator; TODO: a better way to do this test? return scheme; -- return scheme only making domain nil which will cause an error message end end domain = domain:gsub ('(%a):%d+', '%1'); -- strip port number if present end return scheme, domain; end --[[--------------------------< L I N K _ P A R A M _ O K >--------------------------------------------------- checks the content of |title-link=, |series-link=, |author-link=, etc. for properly formatted content: no wikilinks, no URLs Link parameters are to hold the title of a Wikipedia article, so none of the WP:TITLESPECIALCHARACTERS are allowed: # < > [ ] | { } _ except the underscore which is used as a space in wiki URLs and # which is used for section links returns false when the value contains any of these characters. When there are no illegal characters, this function returns TRUE if value DOES NOT appear to be a valid URL (the |<param>-link= parameter is ok); else false when value appears to be a valid URL (the |<param>-link= parameter is NOT ok). ]] local function link_param_ok (value) local scheme, domain; if value:find ('[<>%[%]|{}]') then -- if any prohibited characters return false; end scheme, domain = split_url (value); -- get scheme or nil and domain or nil from URL; return not is_url (scheme, domain); -- return true if value DOES NOT appear to be a valid URL end --[[--------------------------< L I N K _ T I T L E _ O K >--------------------------------------------------- Use link_param_ok() to validate |<param>-link= value and its matching |<title>= value. |<title>= may be wiki-linked but not when |<param>-link= has a value. This function emits an error message when that condition exists check <link> for inter-language interwiki-link prefix. prefix must be a MediaWiki-recognized language code and must begin with a colon. ]] local function link_title_ok (link, lorig, title, torig) local orig; if utilities.is_set (link) then -- don't bother if <param>-link doesn't have a value if not link_param_ok (link) then -- check |<param>-link= markup orig = lorig; -- identify the failing link parameter elseif title:find ('%[%[') then -- check |title= for wikilink markup orig = torig; -- identify the failing |title= parameter elseif link:match ('^%a+:') then -- if the link is what looks like an interwiki local prefix = link:match ('^(%a+):'):lower(); -- get the interwiki prefix if cfg.inter_wiki_map[prefix] then -- if prefix is in the map, must have preceding colon orig = lorig; -- flag as error end end end if utilities.is_set (orig) then link = ''; -- unset utilities.set_message ('err_bad_paramlink', orig); -- URL or wikilink in |title= with |title-link=; end return link; -- link if ok, empty string else end --[[--------------------------< C H E C K _ U R L >------------------------------------------------------------ Determines whether a URL string appears to be valid. First we test for space characters. If any are found, return false. Then split the URL into scheme and domain portions, or for protocol-relative (//example.com) URLs, just the domain. Use is_url() to validate the two portions of the URL. If both are valid, or for protocol-relative if domain is valid, return true, else false. Because it is different from a standard URL, and because this module used external_link() to make external links that work for standard and news: links, we validate newsgroup names here. The specification for a newsgroup name is at https://tools.ietf.org/html/rfc5536#section-3.1.4 ]] local function check_url( url_str ) if nil == url_str:match ("^%S+$") then -- if there are any spaces in |url=value it can't be a proper URL return false; end local scheme, domain; scheme, domain = split_url (url_str); -- get scheme or nil and domain or nil from URL; if 'news:' == scheme then -- special case for newsgroups return domain:match('^[%a%d%+%-_]+%.[%a%d%+%-_%.]*[%a%d%+%-_]$'); end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[=[-------------------------< I S _ P A R A M E T E R _ E X T _ W I K I L I N K >---------------------------- Return true if a parameter value has a string that begins and ends with square brackets [ and ] and the first non-space characters following the opening bracket appear to be a URL. The test will also find external wikilinks that use protocol-relative URLs. Also finds bare URLs. The frontier pattern prevents a match on interwiki-links which are similar to scheme:path URLs. The tests that find bracketed URLs are required because the parameters that call this test (currently |title=, |chapter=, |work=, and |publisher=) may have wikilinks and there are articles or redirects like '//Hus' so, while uncommon, |title=[[//Hus]] is possible as might be [[en://Hus]]. ]=] local function is_parameter_ext_wikilink (value) local scheme, domain; if value:match ('%f[%[]%[%a%S*:%S+.*%]') then -- if ext. wikilink with scheme and domain: [xxxx://yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(%a%S*:%S+).*%]')); elseif value:match ('%f[%[]%[//%S+.*%]') then -- if protocol-relative ext. wikilink: [//yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(//%S+).*%]')); elseif value:match ('%a%S*:%S+') then -- if bare URL with scheme; may have leading or trailing plain text scheme, domain = split_url (value:match ('(%a%S*:%S+)')); elseif value:match ('^//%S+') or value:match ('%s//%S+') then -- if protocol-relative bare URL: //yyyyy.zzz; authority indicator (//) must be be preceded nothing or by whitespace scheme, domain = split_url (value:match ('(//%S+)')); -- what is left should be the domain else return false; -- didn't find anything that is obviously a URL end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[[-------------------------< C H E C K _ F O R _ U R L >----------------------------------------------------- loop through a list of parameters and their values. Look at the value and if it has an external link, emit an error message. ]] local function check_for_url (parameter_list, error_list) for k, v in pairs (parameter_list) do -- for each parameter in the list if is_parameter_ext_wikilink (v) then -- look at the value; if there is a URL add an error message table.insert (error_list, utilities.wrap_style ('parameter', k)); end end end --[[--------------------------< S A F E _ F O R _ U R L >------------------------------------------------------ Escape sequences for content that will be used for URL descriptions ]] local function safe_for_url( str ) if str:match( "%[%[.-%]%]" ) ~= nil then utilities.set_message ('err_wikilink_in_url', {}); end return str:gsub( '[%[%]\n]', { ['['] = '&#91;', [']'] = '&#93;', ['\n'] = ' ' } ); end --[[--------------------------< E X T E R N A L _ L I N K >---------------------------------------------------- Format an external link with error checking ]] local function external_link (URL, label, source, access) local err_msg = ''; local domain; local path; local base_url; if not utilities.is_set (label) then label = URL; if utilities.is_set (source) then utilities.set_message ('err_bare_url_missing_title', {utilities.wrap_style ('parameter', source)}); else error (cfg.messages["bare_url_no_origin"]); -- programmer error; valid parameter name does not have matching meta-parameter end end if not check_url (URL) then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); end domain, path = URL:match ('^([/%.%-%+:%a%d]+)([/%?#].*)$'); -- split the URL into scheme plus domain and path if path then -- if there is a path portion path = path:gsub ('[%[%]]', {['['] = '%5b', [']'] = '%5d'}); -- replace '[' and ']' with their percent-encoded values URL = table.concat ({domain, path}); -- and reassemble end base_url = table.concat ({ "[", URL, " ", safe_for_url (label), "]" }); -- assemble a wiki-markup URL if utilities.is_set (access) then -- access level (subscription, registration, limited) base_url = utilities.substitute (cfg.presentation['ext-link-access-signal'], {cfg.presentation[access].class, cfg.presentation[access].title, base_url}); -- add the appropriate icon end return base_url; end --[[--------------------------< D E P R E C A T E D _ P A R A M E T E R >-------------------------------------- Categorize and emit an error message when the citation contains one or more deprecated parameters. The function includes the offending parameter name to the error message. Only one error message is emitted regardless of the number of deprecated parameters in the citation. added_deprecated_cat is a Boolean declared in page scope variables above ]] local function deprecated_parameter(name) if not added_deprecated_cat then added_deprecated_cat = true; -- note that we've added this category utilities.set_message ('err_deprecated_params', {name}); -- add error message end end --[=[-------------------------< K E R N _ Q U O T E S >-------------------------------------------------------- Apply kerning to open the space between the quote mark provided by the module and a leading or trailing quote mark contained in a |title= or |chapter= parameter's value. This function will positive kern either single or double quotes: "'Unkerned title with leading and trailing single quote marks'" " 'Kerned title with leading and trailing single quote marks' " (in real life the kerning isn't as wide as this example) Double single quotes (italic or bold wiki-markup) are not kerned. Replaces Unicode quote marks in plain text or in the label portion of a [[L|D]] style wikilink with typewriter quote marks regardless of the need for kerning. Unicode quote marks are not replaced in simple [[D]] wikilinks. Call this function for chapter titles, for website titles, etc.; not for book titles. ]=] local function kern_quotes (str) local cap = ''; local wl_type, label, link; wl_type, label, link = utilities.is_wikilink (str); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] if 1 == wl_type then -- [[D]] simple wikilink with or without quote marks if mw.ustring.match (str, '%[%[[\"“”\'‘’].+[\"“”\'‘’]%]%]') then -- leading and trailing quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); str = utilities.substitute (cfg.presentation['kern-right'], str); elseif mw.ustring.match (str, '%[%[[\"“”\'‘’].+%]%]') then -- leading quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); elseif mw.ustring.match (str, '%[%[.+[\"“”\'‘’]%]%]') then -- trailing quote marks str = utilities.substitute (cfg.presentation['kern-right'], str); end else -- plain text or [[L|D]]; text in label variable label = mw.ustring.gsub (label, '[“”]', '\"'); -- replace “” (U+201C & U+201D) with " (typewriter double quote mark) label = mw.ustring.gsub (label, '[‘’]', '\''); -- replace ‘’ (U+2018 & U+2019) with ' (typewriter single quote mark) cap = mw.ustring.match (label, "^([\"\'][^\'].+)"); -- match leading double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-left'], cap); end cap = mw.ustring.match (label, "^(.+[^\'][\"\'])$") -- match trailing double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-right'], cap); end if 2 == wl_type then str = utilities.make_wikilink (link, label); -- reassemble the wikilink else str = label; end end return str; end --[[--------------------------< F O R M A T _ S C R I P T _ V A L U E >---------------------------------------- |script-title= holds title parameters that are not written in Latin-based scripts: Chinese, Japanese, Arabic, Hebrew, etc. These scripts should not be italicized and may be written right-to-left. The value supplied by |script-title= is concatenated onto Title after Title has been wrapped in italic markup. Regardless of language, all values provided by |script-title= are wrapped in <bdi>...</bdi> tags to isolate RTL languages from the English left to right. |script-title= provides a unique feature. The value in |script-title= may be prefixed with a two-character ISO 639-1 language code and a colon: |script-title=ja:*** *** (where * represents a Japanese character) Spaces between the two-character code and the colon and the colon and the first script character are allowed: |script-title=ja : *** *** |script-title=ja: *** *** |script-title=ja :*** *** Spaces preceding the prefix are allowed: |script-title = ja:*** *** The prefix is checked for validity. If it is a valid ISO 639-1 language code, the lang attribute (lang="ja") is added to the <bdi> tag so that browsers can know the language the tag contains. This may help the browser render the script more correctly. If the prefix is invalid, the lang attribute is not added. At this time there is no error message for this condition. Supports |script-title=, |script-chapter=, |script-<periodical>= ]] local function format_script_value (script_value, script_param) local lang=''; -- initialize to empty string local name; if script_value:match('^%l%l%l?%s*:') then -- if first 3 or 4 non-space characters are script language prefix lang = script_value:match('^(%l%l%l?)%s*:%s*%S.*'); -- get the language prefix or nil if there is no script if not utilities.is_set (lang) then utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing title part']}); -- prefix without 'title'; add error message return ''; -- script_value was just the prefix so return empty string end -- if we get this far we have prefix and script name = cfg.lang_tag_remap[lang] or mw.language.fetchLanguageName( lang, cfg.this_wiki_code ); -- get language name so that we can use it to categorize if utilities.is_set (name) then -- is prefix a proper ISO 639-1 language code? script_value = script_value:gsub ('^%l+%s*:%s*', ''); -- strip prefix from script -- is prefix one of these language codes? if utilities.in_array (lang, cfg.script_lang_codes) then utilities.add_prop_cat ('script', {name, lang}) else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['unknown language code']}); -- unknown script-language; add error message end lang = ' lang="' .. lang .. '" '; -- convert prefix into a lang attribute else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['invalid language code']}); -- invalid language code; add error message lang = ''; -- invalid so set lang to empty string end else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing prefix']}); -- no language code prefix; add error message end script_value = utilities.substitute (cfg.presentation['bdi'], {lang, script_value}); -- isolate in case script is RTL return script_value; end --[[--------------------------< S C R I P T _ C O N C A T E N A T E >------------------------------------------ Initially for |title= and |script-title=, this function concatenates those two parameter values after the script value has been wrapped in <bdi> tags. ]] local function script_concatenate (title, script, script_param) if utilities.is_set (script) then script = format_script_value (script, script_param); -- <bdi> tags, lang attribute, categorization, etc.; returns empty string on error if utilities.is_set (script) then title = title .. ' ' .. script; -- concatenate title and script title end end return title; end --[[--------------------------< W R A P _ M S G >-------------------------------------------------------------- Applies additional message text to various parameter values. Supplied string is wrapped using a message_list configuration taking one argument. Supports lower case text for {{citation}} templates. Additional text taken from citation_config.messages - the reason this function is similar to but separate from wrap_style(). ]] local function wrap_msg (key, str, lower) if not utilities.is_set ( str ) then return ""; end if true == lower then local msg; msg = cfg.messages[key]:lower(); -- set the message to lower case before return utilities.substitute ( msg, str ); -- including template text else return utilities.substitute ( cfg.messages[key], str ); end end --[[----------------< W I K I S O U R C E _ U R L _ M A K E >------------------- Makes a Wikisource URL from Wikisource interwiki-link. Returns the URL and appropriate label; nil else. str is the value assigned to |chapter= (or aliases) or |title= or |title-link= ]] local function wikisource_url_make (str) local wl_type, D, L; local ws_url, ws_label; local wikisource_prefix = table.concat ({'https://', cfg.this_wiki_code, '.wikisource.org/wiki/'}); wl_type, D, L = utilities.is_wikilink (str); -- wl_type is 0 (not a wikilink), 1 (simple wikilink), 2 (complex wikilink) if 0 == wl_type then -- not a wikilink; might be from |title-link= str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 1 == wl_type then -- simple wikilink: [[Wikisource:ws article]] str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 2 == wl_type then -- non-so-simple wikilink: [[Wikisource:ws article|displayed text]] ([[L|D]]) str = L:match ('^[Ww]ikisource:(.+)') or L:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_label = D; -- get ws article name from display portion of interwiki link ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title without namespace from link portion of wikilink }); end end if ws_url then ws_url = mw.uri.encode (ws_url, 'WIKI'); -- make a usable URL ws_url = ws_url:gsub ('%%23', '#'); -- undo percent-encoding of fragment marker end return ws_url, ws_label, L or D; -- return proper URL or nil and a label or nil end --[[----------------< F O R M A T _ P E R I O D I C A L >----------------------- Format the three periodical parameters: |script-<periodical>=, |<periodical>=, and |trans-<periodical>= into a single Periodical meta-parameter. ]] local function format_periodical (script_periodical, script_periodical_source, periodical, trans_periodical) if not utilities.is_set (periodical) then periodical = ''; -- to be safe for concatenation else periodical = utilities.wrap_style ('italic-title', periodical); -- style end periodical = script_concatenate (periodical, script_periodical, script_periodical_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (trans_periodical) then trans_periodical = utilities.wrap_style ('trans-italic-title', trans_periodical); if utilities.is_set (periodical) then periodical = periodical .. ' ' .. trans_periodical; else -- here when trans-periodical without periodical or script-periodical periodical = trans_periodical; utilities.set_message ('err_trans_missing_title', {'periodical'}); end end return periodical; end --[[------------------< F O R M A T _ C H A P T E R _ T I T L E >--------------- Format the four chapter parameters: |script-chapter=, |chapter=, |trans-chapter=, and |chapter-url= into a single chapter meta- parameter (chapter_url_source used for error messages). ]] local function format_chapter_title (script_chapter, script_chapter_source, chapter, chapter_source, trans_chapter, trans_chapter_source, chapter_url, chapter_url_source, no_quotes, access) local ws_url, ws_label, L = wikisource_url_make (chapter); -- make a wikisource URL and label from a wikisource interwiki link if ws_url then ws_label = ws_label:gsub ('_', ' '); -- replace underscore separators with space characters chapter = ws_label; end if not utilities.is_set (chapter) then chapter = ''; -- to be safe for concatenation else if false == no_quotes then chapter = kern_quotes (chapter); -- if necessary, separate chapter title's leading and trailing quote marks from module provided quote marks chapter = utilities.wrap_style ('quoted-title', chapter); end end chapter = script_concatenate (chapter, script_chapter, script_chapter_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (chapter_url) then chapter = external_link (chapter_url, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate elseif ws_url then chapter = external_link (ws_url, chapter .. '&nbsp;', 'ws link in chapter'); -- adds bare_url_missing_title error if appropriate; space char to move icon away from chap text; TODO: better way to do this? chapter = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, chapter}); end if utilities.is_set (trans_chapter) then trans_chapter = utilities.wrap_style ('trans-quoted-title', trans_chapter); if utilities.is_set (chapter) then chapter = chapter .. ' ' .. trans_chapter; else -- here when trans_chapter without chapter or script-chapter chapter = trans_chapter; chapter_source = trans_chapter_source:match ('trans%-?(.+)'); -- when no chapter, get matching name from trans-<param> utilities.set_message ('err_trans_missing_title', {chapter_source}); end end return chapter; end --[[----------------< H A S _ I N V I S I B L E _ C H A R S >------------------- This function searches a parameter's value for non-printable or invisible characters. The search stops at the first match. This function will detect the visible replacement character when it is part of the Wikisource. Detects but ignores nowiki and math stripmarkers. Also detects other named stripmarkers (gallery, math, pre, ref) and identifies them with a slightly different error message. See also coins_cleanup(). Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker that was detected along with its position (or, for multi-byte characters, the position of its first byte) in the parameter value. ]] local function has_invisible_chars (param, v) local position = ''; -- position of invisible char or starting position of stripmarker local capture; -- used by stripmarker detection to hold name of the stripmarker local stripmarker; -- boolean set true when a stripmarker is found capture = string.match (v, '[%w%p ]*'); -- test for values that are simple ASCII text and bypass other tests if true if capture == v then -- if same there are no Unicode characters return; end for _, invisible_char in ipairs (cfg.invisible_chars) do local char_name = invisible_char[1]; -- the character or group name local pattern = invisible_char[2]; -- the pattern used to find it position, _, capture = mw.ustring.find (v, pattern); -- see if the parameter value contains characters that match the pattern if position and (cfg.invisible_defs.zwj == capture) then -- if we found a zero-width joiner character if mw.ustring.find (v, cfg.indic_script) then -- it's ok if one of the Indic scripts position = nil; -- unset position elseif cfg.emoji_t[mw.ustring.codepoint (v, position+1)] then -- is zwj followed by a character listed in emoji{}? position = nil; -- unset position end end if position then if 'nowiki' == capture or 'math' == capture or -- nowiki and math stripmarkers (not an error condition) ('templatestyles' == capture and utilities.in_array (param, {'id', 'quote'})) then -- templatestyles stripmarker allowed in these parameters stripmarker = true; -- set a flag elseif true == stripmarker and cfg.invisible_defs.del == capture then -- because stripmakers begin and end with the delete char, assume that we've found one end of a stripmarker position = nil; -- unset else local err_msg; if capture and not (cfg.invisible_defs.del == capture or cfg.invisible_defs.zwj == capture) then err_msg = utilities.substitute (cfg.messages.invisible_1, {capture, char_name}); -- <capture> here is stripmarker name else err_msg = utilities.substitute (cfg.messages.invisible_2, char_name); end utilities.set_message ('err_invisible_char', {err_msg, utilities.wrap_style ('parameter', param), position}); -- add error message return; -- and done with this parameter end end end end --[[-------------------< A R G U M E N T _ W R A P P E R >---------------------- Argument wrapper. This function provides support for argument mapping defined in the configuration file so that multiple names can be transparently aliased to single internal variable. ]] local function argument_wrapper ( args ) local origin = {}; return setmetatable({ ORIGIN = function ( self, k ) local dummy = self[k]; -- force the variable to be loaded. return origin[k]; end }, { __index = function ( tbl, k ) if origin[k] ~= nil then return nil; end local args, list, v = args, cfg.aliases[k]; if type( list ) == 'table' then v, origin[k] = utilities.select_one ( args, list, 'err_redundant_parameters' ); if origin[k] == nil then origin[k] = ''; -- Empty string, not nil end elseif list ~= nil then v, origin[k] = args[list], list; else -- maybe let through instead of raising an error? -- v, origin[k] = args[k], k; error( cfg.messages['unknown_argument_map'] .. ': ' .. k); end -- Empty strings, not nil; if v == nil then v = ''; origin[k] = ''; end tbl = rawset( tbl, k, v ); return v; end, }); end --[[--------------------------< N O W R A P _ D A T E >------------------------- When date is YYYY-MM-DD format wrap in nowrap span: <span ...>YYYY-MM-DD</span>. When date is DD MMMM YYYY or is MMMM DD, YYYY then wrap in nowrap span: <span ...>DD MMMM</span> YYYY or <span ...>MMMM DD,</span> YYYY DOES NOT yet support MMMM YYYY or any of the date ranges. ]] local function nowrap_date (date) local cap = ''; local cap2 = ''; if date:match("^%d%d%d%d%-%d%d%-%d%d$") then date = utilities.substitute (cfg.presentation['nowrap1'], date); elseif date:match("^%a+%s*%d%d?,%s+%d%d%d%d$") or date:match ("^%d%d?%s*%a+%s+%d%d%d%d$") then cap, cap2 = string.match (date, "^(.*)%s+(%d%d%d%d)$"); date = utilities.substitute (cfg.presentation['nowrap2'], {cap, cap2}); end return date; end --[[--------------------------< S E T _ T I T L E T Y P E >--------------------- This function sets default title types (equivalent to the citation including |type=<default value>) for those templates that have defaults. Also handles the special case where it is desirable to omit the title type from the rendered citation (|type=none). ]] local function set_titletype (cite_class, title_type) if utilities.is_set (title_type) then if 'none' == cfg.keywords_xlate[title_type] then title_type = ''; -- if |type=none then type parameter not displayed end return title_type; -- if |type= has been set to any other value use that value end return cfg.title_types [cite_class] or ''; -- set template's default title type; else empty string for concatenation end --[[--------------------------< S A F E _ J O I N >----------------------------- Joins a sequence of strings together while checking for duplicate separation characters. ]] local function safe_join( tbl, duplicate_char ) local f = {}; -- create a function table appropriate to type of 'duplicate character' if 1 == #duplicate_char then -- for single byte ASCII characters use the string library functions f.gsub = string.gsub f.match = string.match f.sub = string.sub else -- for multi-byte characters use the ustring library functions f.gsub = mw.ustring.gsub f.match = mw.ustring.match f.sub = mw.ustring.sub end local str = ''; -- the output string local comp = ''; -- what does 'comp' mean? local end_chr = ''; local trim; for _, value in ipairs( tbl ) do if value == nil then value = ''; end if str == '' then -- if output string is empty str = value; -- assign value to it (first time through the loop) elseif value ~= '' then if value:sub(1, 1) == '<' then -- special case of values enclosed in spans and other markup. comp = value:gsub( "%b<>", "" ); -- remove HTML markup (<span>string</span> -> string) else comp = value; end -- typically duplicate_char is sepc if f.sub(comp, 1, 1) == duplicate_char then -- is first character same as duplicate_char? why test first character? -- Because individual string segments often (always?) begin with terminal punct for the -- preceding segment: 'First element' .. 'sepc next element' .. etc.? trim = false; end_chr = f.sub(str, -1, -1); -- get the last character of the output string -- str = str .. "<HERE(enchr=" .. end_chr .. ")" -- debug stuff? if end_chr == duplicate_char then -- if same as separator str = f.sub(str, 1, -2); -- remove it elseif end_chr == "'" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "''" then -- if last three chars of str are sepc'' str = f.sub(str, 1, -4) .. "''"; -- remove them and add back '' elseif f.sub(str, -5, -1) == duplicate_char .. "]]''" then -- if last five chars of str are sepc]]'' trim = true; -- why? why do this and next differently from previous? elseif f.sub(str, -4, -1) == duplicate_char .. "]''" then -- if last four chars of str are sepc]'' trim = true; -- same question end elseif end_chr == "]" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "]]" then -- if last three chars of str are sepc]] wikilink trim = true; elseif f.sub(str, -3, -1) == duplicate_char .. '"]' then -- if last three chars of str are sepc"] quoted external link trim = true; elseif f.sub(str, -2, -1) == duplicate_char .. "]" then -- if last two chars of str are sepc] external link trim = true; elseif f.sub(str, -4, -1) == duplicate_char .. "'']" then -- normal case when |url=something & |title=Title. trim = true; end elseif end_chr == " " then -- if last char of output string is a space if f.sub(str, -2, -1) == duplicate_char .. " " then -- if last two chars of str are <sepc><space> str = f.sub(str, 1, -3); -- remove them both end end if trim then if value ~= comp then -- value does not equal comp when value contains HTML markup local dup2 = duplicate_char; if f.match(dup2, "%A" ) then dup2 = "%" .. dup2; end -- if duplicate_char not a letter then escape it value = f.gsub(value, "(%b<>)" .. dup2, "%1", 1 ) -- remove duplicate_char if it follows HTML markup else value = f.sub(value, 2, -1 ); -- remove duplicate_char when it is first character end end end str = str .. value; -- add it to the output string end end return str; end --[[--------------------------< I S _ S U F F I X >----------------------------- returns true if suffix is properly formed Jr, Sr, or ordinal in the range 1–9. Puncutation not allowed. ]] local function is_suffix (suffix) if utilities.in_array (suffix, {'Jr', 'Sr', 'Jnr', 'Snr', '1st', '2nd', '3rd'}) or suffix:match ('^%dth$') then return true; end return false; end --[[--------------------< I S _ G O O D _ V A N C _ N A M E >------------------- For Vancouver style, author/editor names are supposed to be rendered in Latin (read ASCII) characters. When a name uses characters that contain diacritical marks, those characters are to be converted to the corresponding Latin character. When a name is written using a non-Latin alphabet or logogram, that name is to be transliterated into Latin characters. The module doesn't do this so editors may/must. This test allows |first= and |last= names to contain any of the letters defined in the four Unicode Latin character sets [http://www.unicode.org/charts/PDF/U0000.pdf C0 Controls and Basic Latin] 0041–005A, 0061–007A [http://www.unicode.org/charts/PDF/U0080.pdf C1 Controls and Latin-1 Supplement] 00C0–00D6, 00D8–00F6, 00F8–00FF [http://www.unicode.org/charts/PDF/U0100.pdf Latin Extended-A] 0100–017F [http://www.unicode.org/charts/PDF/U0180.pdf Latin Extended-B] 0180–01BF, 01C4–024F |lastn= also allowed to contain hyphens, spaces, and apostrophes. (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) |firstn= also allowed to contain hyphens, spaces, apostrophes, and periods This original test: if nil == mw.ustring.find (last, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%'%.]+[2-6%a]*$") then was written outside of the code editor and pasted here because the code editor gets confused between character insertion point and cursor position. The test has been rewritten to use decimal character escape sequence for the individual bytes of the Unicode characters so that it is not necessary to use an external editor to maintain this code. \195\128-\195\150 – À-Ö (U+00C0–U+00D6 – C0 controls) \195\152-\195\182 – Ø-ö (U+00D8-U+00F6 – C0 controls) \195\184-\198\191 – ø-ƿ (U+00F8-U+01BF – C0 controls, Latin extended A & B) \199\132-\201\143 – DŽ-ɏ (U+01C4-U+024F – Latin extended B) ]] local function is_good_vanc_name (last, first, suffix, position) if not suffix then if first:find ('[,%s]') then -- when there is a space or comma, might be first name/initials + generational suffix first = first:match ('(.-)[,%s]+'); -- get name/initials suffix = first:match ('[,%s]+(.+)$'); -- get generational suffix end end if utilities.is_set (suffix) then if not is_suffix (suffix) then add_vanc_error (cfg.err_msg_supl.suffix, position); return false; -- not a name with an appropriate suffix end end if nil == mw.ustring.find (last, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%'%.]*$") then add_vanc_error (cfg.err_msg_supl['non-Latin char'], position); return false; -- not a string of Latin characters; Vancouver requires Romanization end; return true; end --[[--------------------------< R E D U C E _ T O _ I N I T I A L S >------------------------------------------ Attempts to convert names to initials in support of |name-list-style=vanc. Names in |firstn= may be separated by spaces or hyphens, or for initials, a period. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35062/. Vancouver style requires family rank designations (Jr, II, III, etc.) to be rendered as Jr, 2nd, 3rd, etc. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35085/. This code only accepts and understands generational suffix in the Vancouver format because Roman numerals look like, and can be mistaken for, initials. This function uses ustring functions because firstname initials may be any of the Unicode Latin characters accepted by is_good_vanc_name (). ]] local function reduce_to_initials (first, position) if first:find (',', 1, true) then return first; -- commas not allowed; abandon end local name, suffix = mw.ustring.match (first, "^(%u+) ([%dJS][%drndth]+)$"); if not name then -- if not initials and a suffix name = mw.ustring.match (first, "^(%u+)$"); -- is it just initials? end if name then -- if first is initials with or without suffix if 3 > mw.ustring.len (name) then -- if one or two initials if suffix then -- if there is a suffix if is_suffix (suffix) then -- is it legitimate? return first; -- one or two initials and a valid suffix so nothing to do else add_vanc_error (cfg.err_msg_supl.suffix, position); -- one or two initials with invalid suffix so error message return first; -- and return first unmolested end else return first; -- one or two initials without suffix; nothing to do end end end -- if here then name has 3 or more uppercase letters so treat them as a word local initials_t, names_t = {}, {}; -- tables to hold name parts and initials local i = 1; -- counter for number of initials names_t = mw.text.split (first, '[%s%-]+'); -- split into a sequence of names and possible suffix while names_t[i] do -- loop through the sequence if 1 < i and names_t[i]:match ('[%dJS][%drndth]+%.?$') then -- if not the first name, and looks like a suffix (may have trailing dot) names_t[i] = names_t[i]:gsub ('%.', ''); -- remove terminal dot if present if is_suffix (names_t[i]) then -- if a legitimate suffix table.insert (initials_t, ' ' .. names_t[i]); -- add a separator space, insert at end of initials sequence break; -- and done because suffix must fall at the end of a name end -- no error message if not a suffix; possibly because of Romanization end if 3 > i then table.insert (initials_t, mw.ustring.sub (names_t[i], 1, 1)); -- insert the initial at end of initials sequence end i = i + 1; -- bump the counter end return table.concat (initials_t); -- Vancouver format does not include spaces. end --[[--------------------------< I N T E R W I K I _ P R E F I X E N _ G E T >---------------------------------- extract interwiki prefixen from <value>. Returns two one or two values: false – no prefixen nil – prefix exists but not recognized project prefix, language prefix – when value has either of: :<project>:<language>:<article> :<language>:<project>:<article> project prefix, nil – when <value> has only a known single-letter prefix nil, language prefix – when <value> has only a known language prefix accepts single-letter project prefixen: 'd' (wikidata), 's' (wikisource), and 'w' (wikipedia) prefixes; at this writing, the other single-letter prefixen (b (wikibook), c (commons), m (meta), n (wikinews), q (wikiquote), and v (wikiversity)) are not supported. ]] local function interwiki_prefixen_get (value, is_link) if not value:find (':%l+:') then -- if no prefix return false; -- abandon; boolean here to distinguish from nil fail returns later end local prefix_patterns_linked_t = { -- sequence of valid interwiki and inter project prefixen '^%[%[:([dsw]):(%l%l+):', -- wikilinked; project and language prefixes '^%[%[:(%l%l+):([dsw]):', -- wikilinked; language and project prefixes '^%[%[:([dsw]):', -- wikilinked; project prefix '^%[%[:(%l%l+):', -- wikilinked; language prefix } local prefix_patterns_unlinked_t = { -- sequence of valid interwiki and inter project prefixen '^:([dsw]):(%l%l+):', -- project and language prefixes '^:(%l%l+):([dsw]):', -- language and project prefixes '^:([dsw]):', -- project prefix '^:(%l%l+):', -- language prefix } local cap1, cap2; for _, pattern in ipairs ((is_link and prefix_patterns_linked_t) or prefix_patterns_unlinked_t) do cap1, cap2 = value:match (pattern); if cap1 then break; -- found a match so stop looking end end if cap1 and cap2 then -- when both then :project:language: or :language:project: (both forms allowed) if 1 == #cap1 then -- length == 1 then :project:language: if cfg.inter_wiki_map[cap2] then -- is language prefix in the interwiki map? return cap1, cap2; -- return interwiki project and interwiki language end else -- here when :language:project: if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return cap2, cap1; -- return interwiki project and interwiki language end end return nil; -- unknown interwiki language elseif not (cap1 or cap2) then -- both are nil? return nil; -- we got something that looks like a project prefix but isn't; return fail elseif 1 == #cap1 then -- here when one capture return cap1, nil; -- length is 1 so return project, nil language else -- here when one capture and its length it more than 1 if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return nil, cap1; -- return nil project, language end end end --[[--------------------------< L I S T _ P E O P L E >-------------------------- Formats a list of people (authors, contributors, editors, interviewers, translators) names in the list will be linked when |<name>-link= has a value |<name>-mask- does NOT have a value; masked names are presumed to have been rendered previously so should have been linked there when |<name>-mask=0, the associated name is not rendered ]] local function list_people (control, people, etal) local sep; local namesep; local format = control.format; local maximum = control.maximum; local name_list = {}; if 'vanc' == format then -- Vancouver-like name styling? sep = cfg.presentation['sep_nl_vanc']; -- name-list separator between names is a comma namesep = cfg.presentation['sep_name_vanc']; -- last/first separator is a space else sep = cfg.presentation['sep_nl']; -- name-list separator between names is a semicolon namesep = cfg.presentation['sep_name']; -- last/first separator is <comma><space> end if sep:sub (-1, -1) ~= " " then sep = sep .. " " end if utilities.is_set (maximum) and maximum < 1 then return "", 0; end -- returned 0 is for EditorCount; not used for other names for i, person in ipairs (people) do if utilities.is_set (person.last) then local mask = person.mask; local one; local sep_one = sep; if utilities.is_set (maximum) and i > maximum then etal = true; break; end if mask then local n = tonumber (mask); -- convert to a number if it can be converted; nil else if n then one = 0 ~= n and string.rep("&mdash;", n) or nil; -- make a string of (n > 0) mdashes, nil else, to replace name person.link = nil; -- don't create link to name if name is replaces with mdash string or has been set nil else one = mask; -- replace name with mask text (must include name-list separator) sep_one = " "; -- modify name-list separator end else one = person.last; -- get surname local first = person.first -- get given name if utilities.is_set (first) then if ("vanc" == format) then -- if Vancouver format one = one:gsub ('%.', ''); -- remove periods from surnames (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) if not person.corporate and is_good_vanc_name (one, first, nil, i) then -- and name is all Latin characters; corporate authors not tested first = reduce_to_initials (first, i); -- attempt to convert first name(s) to initials end end one = one .. namesep .. first; end end if utilities.is_set (person.link) then one = utilities.make_wikilink (person.link, one); -- link author/editor end if one then -- if <one> has a value (name, mdash replacement, or mask text replacement) local proj, tag = interwiki_prefixen_get (one, true); -- get the interwiki prefixen if present if 'w' == proj and ('Wikipedia' == mw.site.namespaces.Project['name']) then proj = nil; -- for stuff like :w:de:<article>, :w is unnecessary TODO: maint cat? end if proj then local proj_name = ({['d'] = cfg.messages.wikidata, ['s'] = cfg.messages.wikisource, ['w'] = cfg.messages.wikipedia})[proj]; -- :w (wikipedia) for linking from a non-wikipedia project if proj_name then one = one .. utilities.wrap_style ('interproj', proj_name); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interproj-linked-name', proj); -- categorize it; <proj> is sort key tag = nil; -- unset; don't do both project and language end end if tag == cfg.this_wiki_code then tag = nil; -- stuff like :en:<article> at en.wiki is pointless TODO: maint cat? end if tag then local lang = cfg.lang_tag_remap[tag] or cfg.mw_languages_by_tag_t[tag]; if lang then -- error messaging done in extract_names() where we know parameter names one = one .. utilities.wrap_style ('interwiki', lang); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interwiki-linked-name', tag); -- categorize it; <tag> is sort key end end table.insert (name_list, one); -- add it to the list of names table.insert (name_list, sep_one); -- add the proper name-list separator end end end local count = #name_list / 2; -- (number of names + number of separators) divided by 2 if 0 < count then if 1 < count and not etal then if 'amp' == format then name_list[#name_list-2] = " & "; -- replace last separator with ampersand text elseif 'and' == format then if 2 == count then name_list[#name_list-2] = cfg.presentation.sep_nl_and; -- replace last separator with 'and' text else name_list[#name_list-2] = cfg.presentation.sep_nl_end; -- replace last separator with '(sep) and' text end end end name_list[#name_list] = nil; -- erase the last separator end local result = table.concat (name_list); -- construct list if etal and utilities.is_set (result) then -- etal may be set by |display-authors=etal but we might not have a last-first list result = result .. sep .. cfg.messages['et al']; -- we've got a last-first list and etal so add et al. end return result, count; -- return name-list string and count of number of names (count used for editor names only) end --[[--------------------< M A K E _ C I T E R E F _ I D >----------------------- Generates a CITEREF anchor ID if we have at least one name or a date. Otherwise returns an empty string. namelist is one of the contributor-, author-, or editor-name lists chosen in that order. year is Year or anchor_year. ]] local function make_citeref_id (namelist, year) local names={}; -- a table for the one to four names and year for i,v in ipairs (namelist) do -- loop through the list and take up to the first four last names names[i] = v.last if i == 4 then break end -- if four then done end table.insert (names, year); -- add the year at the end local id = table.concat(names); -- concatenate names and year for CITEREF id if utilities.is_set (id) then -- if concatenation is not an empty string return "CITEREF" .. id; -- add the CITEREF portion else return ''; -- return an empty string; no reason to include CITEREF id in this citation end end --[[--------------------------< C I T E _ C L A S S _A T T R I B U T E _M A K E >------------------------------ construct <cite> tag class attribute for this citation. <cite_class> – config.CitationClass from calling template <mode> – value from |mode= parameter ]] local function cite_class_attribute_make (cite_class, mode) local class_t = {}; table.insert (class_t, 'citation'); -- required for blue highlight if 'citation' ~= cite_class then table.insert (class_t, cite_class); -- identify this template for user css table.insert (class_t, utilities.is_set (mode) and mode or 'cs1'); -- identify the citation style for user css or javascript else table.insert (class_t, utilities.is_set (mode) and mode or 'cs2'); -- identify the citation style for user css or javascript end for _, prop_key in ipairs (z.prop_keys_t) do table.insert (class_t, prop_key); -- identify various properties for user css or javascript end return table.concat (class_t, ' '); -- make a big string and done end --[[---------------------< N A M E _ H A S _ E T A L >-------------------------- Evaluates the content of name parameters (author, editor, etc.) for variations on the theme of et al. If found, the et al. is removed, a flag is set to true and the function returns the modified name and the flag. This function never sets the flag to false but returns its previous state because it may have been set by previous passes through this function or by the associated |display-<names>=etal parameter ]] local function name_has_etal (name, etal, nocat, param) if utilities.is_set (name) then -- name can be nil in which case just return local patterns = cfg.et_al_patterns; -- get patterns from configuration for _, pattern in ipairs (patterns) do -- loop through all of the patterns if name:match (pattern) then -- if this 'et al' pattern is found in name name = name:gsub (pattern, ''); -- remove the offending text etal = true; -- set flag (may have been set previously here or by |display-<names>=etal) if not nocat then -- no categorization for |vauthors= utilities.set_message ('err_etal', {param}); -- and set an error if not added end end end end return name, etal; end --[[---------------------< N A M E _ I S _ N U M E R I C >---------------------- Add an error message and category when <name> parameter value does not contain letters. Add a maintenance category when <name> parameter value has numeric characters mixed with characters that are not numeric characters; could be letters and/or punctuation characters. This function will only emit one error and one maint message for the current template. Does not emit both error and maint messages/categories for the same parameter value. returns nothing ]] local function name_is_numeric (name, name_alias, list_name) local patterns = { '^%D+%d', -- <name> must have digits preceded by other characters '^%D*%d+%D+', -- <name> must have digits followed by other characters } if not added_numeric_name_errs and mw.ustring.match (name, '^[%A]+$') then -- if we have not already set an error message and <name> does not have any alpha characters utilities.set_message ('err_numeric_names', name_alias); -- add an error message added_numeric_name_errs = true; -- set the flag so we emit only one error message return; -- when here no point in further testing; abandon end if not added_numeric_name_maint then -- if we have already set a maint message for _, pattern in ipairs (patterns) do -- spin through list of patterns if mw.ustring.match (name, pattern) then -- digits preceded or followed by anything but digits; %D+ includes punctuation utilities.set_message ('maint_numeric_names', cfg.special_case_translation [list_name]); -- add a maint cat for this template added_numeric_name_maint = true; -- set the flag so we emit only one maint message return; -- when here no point in further testing; abandon end end end end --[[-----------------< N A M E _ H A S _ M U L T _ N A M E S >------------------ Evaluates the content of last/surname (authors etc.) parameters for multiple names. Multiple names are indicated if there is more than one comma or any "unescaped" semicolons. Escaped semicolons are ones used as part of selected HTML entities. If the condition is met, the function adds the multiple name maintenance category. Same test for first except that commas should not appear in given names (MOS:JR says that the generational suffix does not take a separator character). Titles, degrees, postnominals, affiliations, all normally comma separated don't belong in a citation. <name> – name parameter value <list_name> – AuthorList, EditorList, etc <limit> – number of allowed commas; 1 (default) for surnames; 0 for given names returns nothing ]] local function name_has_mult_names (name, list_name, limit) local _, commas, semicolons, nbsps; limit = limit and limit or 1; if utilities.is_set (name) then _, commas = name:gsub (',', ''); -- count the number of commas _, semicolons = name:gsub (';', ''); -- count the number of semicolons -- nbsps probably should be its own separate count rather than merged in -- some way with semicolons because Lua patterns do not support the -- grouping operator that regex does, which means there is no way to add -- more entities to escape except by adding more counts with the new -- entities _, nbsps = name:gsub ('&nbsp;',''); -- count nbsps -- There is exactly 1 semicolon per &nbsp; entity, so subtract nbsps -- from semicolons to 'escape' them. If additional entities are added, -- they also can be subtracted. if limit < commas or 0 < (semicolons - nbsps) then utilities.set_message ('maint_mult_names', cfg.special_case_translation [list_name]); -- add a maint message end end end --[=[-------------------------< I S _ G E N E R I C >---------------------------------------------------------- Compares values assigned to various parameters according to the string provided as <item> in the function call. <item> can have on of two values: 'generic_names' – for name-holding parameters: |last=, |first=, |editor-last=, etc 'generic_titles' – for |title= There are two types of generic tests. The 'accept' tests look for a pattern that should not be rejected by the 'reject' test. For example, |author=[[John Smith (author)|Smith, John]] would be rejected by the 'author' reject test. But piped wikilinks with 'author' disambiguation should not be rejected so the 'accept' test prevents that from happening. Accept tests are always performed before reject tests. Each of the 'accept' and 'reject' sequence tables hold tables for en.wiki (['en']) and local.wiki (['local']) that each can hold a test sequence table The sequence table holds, at index [1], a test pattern, and, at index [2], a boolean control value. The control value tells string.find() or mw.ustring.find() to do plain-text search (true) or a pattern search (false). The intent of all this complexity is to make these searches as fast as possible so that we don't run out of processing time on very large articles. Returns true when a reject test finds the pattern or string false when an accept test finds the pattern or string nil else ]=] local function is_generic (item, value, wiki) local test_val; local str_lower = { -- use string.lower() for en.wiki (['en']) and use mw.ustring.lower() or local.wiki (['local']) ['en'] = string.lower, ['local'] = mw.ustring.lower, } local str_find = { -- use string.find() for en.wiki (['en']) and use mw.ustring.find() or local.wiki (['local']) ['en'] = string.find, ['local'] = mw.ustring.find, } local function test (val, test_t, wiki) -- local function to do the testing; <wiki> selects lower() and find() functions val = test_t[2] and str_lower[wiki](value) or val; -- when <test_t[2]> set to 'true', plaintext search using lowercase value return str_find[wiki] (val, test_t[1], 1, test_t[2]); -- return nil when not found or matched end local test_types_t = {'accept', 'reject'}; -- test accept patterns first, then reject patterns local wikis_t = {'en', 'local'}; -- do tests for each of these keys; en.wiki first, local.wiki second for _, test_type in ipairs (test_types_t) do -- for each test type for _, generic_value in pairs (cfg.special_case_translation[item][test_type]) do -- spin through the list of generic value fragments to accept or reject for _, wiki in ipairs (wikis_t) do if generic_value[wiki] then if test (value, generic_value[wiki], wiki) then -- go do the test return ('reject' == test_type); -- param value rejected, return true; false else end end end end end end --[[--------------------------< N A M E _ I S _ G E N E R I C >------------------------------------------------ calls is_generic() to determine if <name> is a 'generic name' listed in cfg.generic_names; <name_alias> is the parameter name used in error messaging ]] local function name_is_generic (name, name_alias) if not added_generic_name_errs and is_generic ('generic_names', name) then utilities.set_message ('err_generic_name', name_alias); -- set an error message added_generic_name_errs = true; end end --[[--------------------------< N A M E _ C H E C K S >-------------------------------------------------------- This function calls various name checking functions used to validate the content of the various name-holding parameters. ]] local function name_checks (last, first, list_name, last_alias, first_alias) local accept_name; if utilities.is_set (last) then last, accept_name = utilities.has_accept_as_written (last); -- remove accept-this-as-written markup when it wraps all of <last> if not accept_name then -- <last> not wrapped in accept-as-written markup name_has_mult_names (last, list_name); -- check for multiple names in the parameter name_is_numeric (last, last_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (last, last_alias); -- check for names found in the generic names list end end if utilities.is_set (first) then first, accept_name = utilities.has_accept_as_written (first); -- remove accept-this-as-written markup when it wraps all of <first> if not accept_name then -- <first> not wrapped in accept-as-written markup name_has_mult_names (first, list_name, 0); -- check for multiple names in the parameter; 0 is number of allowed commas in a given name name_is_numeric (first, first_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (first, first_alias); -- check for names found in the generic names list end local wl_type, D = utilities.is_wikilink (first); if 0 ~= wl_type then first = D; utilities.set_message ('err_bad_paramlink', first_alias); end end return last, first; -- done end --[[----------------------< E X T R A C T _ N A M E S >------------------------- Gets name list from the input arguments Searches through args in sequential order to find |lastn= and |firstn= parameters (or their aliases), and their matching link and mask parameters. Stops searching when both |lastn= and |firstn= are not found in args after two sequential attempts: found |last1=, |last2=, and |last3= but doesn't find |last4= and |last5= then the search is done. This function emits an error message when there is a |firstn= without a matching |lastn=. When there are 'holes' in the list of last names, |last1= and |last3= are present but |last2= is missing, an error message is emitted. |lastn= is not required to have a matching |firstn=. When an author or editor parameter contains some form of 'et al.', the 'et al.' is stripped from the parameter and a flag (etal) returned that will cause list_people() to add the static 'et al.' text from Module:Citation/CS1/Configuration. This keeps 'et al.' out of the template's metadata. When this occurs, an error is emitted. ]] local function extract_names(args, list_name) local names = {}; -- table of names local last; -- individual name components local first; local link; local mask; local i = 1; -- loop counter/indexer local n = 1; -- output table indexer local count = 0; -- used to count the number of times we haven't found a |last= (or alias for authors, |editor-last or alias for editors) local etal = false; -- return value set to true when we find some form of et al. in an author parameter local last_alias, first_alias, link_alias; -- selected parameter aliases used in error messaging while true do last, last_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'err_redundant_parameters', i ); -- search through args for name components beginning at 1 first, first_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'err_redundant_parameters', i ); link, link_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ); mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); if last then -- error check |lastn= alias for unknown interwiki link prefix; done here because this is where we have the parameter name local project, language = interwiki_prefixen_get (last, true); -- true because we expect interwiki links in |lastn= to be wikilinked if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', last_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? last = utilities.remove_wiki_link (last); -- remove wikilink markup; show display value only end end if link then -- error check |linkn= alias for unknown interwiki link prefix local project, language = interwiki_prefixen_get (link, false); -- false because wiki links in |author-linkn= is an error if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', link_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? link = nil; -- unset so we don't link link_alias = nil; end end last, etal = name_has_etal (last, etal, false, last_alias); -- find and remove variations on et al. first, etal = name_has_etal (first, etal, false, first_alias); -- find and remove variations on et al. last, first = name_checks (last, first, list_name, last_alias, first_alias); -- multiple names, extraneous annotation, etc. checks if first and not last then -- if there is a firstn without a matching lastn local alias = first_alias:find ('given', 1, true) and 'given' or 'first'; -- get first or given form of the alias utilities.set_message ('err_first_missing_last', { first_alias, -- param name of alias missing its mate first_alias:gsub (alias, {['first'] = 'last', ['given'] = 'surname'}), -- make param name appropriate to the alias form }); -- add this error message elseif not first and not last then -- if both firstn and lastn aren't found, are we done? count = count + 1; -- number of times we haven't found last and first if 2 <= count then -- two missing names and we give up break; -- normal exit or there is a two-name hole in the list; can't tell which end else -- we have last with or without a first local result; link = link_title_ok (link, link_alias, last, last_alias); -- check for improper wiki-markup if first then link = link_title_ok (link, link_alias, first, first_alias); -- check for improper wiki-markup end names[n] = {last = last, first = first, link = link, mask = mask, corporate = false}; -- add this name to our names list (corporate for |vauthors= only) n = n + 1; -- point to next location in the names table if 1 == count then -- if the previous name was missing utilities.set_message ('err_missing_name', {list_name:match ("(%w+)List"):lower(), i - 1}); -- add this error message end count = 0; -- reset the counter, we're looking for two consecutive missing names end i = i + 1; -- point to next args location end return names, etal; -- all done, return our list of names and the etal flag end --[[--------------------------< N A M E _ T A G _ G E T >------------------------------------------------------ attempt to decode |language=<lang_param> and return language name and matching tag; nil else. This function looks for: <lang_param> as a tag in cfg.lang_tag_remap{} <lang_param> as a name in cfg.lang_name_remap{} <lang_param> as a name in cfg.mw_languages_by_name_t <lang_param> as a tag in cfg.mw_languages_by_tag_t when those fail, presume that <lang_param> is an IETF-like tag that MediaWiki does not recognize. Strip all script, region, variant, whatever subtags from <lang_param> to leave just a two or three character language tag and look for the new <lang_param> in cfg.mw_languages_by_tag_t{} on success, returns name (in properly capitalized form) and matching tag (in lowercase); on failure returns nil ]] local function name_tag_get (lang_param) local lang_param_lc = mw.ustring.lower (lang_param); -- use lowercase as an index into the various tables local name; local tag; name = cfg.lang_tag_remap[lang_param_lc]; -- assume <lang_param_lc> is a tag; attempt to get remapped language name if name then -- when <name>, <lang_param> is a tag for a remapped language name if cfg.lang_name_remap[name:lower()][2] ~= lang_param_lc then utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added return name, cfg.lang_name_remap[name:lower()][2]; -- so return name and tag from lang_name_remap[name]; special case to xlate sr-ec and sr-el to sr-cyrl and sr-latn end return name, lang_param_lc; -- so return <name> from remap and <lang_param_lc> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- still assuming that <lang_param_lc> is a tag; strip script, region, variant subtags name = cfg.lang_tag_remap[tag]; -- attempt to get remapped language name with language subtag only if name then -- when <name>, <tag> is a tag for a remapped language name return name, tag; -- so return <name> from remap and <tag> end if cfg.lang_name_remap[lang_param_lc] then -- not a remapped tag, assume <lang_param_lc> is a name; attempt to get remapped language tag return cfg.lang_name_remap[lang_param_lc][1], cfg.lang_name_remap[lang_param_lc][2]; -- for this <lang_param_lc>, return a (possibly) new name and appropriate tag end name = cfg.mw_languages_by_tag_t[lang_param_lc]; -- assume that <lang_param_lc> is a tag; attempt to get its matching language name if name then return name, lang_param_lc; -- <lang_param_lc> is a tag so return it and <name> end tag = cfg.mw_languages_by_name_t[lang_param_lc]; -- assume that <lang_param_lc> is a language name; attempt to get its matching tag if tag then return cfg.mw_languages_by_tag_t[tag], tag; -- <lang_param_lc> is a name so return the name from the table and <tag> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- is <lang_param_lc> an IETF-like tag that MediaWiki doesn't recognize? <tag> gets the language subtag; nil else if tag then name = cfg.mw_languages_by_tag_t[tag]; -- attempt to get a language name using the shortened <tag> if name then return name, tag; -- <lang_param_lc> is an unrecognized IETF-like tag so return <name> and language subtag end end end --[[-------------------< L A N G U A G E _ P A R A M E T E R >------------------ Gets language name from a provided two- or three-character ISO 639 code. If a code is recognized by MediaWiki, use the returned name; if not, then use the value that was provided with the language parameter. When |language= contains a recognized language (either code or name), the page is assigned to the category for that code: Category:Norwegian-language sources (no). For valid three-character code languages, the page is assigned to the single category for '639-2' codes: Category:CS1 ISO 639-2 language sources. Languages that are the same as the local wiki are not categorized. MediaWiki does not recognize three-character equivalents of two-character codes: code 'ar' is recognized but code 'ara' is not. This function supports multiple languages in the form |language=nb, French, th where the language names or codes are separated from each other by commas with optional space characters. ]] local function language_parameter (lang) local tag; -- some form of IETF-like language tag; language subtag with optional region, sript, vatiant, etc subtags local lang_subtag; -- ve populates |language= with mostly unecessary region subtags the MediaWiki does not recognize; this is the base language subtag local name; -- the language name local language_list = {}; -- table of language names to be rendered local names_t = {}; -- table made from the value assigned to |language= local this_wiki_name = mw.language.fetchLanguageName (cfg.this_wiki_code, cfg.this_wiki_code); -- get this wiki's language name names_t = mw.text.split (lang, '%s*,%s*'); -- names should be a comma separated list for _, lang in ipairs (names_t) do -- reuse lang here because we don't yet know if lang is a language name or a language tag name, tag = name_tag_get (lang); -- attempt to get name/tag pair for <lang>; <name> has proper capitalization; <tag> is lowercase if utilities.is_set (tag) then lang_subtag = tag:gsub ('^(%a%a%a?)%-.*', '%1'); -- for categorization, strip any IETF-like tags from language tag if cfg.this_wiki_code ~= lang_subtag then -- when the language is not the same as this wiki's language if 2 == lang_subtag:len() then -- and is a two-character tag utilities.add_prop_cat ('foreign-lang-source', {name, tag}, lang_subtag); -- categorize it; tag appended to allow for multiple language categorization else -- or is a recognized language (but has a three-character tag) utilities.add_prop_cat ('foreign-lang-source-2', {lang_subtag}, lang_subtag); -- categorize it differently TODO: support multiple three-character tag categories per cs1|2 template? end elseif cfg.local_lang_cat_enable then -- when the language and this wiki's language are the same and categorization is enabled utilities.add_prop_cat ('local-lang-source', {name, lang_subtag}); -- categorize it end else name = lang; -- return whatever <lang> has so that we show something utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added end table.insert (language_list, name); name = ''; -- so we can reuse it end name = utilities.make_sep_list (#language_list, language_list); if (1 == #language_list) and (lang_subtag == cfg.this_wiki_code) then -- when only one language, find lang name in this wiki lang name; for |language=en-us, 'English' in 'American English' return ''; -- if one language and that language is this wiki's return an empty string (no annotation) end return (" " .. wrap_msg ('language', name)); -- otherwise wrap with '(in ...)' --[[ TODO: should only return blank or name rather than full list so we can clean up the bunched parenthetical elements Language, Type, Format ]] end --[[-----------------------< S E T _ C S _ S T Y L E >-------------------------- Gets the default CS style configuration for the given mode. Returns default separator and either postscript as passed in or the default. In CS1, the default postscript and separator are '.'. In CS2, the default postscript is the empty string and the default separator is ','. ]] local function set_cs_style (postscript, mode) if utilities.is_set(postscript) then -- emit a maintenance message if user postscript is the default cs1 postscript -- we catch the opposite case for cs2 in set_style if mode == 'cs1' and postscript == cfg.presentation['ps_' .. mode] then utilities.set_message ('maint_postscript'); end else postscript = cfg.presentation['ps_' .. mode]; end return cfg.presentation['sep_' .. mode], postscript; end --[[--------------------------< S E T _ S T Y L E >----------------------------- Sets the separator and postscript styles. Checks the |mode= first and the #invoke CitationClass second. Removes the postscript if postscript == none. ]] local function set_style (mode, postscript, cite_class) local sep; if 'cs2' == mode then sep, postscript = set_cs_style (postscript, 'cs2'); elseif 'cs1' == mode then sep, postscript = set_cs_style (postscript, 'cs1'); elseif 'citation' == cite_class then sep, postscript = set_cs_style (postscript, 'cs2'); else sep, postscript = set_cs_style (postscript, 'cs1'); end if cfg.keywords_xlate[postscript:lower()] == 'none' then -- emit a maintenance message if user postscript is the default cs2 postscript -- we catch the opposite case for cs1 in set_cs_style if 'cs2' == mode or ('cs1' ~= mode and 'citation' == cite_class) then -- {{citation |title=Title |mode=cs1 |postscript=none}} should not emit maint message utilities.set_message ('maint_postscript'); end postscript = ''; end return sep, postscript end --[=[-------------------------< I S _ P D F >----------------------------------- Determines if a URL has the file extension that is one of the PDF file extensions used by [[MediaWiki:Common.css]] when applying the PDF icon to external links. returns true if file extension is one of the recognized extensions, else false ]=] local function is_pdf (url) return url:match ('%.pdf$') or url:match ('%.PDF$') or url:match ('%.pdf[%?#]') or url:match ('%.PDF[%?#]') or url:match ('%.PDF&#035') or url:match ('%.pdf&#035'); end --[[--------------------------< S T Y L E _ F O R M A T >----------------------- Applies CSS style to |format=, |chapter-format=, etc. Also emits an error message if the format parameter does not have a matching URL parameter. If the format parameter is not set and the URL contains a file extension that is recognized as a PDF document by MediaWiki's commons.css, this code will set the format parameter to (PDF) with the appropriate styling. ]] local function style_format (format, url, fmt_param, url_param) if utilities.is_set (format) then format = utilities.wrap_style ('format', format); -- add leading space, parentheses, resize if not utilities.is_set (url) then utilities.set_message ('err_format_missing_url', {fmt_param, url_param}); -- add an error message end elseif is_pdf (url) then -- format is not set so if URL is a PDF file then format = utilities.wrap_style ('format', 'PDF'); -- set format to PDF else format = ''; -- empty string for concatenation end return format; end --[[---------------------< G E T _ D I S P L A Y _ N A M E S >------------------ Returns a number that defines the number of names displayed for author and editor name lists and a Boolean flag to indicate when et al. should be appended to the name list. When the value assigned to |display-xxxxors= is a number greater than or equal to zero, return the number and the previous state of the 'etal' flag (false by default but may have been set to true if the name list contains some variant of the text 'et al.'). When the value assigned to |display-xxxxors= is the keyword 'etal', return a number that is one greater than the number of authors in the list and set the 'etal' flag true. This will cause the list_people() to display all of the names in the name list followed by 'et al.' In all other cases, returns nil and the previous state of the 'etal' flag. inputs: max: A['DisplayAuthors'] or A['DisplayEditors'], etc; a number or some flavor of etal count: #a or #e list_name: 'authors' or 'editors' etal: author_etal or editor_etal This function sets an error message when |display-xxxxors= value greater than or equal to number of names but not when <max> comes from {{cs1 config}} global settings. When using global settings, <param> is set to the keyword 'cs1 config' which is used to supress the normal error. Error is suppressed because it is to be expected that some citations in an article will have the same or fewer names that the limit specified in {{cs1 config}}. ]] local function get_display_names (max, count, list_name, etal, param) if utilities.is_set (max) then if 'etal' == max:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings max = count + 1; -- number of authors + 1 so display all author name plus et al. etal = true; -- overrides value set by extract_names() elseif max:match ('^%d+$') then -- if is a string of numbers max = tonumber (max); -- make it a number if (max >= count) and ('cs1 config' ~= param) then -- error when local |display-xxxxors= value greater than or equal to number of names; not an error when using global setting utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; end else -- not a valid keyword or number utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; -- unset; as if |display-xxxxors= had not been set end end return max, etal; end --[[----------< E X T R A _ T E X T _ I N _ P A G E _ C H E C K >--------------- Adds error if |page=, |pages=, |quote-page=, |quote-pages= has what appears to be some form of p. or pp. abbreviation in the first characters of the parameter content. check page for extraneous p, p., pp, pp., pg, pg. at start of parameter value: good pattern: '^P[^%.P%l]' matches when page begins PX or P# but not Px where x and X are letters and # is a digit bad pattern: '^[Pp][PpGg]' matches when page begins pp, pP, Pp, PP, pg, pG, Pg, PG ]] local function extra_text_in_page_check (val, name) if not val:match (cfg.vol_iss_pg_patterns.good_ppattern) then for _, pattern in ipairs (cfg.vol_iss_pg_patterns.bad_ppatterns) do -- spin through the selected sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message ('err_extra_text_pages', name); -- add error message return; -- and done end end end end --[[--------------------------< E X T R A _ T E X T _ I N _ V O L _ I S S _ C H E C K >------------------------ Adds error if |volume= or |issue= has what appears to be some form of redundant 'type' indicator. Applies to both; this function looks for issue text in both |issue= and |volume= and looks for volume-like text in |voluem= and |issue=. For |volume=: 'V.', or 'Vol.' (with or without the dot) abbreviations or 'Volume' in the first characters of the parameter content (all case insensitive). 'V' and 'v' (without the dot) are presumed to be roman numerals so are allowed. For |issue=: 'No.', 'I.', 'Iss.' (with or without the dot) abbreviations, or 'Issue' in the first characters of the parameter content (all case insensitive); numero styling: 'n°' with degree sign U+00B0, and № precomposed numero sign U+2116. Single character values ('v', 'i', 'n') allowed when not followed by separator character ('.', ':', '=', or whitespace character) – param values are trimmed of whitespace by MediaWiki before delivered to the module. <val> is |volume= or |issue= parameter value <name> is |volume= or |issue= parameter name for error message <selector> is 'v' for |volume=, 'i' for |issue= sets error message on failure; returns nothing ]] local function extra_text_in_vol_iss_check (val, name, selector) if not utilities.is_set (val) then return; end local handler = 'v' == selector and 'err_extra_text_volume' or 'err_extra_text_issue'; local accept_val; val, accept_val = utilities.has_accept_as_written (val); --if accept_val then -- if uncomment this, |volume=((vol. 1)) suppresses error -- return; --end --val = mw.text.unstripNoWiki (val); -- if uncomment this, |volume=<nowiki>vol. 1</nowiki> shows error val = val:lower(); -- force parameter value to lower case for _, pattern in ipairs (cfg.vol_iss_pg_patterns.vi_patterns_t) do -- spin through the sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message (handler, name); -- add error message return; -- and done end end end --[=[-------------------------< G E T _ V _ N A M E _ T A B L E >---------------------------------------------- split apart a |vauthors= or |veditors= parameter. This function allows for corporate names, wrapped in doubled parentheses to also have commas; in the old version of the code, the doubled parentheses were included in the rendered citation and in the metadata. Individual author names may be wikilinked |vauthors=Jones AB, [[E. B. White|White EB]], ((Black, Brown, and Co.)) ]=] local function get_v_name_table (vparam, output_table, output_link_table) local _, accept = utilities.has_accept_as_written (vparam); if accept then utilities.add_prop_cat ('vanc-accept'); -- add properties category end local name_table = mw.text.split(vparam, "%s*,%s*"); -- names are separated by commas local wl_type, label, link; -- wl_type not used here; just a placeholder local i = 1; while name_table[i] do if name_table[i]:match ('^%(%(.*[^%)][^%)]$') then -- first segment of corporate with one or more commas; this segment has the opening doubled parentheses local name = name_table[i]; i = i + 1; -- bump indexer to next segment while name_table[i] do name = name .. ', ' .. name_table[i]; -- concatenate with previous segments if name_table[i]:match ('^.*%)%)$') then -- if this table member has the closing doubled parentheses break; -- and done reassembling so end i = i + 1; -- bump indexer end table.insert (output_table, name); -- and add corporate name to the output table table.insert (output_link_table, ''); -- no wikilink else wl_type, label, link = utilities.is_wikilink (name_table[i]); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] table.insert (output_table, label); -- add this name if 1 == wl_type then table.insert (output_link_table, label); -- simple wikilink [[D]] else table.insert (output_link_table, link); -- no wikilink or [[L|D]]; add this link if there is one, else empty string end end i = i + 1; end return output_table; end --[[--------------------------< P A R S E _ V A U T H O R S _ V E D I T O R S >-------------------------------- This function extracts author / editor names from |vauthors= or |veditors= and finds matching |xxxxor-maskn= and |xxxxor-linkn= in args. It then returns a table of assembled names just as extract_names() does. Author / editor names in |vauthors= or |veditors= must be in Vancouver system style. Corporate or institutional names may sometimes be required and because such names will often fail the is_good_vanc_name() and other format compliance tests, are wrapped in doubled parentheses ((corporate name)) to suppress the format tests. Supports generational suffixes Jr, 2nd, 3rd, 4th–6th. This function sets the Vancouver error when a required comma is missing and when there is a space between an author's initials. ]] local function parse_vauthors_veditors (args, vparam, list_name) local names = {}; -- table of names assembled from |vauthors=, |author-maskn=, |author-linkn= local v_name_table = {}; local v_link_table = {}; -- when name is wikilinked, targets go in this table local etal = false; -- return value set to true when we find some form of et al. vauthors parameter local last, first, link, mask, suffix; local corporate = false; vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period) v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); -- names are separated by commas for i, v_name in ipairs(v_name_table) do first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor local accept_name; v_name, accept_name = utilities.has_accept_as_written (v_name); -- remove accept-this-as-written markup when it wraps all of <v_name> if accept_name then last = v_name; corporate = true; -- flag used in list_people() elseif string.find(v_name, "%s") then if v_name:find('[;%.]') then -- look for commonly occurring punctuation characters; add_vanc_error (cfg.err_msg_supl.punctuation, i); end local lastfirstTable = {} lastfirstTable = mw.text.split(v_name, "%s+") first = table.remove(lastfirstTable); -- removes and returns value of last element in table which should be initials or generational suffix if not mw.ustring.match (first, '^%u+$') then -- mw.ustring here so that later we will catch non-Latin characters suffix = first; -- not initials so assume that whatever we got is a generational suffix first = table.remove(lastfirstTable); -- get what should be the initials from the table end last = table.concat(lastfirstTable, ' ') -- returns a string that is the concatenation of all other names that are not initials and generational suffix if not utilities.is_set (last) then first = ''; -- unset last = v_name; -- last empty because something wrong with first add_vanc_error (cfg.err_msg_supl.name, i); end if mw.ustring.match (last, '%a+%s+%u+%s+%a+') then add_vanc_error (cfg.err_msg_supl['missing comma'], i); -- matches last II last; the case when a comma is missing end if mw.ustring.match (v_name, ' %u %u$') then -- this test is in the wrong place TODO: move or replace with a more appropriate test add_vanc_error (cfg.err_msg_supl.initials, i); -- matches a space between two initials end else last = v_name; -- last name or single corporate name? Doesn't support multiword corporate names? do we need this? end if utilities.is_set (first) then if not mw.ustring.match (first, "^%u?%u$") then -- first shall contain one or two upper-case letters, nothing else add_vanc_error (cfg.err_msg_supl.initials, i); -- too many initials; mixed case initials (which may be ok Romanization); hyphenated initials end is_good_vanc_name (last, first, suffix, i); -- check first and last before restoring the suffix which may have a non-Latin digit if utilities.is_set (suffix) then first = first .. ' ' .. suffix; -- if there was a suffix concatenate with the initials suffix = ''; -- unset so we don't add this suffix to all subsequent names end else if not corporate then is_good_vanc_name (last, '', nil, i); end end link = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ) or v_link_table[i]; mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); names[i] = {last = last, first = first, link = link, mask = mask, corporate = corporate}; -- add this assembled name to our names list end return names, etal; -- all done, return our list of names end --[[--------------------------< S E L E C T _ A U T H O R _ E D I T O R _ S O U R C E >------------------------ Select one of |authors=, |authorn= / |lastn / firstn=, or |vauthors= as the source of the author name list or select one of |editorn= / editor-lastn= / |editor-firstn= or |veditors= as the source of the editor name list. Only one of these appropriate three will be used. The hierarchy is: |authorn= (and aliases) highest and |authors= lowest; |editorn= (and aliases) highest and |veditors= lowest (support for |editors= withdrawn) When looking for |authorn= / |editorn= parameters, test |xxxxor1= and |xxxxor2= (and all of their aliases); stops after the second test which mimicks the test used in extract_names() when looking for a hole in the author name list. There may be a better way to do this, I just haven't discovered what that way is. Emits an error message when more than one xxxxor name source is provided. In this function, vxxxxors = vauthors or veditors; xxxxors = authors as appropriate. ]] local function select_author_editor_source (vxxxxors, xxxxors, args, list_name) local lastfirst = false; if utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 1 ) or -- do this twice in case we have a |first1= without a |last1=; this ... utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 1 ) or -- ... also catches the case where |first= is used with |vauthors= utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 2 ) or utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 2 ) then lastfirst = true; end if (utilities.is_set (vxxxxors) and true == lastfirst) or -- these are the three error conditions (utilities.is_set (vxxxxors) and utilities.is_set (xxxxors)) or (true == lastfirst and utilities.is_set (xxxxors)) then utilities.set_message ('err_redundant_parameters', utilities.substitute (cfg.special_case_translation.name_list_params, ('AuthorList' == list_name) and cfg.special_case_translation.author or cfg.special_case_translation.editor)); -- add error message end if true == lastfirst then return 1 end; -- return a number indicating which author name source to use if utilities.is_set (vxxxxors) then return 2 end; if utilities.is_set (xxxxors) then return 3 end; return 1; -- no authors so return 1; this allows missing author name test to run in case there is a first without last end --[[--------------------------< I S _ V A L I D _ P A R A M E T E R _ V A L U E >------------------------------ This function is used to validate a parameter's assigned value for those parameters that have only a limited number of allowable values (yes, y, true, live, dead, etc.). When the parameter value has not been assigned a value (missing or empty in the source template) the function returns the value specified by ret_val. If the parameter value is one of the list of allowed values returns the translated value; else, emits an error message and returns the value specified by ret_val. TODO: explain <invert> ]] local function is_valid_parameter_value (value, name, possible, ret_val, invert) if not utilities.is_set (value) then return ret_val; -- an empty parameter is ok end if (not invert and utilities.in_array (value, possible)) then -- normal; <value> is in <possible> table return cfg.keywords_xlate[value]; -- return translation of parameter keyword elseif invert and not utilities.in_array (value, possible) then -- invert; <value> is not in <possible> table return value; -- return <value> as it is else utilities.set_message ('err_invalid_param_val', {name, value}); -- not an allowed value so add error message return ret_val; end end --[[--------------------------< T E R M I N A T E _ N A M E _ L I S T >---------------------------------------- This function terminates a name list (author, contributor, editor) with a separator character (sepc) and a space when the last character is not a sepc character or when the last three characters are not sepc followed by two closing square brackets (close of a wikilink). When either of these is true, the name_list is terminated with a single space character. ]] local function terminate_name_list (name_list, sepc) if (string.sub (name_list, -3, -1) == sepc .. '. ') then -- if already properly terminated return name_list; -- just return the name list elseif (string.sub (name_list, -1, -1) == sepc) or (string.sub (name_list, -3, -1) == sepc .. ']]') then -- if last name in list ends with sepc char return name_list .. " "; -- don't add another else return name_list .. sepc .. ' '; -- otherwise terminate the name list end end --[[-------------------------< F O R M A T _ V O L U M E _ I S S U E >----------------------------------------- returns the concatenation of the formatted volume and issue (or journal article number) parameters as a single string; or formatted volume or formatted issue, or an empty string if neither are set. ]] local function format_volume_issue (volume, issue, article, cite_class, origin, sepc, lower) if not utilities.is_set (volume) and not utilities.is_set (issue) and not utilities.is_set (article) then return ''; end -- same condition as in format_pages_sheets() local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); local is_numeric_vol = volume and (volume:match ('^[MDCLXVI]+$') or volume:match ('^%d+$')); -- is only uppercase roman numerals or only digits? local is_long_vol = volume and (4 < mw.ustring.len(volume)); -- is |volume= value longer than 4 characters? if volume and (not is_numeric_vol and is_long_vol) then -- when not all digits or Roman numerals, is |volume= longer than 4 characters? utilities.add_prop_cat ('long-vol'); -- yes, add properties cat end if is_journal then -- journal-style formatting local vol = ''; if utilities.is_set (volume) then if is_numeric_vol then -- |volume= value all digits or all uppercase Roman numerals? vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, volume}); -- render in bold face elseif is_long_vol then -- not all digits or Roman numerals; longer than 4 characters? vol = utilities.substitute (cfg.messages['j-vol'], {sepc, utilities.hyphen_to_dash (volume)}); -- not bold else -- four or fewer characters vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, utilities.hyphen_to_dash (volume)}); -- bold end end vol = vol .. (utilities.is_set (issue) and utilities.substitute (cfg.messages['j-issue'], issue) or '') vol = vol .. (utilities.is_set (article) and utilities.substitute (cfg.messages['j-article-num'], article) or '') return vol; end if 'podcast' == cite_class and utilities.is_set (issue) then return wrap_msg ('issue', {sepc, issue}, lower); end if 'conference' == cite_class and utilities.is_set (article) then -- |article-number= supported only in journal and conference cites if utilities.is_set (volume) and utilities.is_set (article) then -- both volume and article number return wrap_msg ('vol-art', {sepc, utilities.hyphen_to_dash (volume), article}, lower); elseif utilities.is_set (article) then -- article number alone; when volume alone, handled below return wrap_msg ('art', {sepc, article}, lower); end end -- all other types of citation if utilities.is_set (volume) and utilities.is_set (issue) then return wrap_msg ('vol-no', {sepc, utilities.hyphen_to_dash (volume), issue}, lower); elseif utilities.is_set (volume) then return wrap_msg ('vol', {sepc, utilities.hyphen_to_dash (volume)}, lower); else return wrap_msg ('issue', {sepc, issue}, lower); end end --[[-------------------------< F O R M A T _ P A G E S _ S H E E T S >----------------------------------------- adds static text to one of |page(s)= or |sheet(s)= values and returns it with all of the others set to empty strings. The return order is: page, pages, sheet, sheets Singular has priority over plural when both are provided. ]] local function format_pages_sheets (page, pages, sheet, sheets, cite_class, origin, sepc, nopp, lower) if 'map' == cite_class then -- only cite map supports sheet(s) as in-source locators if utilities.is_set (sheet) then if 'journal' == origin then return '', '', wrap_msg ('j-sheet', sheet, lower), ''; else return '', '', wrap_msg ('sheet', {sepc, sheet}, lower), ''; end elseif utilities.is_set (sheets) then if 'journal' == origin then return '', '', '', wrap_msg ('j-sheets', sheets, lower); else return '', '', '', wrap_msg ('sheets', {sepc, sheets}, lower); end end end local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); if utilities.is_set (page) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], page), '', '', ''; elseif not nopp then return utilities.substitute (cfg.messages['p-prefix'], {sepc, page}), '', '', ''; else return utilities.substitute (cfg.messages['nopp'], {sepc, page}), '', '', ''; end elseif utilities.is_set (pages) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], pages), '', '', ''; elseif tonumber(pages) ~= nil and not nopp then -- if pages is only digits, assume a single page number return '', utilities.substitute (cfg.messages['p-prefix'], {sepc, pages}), '', ''; elseif not nopp then return '', utilities.substitute (cfg.messages['pp-prefix'], {sepc, pages}), '', ''; else return '', utilities.substitute (cfg.messages['nopp'], {sepc, pages}), '', ''; end end return '', '', '', ''; -- return empty strings end --[[--------------------------< I N S O U R C E _ L O C _ G E T >---------------------------------------------- returns one of the in-source locators: page, pages, or at. If any of these are interwiki links to Wikisource, returns the label portion of the interwiki-link as plain text for use in COinS. This COinS thing is done because here we convert an interwiki-link to an external link and add an icon span around that; get_coins_pages() doesn't know about the span. TODO: should it? TODO: add support for sheet and sheets?; streamline; TODO: make it so that this function returns only one of the three as the single in-source (the return value assigned to a new name)? ]] local function insource_loc_get (page, page_orig, pages, pages_orig, at) local ws_url, ws_label, coins_pages, L; -- for Wikisource interwiki-links; TODO: this corrupts page metadata (span remains in place after cleanup; fix there?) if utilities.is_set (page) then if utilities.is_set (pages) or utilities.is_set (at) then pages = ''; -- unset the others at = ''; end extra_text_in_page_check (page, page_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (page); -- make ws URL from |page= interwiki link; link portion L becomes tooltip label if ws_url then page = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in page'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? page = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, page}); coins_pages = ws_label; end elseif utilities.is_set (pages) then if utilities.is_set (at) then at = ''; -- unset end extra_text_in_page_check (pages, pages_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (pages); -- make ws URL from |pages= interwiki link; link portion L becomes tooltip label if ws_url then pages = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in pages'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? pages = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, pages}); coins_pages = ws_label; end elseif utilities.is_set (at) then ws_url, ws_label, L = wikisource_url_make (at); -- make ws URL from |at= interwiki link; link portion L becomes tooltip label if ws_url then at = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in at'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? at = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, at}); coins_pages = ws_label; end end return page, pages, at, coins_pages; end --[[--------------------------< I S _ U N I Q U E _ A R C H I V E _ U R L >------------------------------------ add error message when |archive-url= value is same as |url= or chapter-url= (or alias...) value ]] local function is_unique_archive_url (archive, url, c_url, source, date) if utilities.is_set (archive) then if archive == url or archive == c_url then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); -- add error message return '', ''; -- unset |archive-url= and |archive-date= because same as |url= or |chapter-url= end end return archive, date; end --[=[-------------------------< A R C H I V E _ U R L _ C H E C K >-------------------------------------------- Check archive.org URLs to make sure they at least look like they are pointing at valid archives and not to the save snapshot URL or to calendar pages. When the archive URL is 'https://web.archive.org/save/' (or http://...) archive.org saves a snapshot of the target page in the URL. That is something that Wikipedia should not allow unwitting readers to do. When the archive.org URL does not have a complete timestamp, archive.org chooses a snapshot according to its own algorithm or provides a calendar 'search' result. [[WP:ELNO]] discourages links to search results. This function looks at the value assigned to |archive-url= and returns empty strings for |archive-url= and |archive-date= and an error message when: |archive-url= holds an archive.org save command URL |archive-url= is an archive.org URL that does not have a complete timestamp (YYYYMMDDhhmmss 14 digits) in the correct place otherwise returns |archive-url= and |archive-date= There are two mostly compatible archive.org URLs: //web.archive.org/<timestamp>... -- the old form //web.archive.org/web/<timestamp>... -- the new form The old form does not support or map to the new form when it contains a display flag. There are four identified flags ('id_', 'js_', 'cs_', 'im_') but since archive.org ignores others following the same form (two letters and an underscore) we don't check for these specific flags but we do check the form. This function supports a preview mode. When the article is rendered in preview mode, this function may return a modified archive URL: for save command errors, return undated wildcard (/*/) for timestamp errors when the timestamp has a wildcard, return the URL unmodified for timestamp errors when the timestamp does not have a wildcard, return with timestamp limited to six digits plus wildcard (/yyyymm*/) A secondary function is to return an archive-url timestamp from those urls that have them (archive.org and archive.today). The timestamp is used by validation.archive_date_check() to see if the value in |archive-date= matches the timestamp in the archive url. ]=] local function archive_url_check (url, date) local err_msg = ''; -- start with the error message empty local path, timestamp, flag; -- portions of the archive.org URL local function is_ts_date_valid (timestamp, origin_date) -- local function to validate archive url taimestamp date; time ignored local y, m, d = timestamp:match ('(%d%d%d%d)(%d%d)(%d%d)'); -- split into parts if y and validation.is_valid_date (y, m, d) and (tonumber (y) >= origin_date) then -- <origin_date> is 1996 for archive.org; 2012 for archive.today return true; end end timestamp = url:match ('//archive.today/(%d%d%d%d%d%d%d%d%d%d%d%d%d%d)/') or -- get timestamp from archive.today urls url:match ('//archive.today/(%d%d%d%d%.%d%d%.%d%d%-%d%d%d%d%d%d)/'); -- this timestamp needs cleanup if timestamp then -- if this is an archive.today url ... timestamp = timestamp:gsub ('[%.%-]', ''); -- strip dots and dashes if not is_ts_date_valid (timestamp, 2012) then -- is ymd portion of timestamp a valid date? utilities.set_message ('err_archive_url', {cfg.err_msg_supl.timestamp}); -- no; set error message; if is_preview_mode then return url, date; -- preview mode so return ArchiveURL, ArchiveDate; suppress timestamp because invalid else return '', ''; -- return empty strings for ArchiveURL and ArchiveDate end else return url, date, timestamp; -- return ArchiveURL, ArchiveDate, and timestamp (dots and dashes removed) from |archive-url=, and done end end -- here for archive.org urls if (not url:match('//web%.archive%.org/')) and (not url:match('//liveweb%.archive%.org/')) then -- also deprecated liveweb Wayback machine URL return url, date; -- not an archive.org archive, return ArchiveURL and ArchiveDate end if url:match('//web%.archive%.org/save/') then -- if a save command URL, we don't want to allow saving of the target page err_msg = cfg.err_msg_supl.save; url = url:gsub ('(//web%.archive%.org)/save/', '%1/*/', 1); -- for preview mode: modify ArchiveURL elseif url:match('//liveweb%.archive%.org/') then err_msg = cfg.err_msg_supl.liveweb; else path, timestamp, flag = url:match('//web%.archive%.org/([^%d]*)(%d+)([^/]*)/'); -- split out some of the URL parts for evaluation if not path then -- malformed in some way; pattern did not match err_msg = cfg.err_msg_supl.timestamp; elseif 14 ~= timestamp:len() then -- path and flag optional, must have 14-digit timestamp here err_msg = cfg.err_msg_supl.timestamp; if '*' ~= flag then local replacement = timestamp:match ('^%d%d%d%d%d%d') or timestamp:match ('^%d%d%d%d'); -- get the first 6 (YYYYMM) or first 4 digits (YYYY) if replacement then -- nil if there aren't at least 4 digits (year) replacement = replacement .. string.rep ('0', 14 - replacement:len()); -- year or yearmo (4 or 6 digits) zero-fill to make 14-digit timestamp url=url:gsub ('(//web%.archive%.org/[^%d]*)%d[^/]*', '%1' .. replacement .. '*', 1) -- for preview, modify ts to 14 digits plus splat for calendar display end end elseif not is_ts_date_valid (timestamp, 1996) then -- is ymd portion of timestamp a valid date? err_msg = cfg.err_msg_supl.timestamp; timestamp = nil; -- unset because invalid elseif utilities.is_set (path) and 'web/' ~= path then -- older archive URLs do not have the extra 'web/' path element err_msg = cfg.err_msg_supl.path; elseif utilities.is_set (flag) and not utilities.is_set (path) then -- flag not allowed with the old form URL (without the 'web/' path element) err_msg = cfg.err_msg_supl.flag; elseif utilities.is_set (flag) and not flag:match ('%a%a_') then -- flag if present must be two alpha characters and underscore (requires 'web/' path element) err_msg = cfg.err_msg_supl.flag; else return url, date, timestamp; -- return ArchiveURL, ArchiveDate, and timestamp from |archive-url= end end -- if here, something not right so utilities.set_message ('err_archive_url', {err_msg}); -- add error message and if is_preview_mode then return url, date, timestamp; -- preview mode so return ArchiveURL, ArchiveDate, and timestamp from |archive-url= else return '', ''; -- return empty strings for ArchiveURL and ArchiveDate end end --[[--------------------------< P L A C E _ C H E C K >-------------------------------------------------------- check |place=, |publication-place=, |location= to see if these params include digits. This function added because many editors misuse location to specify the in-source location (|page(s)= and |at= are supposed to do that) returns the original parameter value without modification; added maint cat when parameter value contains digits ]] local function place_check (param_val) if not utilities.is_set (param_val) then -- parameter empty or omitted return param_val; -- return that empty state end if mw.ustring.find (param_val, '%d') then -- not empty, are there digits in the parameter value utilities.set_message ('maint_location'); -- yep, add maint cat end return param_val; -- and done end --[[--------------------------< I S _ A R C H I V E D _ C O P Y >---------------------------------------------- compares |title= to 'Archived copy' (placeholder added by bots that can't find proper title); if matches, return true; nil else ]] local function is_archived_copy (title) title = mw.ustring.lower(title); -- switch title to lower case if title:find (cfg.special_case_translation.archived_copy.en) then -- if title is 'Archived copy' return true; elseif cfg.special_case_translation.archived_copy['local'] then if mw.ustring.find (title, cfg.special_case_translation.archived_copy['local']) then -- mw.ustring() because might not be Latin script return true; end end end --[[--------------------------< D I S P L A Y _ N A M E S _ S E L E C T >-------------------------------------- for any of the |display-authors=, |display-editors=, etc parameters, select either the local or global setting. When both are present, look at <local_display_names> value. When the value is some sort of 'et al.'string, special handling is required. When {{cs1 config}} has |display-<namelist>= AND this template has |display-<namelist>=etal AND: the number of names specified by <number_of_names> is: greater than the number specified in the global |display-<namelist>= parameter (<global_display_names>) use global |display-<namelist>= parameter value set overridden maint category less than or equal to the number specified in the global |display-<namelist>= parameter use local |display-<namelist>= parameter value The purpose of this function is to prevent categorizing a template that has fewer names than the global setting to keep the etal annotation specified by <local_display_names>. ]] local function display_names_select (global_display_names, local_display_names, param_name, number_of_names, test) if global_display_names and utilities.is_set (local_display_names) then -- when both if 'etal' == local_display_names:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings number_of_names = tonumber (number_of_names); -- convert these to numbers for comparison local global_display_names_num = tonumber (global_display_names); -- <global_display_names> not set when parameter value is not digits if number_of_names > global_display_names_num then -- template has more names than global config allows to be displayed? utilities.set_message ('maint_overridden_setting'); -- set a maint message because global is overriding local |display-<namelist>=etal return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local because fewer names so let <local_display_names> control end end -- here when <global_display_names> and <local_display_names> both numbers; <global_display_names> controls utilities.set_message ('maint_overridden_setting'); -- set a maint message return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) end -- here when only one of <global_display_names> or <local_display_names> set if global_display_names then return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local end end --[[--------------------------< M O D E _ S E T >-------------------------------------------------------------- fetch global mode setting from {{cs1 config}} (if present) or from |mode= (if present); global setting overrides local |mode= parameter value. When both are present, emit maintenance message ]] local function mode_set (Mode, Mode_origin) local mode; if cfg.global_cs1_config_t['Mode'] then -- global setting in {{cs1 config}}; nil when empty or assigned value invalid mode = is_valid_parameter_value (cfg.global_cs1_config_t['Mode'], 'cs1 config: mode', cfg.keywords_lists['mode'], ''); -- error messaging 'param' here is a hoax else mode = is_valid_parameter_value (Mode, Mode_origin, cfg.keywords_lists['mode'], ''); end if cfg.global_cs1_config_t['Mode'] and utilities.is_set (Mode) then -- when template has |mode=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end return mode; end --[[--------------------------< Q U O T E _ M A K E >---------------------------------------------------------- create quotation from |quote=, |trans-quote=, and/or script-quote= with or without |quote-page= or |quote-pages= when any of those three quote parameters are set, this function unsets <PostScript>. When none of those parameters are set, |quote-page= and |quote-pages= are unset to nil so that they are not included in the template's metadata ]] local function quote_make (quote, trans_quote, script_quote, quote_page, quote_pages, nopp, sepc, postscript) if utilities.is_set (quote) or utilities.is_set (trans_quote) or utilities.is_set (script_quote) then if utilities.is_set (quote) then if quote:sub(1, 1) == '"' and quote:sub(-1, -1) == '"' then -- if first and last characters of quote are quote marks quote = quote:sub(2, -2); -- strip them off end end quote = kern_quotes (quote); -- kern if needed quote = utilities.wrap_style ('quoted-text', quote ); -- wrap in <q>...</q> tags if utilities.is_set (script_quote) then quote = script_concatenate (quote, script_quote, 'script-quote'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after quote is wrapped end if utilities.is_set (trans_quote) then if trans_quote:sub(1, 1) == '"' and trans_quote:sub(-1, -1) == '"' then -- if first and last characters of |trans-quote are quote marks trans_quote = trans_quote:sub(2, -2); -- strip them off end quote = quote .. " " .. utilities.wrap_style ('trans-quoted-title', trans_quote ); end if utilities.is_set (quote_page) or utilities.is_set (quote_pages) then -- add page prefix local quote_prefix = ''; if utilities.is_set (quote_page) then extra_text_in_page_check (quote_page, 'quote-page'); -- add to maint cat if |quote-page= value begins with what looks like p., pp., etc. if not nopp then quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_page}), '', '', ''; else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_page}), '', '', ''; end elseif utilities.is_set (quote_pages) then extra_text_in_page_check (quote_pages, 'quote-pages'); -- add to maint cat if |quote-pages= value begins with what looks like p., pp., etc. if tonumber(quote_pages) ~= nil and not nopp then -- if only digits, assume single page quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_pages}), '', ''; elseif not nopp then quote_prefix = utilities.substitute (cfg.messages['pp-prefix'], {sepc, quote_pages}), '', ''; else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_pages}), '', ''; end end quote = quote_prefix .. ": " .. quote; else quote = sepc .. " " .. quote; end postscript = ""; -- cs1|2 does not supply terminal punctuation when |quote= is set elseif utilities.is_set (quote_page) or utilities.is_set (quote_pages) then quote_page = nil; -- unset; these require |quote=; TODO: error message? quote_pages = nil; end return quote, quote_page, quote_pages, postscript; end --[[--------------------------< C H E C K _ P U B L I S H E R _ N A M E >-------------------------------------- look for variations of '<text>: <text>' that might be '<location>: <publisher>' in |publisher= parameter value. when found, emit a maintenance message; return nil else <publisher> is the value assigned to |publisher= or |institution= ]] local function check_publisher_name (publisher) local patterns_t = { '^[%w%s]+%s*:%s*[%w%s]+$', -- plain text <location>: <publisher> '^%[+[%w%s:|]+%]+%s*:%s*[%w%s]+$', -- partially wikilinked [[<location>]]: <publisher> '^[%w%s]+%s*:%s*%[+[%w%s:|]+%]+$', -- partially wikilinked <location>: [[<publisher>]] '^%[+[%w%s:|]+%]+%s*:%s*%[+[%w%s:|]+%]+$', -- wikilinked [[<location>]]: [[<publisher>]] } for _, pattern in ipairs (patterns_t) do -- spin through the patterns_t sequence if mw.ustring.match (publisher, pattern) then -- does this pattern match? utilities.set_message ('maint_publisher_location'); -- set a maint message return; -- and done end end end --[[--------------------------< I S _ P A G E _ A R T _ N U M >------------------------------------------------ compare the trailing (rightmost) characters of the |doi= value against the whole value assigned to |page(s)=. return boolean true when: |page(s)= has exactly 8 digits and a dot between the fourth and fifth digits matches the trailing 9 characters of the |doi= value: |page=12345678 → |page=1234.5678 matches |doi=10.xxxx/yyyy1234.5678 |page(s)= is 5 or more characters and matches |doi= values's trailing characters |page(s)= begins with a lowercase 'e' and |page(s)= without the 'e' matches |doi= values's trailing characters: |page=e12345 → |page=12345 matches |doi=10.xxxx/yyyy12345 |page(s)= begins with a uppercase 'CD' followed by (typically) six digits matches |doi= values that ends with 'CDxxxxxx.pubx' (where 'x' is any single digit) return nil when |page(s)= values: are ranges separated by underscore, hyphen, emdash, endash, figure dash, or minus character are comma- or semicolon-separated lists of pages have external urls (has text 'http') are digit-only values less than 10000 do not match |doi= values's trailing characters ]] local function is_page_art_num (page, doi) if not (utilities.is_set (page) and utilities.is_set (doi)) then -- both required return; -- abandon; nothing to do end if page:match ('[,;_−–—‒%-]') then -- when |page(s)= might be a page range or a separated list of pages return; -- abandon end page = page:lower(); -- because doi names are case insensitive doi = doi:lower(); -- force these to lowercase for testing if page:match ('http') then -- when |page(s)= appears to hold a url return; -- abandon end if tonumber (page) then -- is |page(s)= digits only if 10000 > tonumber (page) then -- when |page(s)= less than 10000 return; -- abandon end if doi:match (page .. '$') then -- digits only page number match the last digits in |doi=? return true; end if 8 == page:len() then -- special case when |page(s)= is exactly 8 digits local dot_page = page:gsub ('(%d%d%d%d)(%d%d%d%d)', '%1.%2'); -- make a |page=xxxx.yyyy version commonly used in |doi= if doi:match (dot_page .. '$') then -- 8-digit dotted page number match the last characters in |doi=? return true; end end else -- here when |page(s)= is alpha-numeric if 4 < page:len() then -- when |page(s)= is five or more characters if doi:match (page .. '$') then -- alpha-numeric page match the last characters in |doi=? return true; end local epage = page:match ('^e([%w]+)$'); -- if first character of |page= is 'e', remove it if epage and doi:match (epage .. '$') then -- page number match the last characters in |doi=? return true; end local cdpage = page:match ('^cd%d+$'); -- if first characters of |page= are 'CD' and last characters are digits (typically 6 digits) if cdpage and doi:match (cdpage .. '%.pub%d$') then -- page number matches doi 'CDxxxxxx.pubx' where 'x' is a digit return true; end end end end --[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------ This is the main function doing the majority of the citation formatting. ]] local function citation0( config, args ) --[[ Load Input Parameters The argument_wrapper facilitates the mapping of multiple aliases to single internal variable. ]] local A = argument_wrapper ( args ); local i -- Pick out the relevant fields from the arguments. Different citation templates -- define different field names for the same underlying things. local author_etal; local a = {}; -- authors list from |lastn= / |firstn= pairs or |vauthors= local Authors; local NameListStyle; if cfg.global_cs1_config_t['NameListStyle'] then -- global setting in {{cs1 config}} overrides local |name-list-style= parameter value; nil when empty or assigned value invalid NameListStyle = is_valid_parameter_value (cfg.global_cs1_config_t['NameListStyle'], 'cs1 config: name-list-style', cfg.keywords_lists['name-list-style'], ''); -- error messaging 'param' here is a hoax else NameListStyle = is_valid_parameter_value (A['NameListStyle'], A:ORIGIN('NameListStyle'), cfg.keywords_lists['name-list-style'], ''); end if cfg.global_cs1_config_t['NameListStyle'] and utilities.is_set (A['NameListStyle']) then -- when template has |name-list-style=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end local Collaboration = A['Collaboration']; do -- to limit scope of selected local selected = select_author_editor_source (A['Vauthors'], A['Authors'], args, 'AuthorList'); if 1 == selected then a, author_etal = extract_names (args, 'AuthorList'); -- fetch author list from |authorn= / |lastn= / |firstn=, |author-linkn=, and |author-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be a, author_etal = parse_vauthors_veditors (args, A['Vauthors'], 'AuthorList'); -- fetch author list from |vauthors=, |author-linkn=, and |author-maskn= elseif 3 == selected then Authors = A['Authors']; -- use content of |people= or |credits=; |authors= is deprecated; TODO: constrain |people= and |credits= to cite av media, episode, serial? end if utilities.is_set (Collaboration) then author_etal = true; -- so that |display-authors=etal not required end end local editor_etal; local e = {}; -- editors list from |editor-lastn= / |editor-firstn= pairs or |veditors= do -- to limit scope of selected local selected = select_author_editor_source (A['Veditors'], nil, args, 'EditorList'); -- support for |editors= withdrawn if 1 == selected then e, editor_etal = extract_names (args, 'EditorList'); -- fetch editor list from |editorn= / |editor-lastn= / |editor-firstn=, |editor-linkn=, and |editor-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be e, editor_etal = parse_vauthors_veditors (args, args.veditors, 'EditorList'); -- fetch editor list from |veditors=, |editor-linkn=, and |editor-maskn= end end local Chapter = A['Chapter']; -- done here so that we have access to |contribution= from |chapter= aliases local Chapter_origin = A:ORIGIN ('Chapter'); local Contribution; -- because contribution is required for contributor(s) if 'contribution' == Chapter_origin then Contribution = Chapter; -- get the name of the contribution end local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (A['Periodical']) then -- |contributor= and |contribution= only supported in book cites c = extract_names (args, 'ContributorList'); -- fetch contributor list from |contributorn= / |contributor-lastn=, -firstn=, -linkn=, -maskn= if 0 < #c then if not utilities.is_set (Contribution) then -- |contributor= requires |contribution= utilities.set_message ('err_contributor_missing_required_param', 'contribution'); -- add missing contribution error message c = {}; -- blank the contributors' table; it is used as a flag later end if 0 == #a then -- |contributor= requires |author= utilities.set_message ('err_contributor_missing_required_param', 'author'); -- add missing author error message c = {}; -- blank the contributors' table; it is used as a flag later end end else -- if not a book cite if utilities.select_one (args, cfg.aliases['ContributorList-Last'], 'err_redundant_parameters', 1 ) then -- are there contributor name list parameters? utilities.set_message ('err_contributor_ignored'); -- add contributor ignored error message end Contribution = nil; -- unset end local Title = A['Title']; local TitleLink = A['TitleLink']; local auto_select = ''; -- default is auto local accept_link; TitleLink, accept_link = utilities.has_accept_as_written (TitleLink, true); -- test for accept-this-as-written markup if (not accept_link) and utilities.in_array (TitleLink, {'none', 'pmc', 'doi'}) then -- check for special keywords auto_select = TitleLink; -- remember selection for later TitleLink = ''; -- treat as if |title-link= would have been empty end TitleLink = link_title_ok (TitleLink, A:ORIGIN ('TitleLink'), Title, 'title'); -- check for wiki-markup in |title-link= or wiki-markup in |title= when |title-link= is set local Section = ''; -- {{cite map}} only; preset to empty string for concatenation if not used if 'map' == config.CitationClass and 'section' == Chapter_origin then Section = A['Chapter']; -- get |section= from |chapter= alias list; |chapter= and the other aliases not supported in {{cite map}} Chapter = ''; -- unset for now; will be reset later from |map= if present end local Periodical = A['Periodical']; local Periodical_origin = A:ORIGIN('Periodical'); local ScriptPeriodical = A['ScriptPeriodical']; local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical'); local TransPeriodical = A['TransPeriodical']; local TransPeriodical_origin = A:ORIGIN ('TransPeriodical'); if (utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical))) then local param; if utilities.is_set (Periodical) then -- get a parameter name from one of these periodical related meta-parameters Periodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = Periodical_origin -- get parameter name for error messaging elseif utilities.is_set (TransPeriodical) then TransPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = TransPeriodical_origin; -- get parameter name for error messaging elseif utilities.is_set (ScriptPeriodical) then ScriptPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = ScriptPeriodical_origin; -- get parameter name for error messaging end if utilities.is_set (param) then -- if we found one utilities.set_message ('err_periodical_ignored', {param}); -- emit an error message end end if utilities.is_set (Periodical) then local i; Periodical, i = utilities.strip_apostrophe_markup (Periodical); -- strip apostrophe markup so that metadata isn't contaminated if i then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {Periodical_origin}); end end if 'mailinglist' == config.CitationClass then -- special case for {{cite mailing list}} if utilities.is_set (Periodical) and utilities.is_set (A ['MailingList']) then -- both set emit an error TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', Periodical_origin) .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'mailinglist')}); end Periodical = A ['MailingList']; -- error or no, set Periodical to |mailinglist= value because this template is {{cite mailing list}} Periodical_origin = A:ORIGIN('MailingList'); end -- web and news not tested for now because of -- Wikipedia:Administrators%27_noticeboard#Is_there_a_semi-automated_tool_that_could_fix_these_annoying_"Cite_Web"_errors? if not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) then -- 'periodical' templates require periodical parameter -- local p = {['journal'] = 'journal', ['magazine'] = 'magazine', ['news'] = 'newspaper', ['web'] = 'website'}; -- for error message local p = {['journal'] = 'journal', ['magazine'] = 'magazine'}; -- for error message if p[config.CitationClass] then utilities.set_message ('err_missing_periodical', {config.CitationClass, p[config.CitationClass]}); end end local Volume; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) then if not utilities.in_array (Periodical_origin, cfg.citation_no_volume_t) then -- {{citation}} does not render |volume= when these parameters are used Volume = A['Volume']; -- but does for all other 'periodicals' end elseif utilities.is_set (ScriptPeriodical) then if 'script-website' ~= ScriptPeriodical_origin then -- {{citation}} does not render volume for |script-website= Volume = A['Volume']; -- but does for all other 'periodicals' end else Volume = A['Volume']; -- and does for non-'periodical' cites end elseif utilities.in_array (config.CitationClass, cfg.templates_using_volume) then -- render |volume= for cs1 according to the configuration settings Volume = A['Volume']; end extra_text_in_vol_iss_check (Volume, A:ORIGIN ('Volume'), 'v'); local Issue; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) and utilities.in_array (Periodical_origin, cfg.citation_issue_t) then -- {{citation}} may render |issue= when these parameters are used Issue = A['Issue']; end elseif utilities.in_array (config.CitationClass, cfg.templates_using_issue) then -- conference & map books do not support issue; {{citation}} listed here because included in settings table if not (utilities.in_array (config.CitationClass, {'conference', 'map', 'citation'}) and not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical))) then Issue = A['Issue']; end end local ArticleNumber; if utilities.in_array (config.CitationClass, {'journal', 'conference'}) or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then ArticleNumber = A['ArticleNumber']; end extra_text_in_vol_iss_check (Issue, A:ORIGIN ('Issue'), 'i'); Issue = utilities.hyphen_to_dash (Issue); local Page; local Pages; local At; local QuotePage; local QuotePages; if not utilities.in_array (config.CitationClass, cfg.templates_not_using_page) then -- TODO: rewrite to emit ignored parameter error message? Page = A['Page']; Pages = utilities.hyphen_to_dash (A['Pages']); At = A['At']; QuotePage = A['QuotePage']; QuotePages = utilities.hyphen_to_dash (A['QuotePages']); end local NoPP = is_valid_parameter_value (A['NoPP'], A:ORIGIN('NoPP'), cfg.keywords_lists['yes_true_y'], nil); local Mode = mode_set (A['Mode'], A:ORIGIN('Mode')); -- separator character and postscript local sepc, PostScript = set_style (Mode:lower(), A['PostScript'], config.CitationClass); local Quote; Quote, QuotePage, QuotePages, PostScript = quote_make (A['Quote'], A['TransQuote'], A['ScriptQuote'], QuotePage, QuotePages, NoPP, sepc, PostScript); local Edition = A['Edition']; local PublicationPlace = place_check (A['PublicationPlace'], A:ORIGIN('PublicationPlace')); local Place = place_check (A['Place'], A:ORIGIN('Place')); local PublisherName = A['PublisherName']; local PublisherName_origin = A:ORIGIN('PublisherName'); if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then local i = 0; PublisherName, i = utilities.strip_apostrophe_markup (PublisherName); -- strip apostrophe markup so that metadata isn't contaminated; publisher is never italicized if i and (0 < i) then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {PublisherName_origin}); end end if ('document' == config.CitationClass) and not utilities.is_set (PublisherName) then utilities.set_message ('err_missing_publisher', {config.CitationClass, 'publisher'}); end local Newsgroup = A['Newsgroup']; -- TODO: strip apostrophe markup? local Newsgroup_origin = A:ORIGIN('Newsgroup'); if 'newsgroup' == config.CitationClass then if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then -- general use parameter |publisher= not allowed in cite newsgroup utilities.set_message ('err_parameter_ignored', {PublisherName_origin}); end PublisherName = nil; -- ensure that this parameter is unset for the time being; will be used again after COinS end if 'book' == config.CitationClass or 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then local accept; PublisherName, accept = utilities.has_accept_as_written (PublisherName); -- check for and remove accept-as-written markup from |publisher= wrapped if not accept then -- when no accept-as-written markup check_publisher_name (PublisherName); -- emit maint message when |publisher= might be prefixed with publisher's location end end local URL = A['URL']; -- TODO: better way to do this for URL, ChapterURL, and MapURL? local UrlAccess = is_valid_parameter_value (A['UrlAccess'], A:ORIGIN('UrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (URL) and utilities.is_set (UrlAccess) then UrlAccess = nil; utilities.set_message ('err_param_access_requires_param', 'url'); end local ChapterURL = A['ChapterURL']; local ChapterUrlAccess = is_valid_parameter_value (A['ChapterUrlAccess'], A:ORIGIN('ChapterUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (ChapterURL) and utilities.is_set (ChapterUrlAccess) then ChapterUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {A:ORIGIN('ChapterUrlAccess'):gsub ('%-access', '')}); end local MapUrlAccess = is_valid_parameter_value (A['MapUrlAccess'], A:ORIGIN('MapUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (A['MapURL']) and utilities.is_set (MapUrlAccess) then MapUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {'map-url'}); end local this_page = mw.title.getCurrentTitle(); -- also used for COinS and for language local no_tracking_cats = is_valid_parameter_value (A['NoTracking'], A:ORIGIN('NoTracking'), cfg.keywords_lists['yes_true_y'], nil); -- check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories if not utilities.is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page if cfg.uncategorized_namespaces[this_page.namespace] then -- is this page's namespace id one of the uncategorized namespace ids? no_tracking_cats = "true"; -- set no_tracking_cats end for _, v in ipairs (cfg.uncategorized_subpages) do -- cycle through page name patterns if this_page.text:match (v) then -- test page name against each pattern no_tracking_cats = "true"; -- set no_tracking_cats break; -- bail out if one is found end end end -- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it) utilities.select_one (args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'err_redundant_parameters'); -- this is a dummy call simply to get the error message and category local coins_pages; Page, Pages, At, coins_pages = insource_loc_get (Page, A:ORIGIN('Page'), Pages, A:ORIGIN('Pages'), At); if utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- both |publication-place= and |place= (|location=) allowed if different utilities.add_prop_cat ('location-test'); -- add property cat to evaluate how often PublicationPlace and Place are used together if PublicationPlace == Place then Place = ''; -- unset; don't need both if they are the same end elseif not utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- when only |place= (|location=) is set ... PublicationPlace = Place; -- promote |place= (|location=) to |publication-place end if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same local URL_origin = A:ORIGIN('URL'); -- get name of parameter that holds URL local ChapterURL_origin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL local ScriptChapter = A['ScriptChapter']; local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); local Format = A['Format']; local ChapterFormat = A['ChapterFormat']; local TransChapter = A['TransChapter']; local TransChapter_origin = A:ORIGIN ('TransChapter'); local TransTitle = A['TransTitle']; local ScriptTitle = A['ScriptTitle']; --[[ Parameter remapping for cite encyclopedia: When the citation has these parameters: |encyclopedia= and |title= then map |title= to |article= and |encyclopedia= to |title= for rendering |encyclopedia= and |article= then map |encyclopedia= to |title= for rendering |trans-title= maps to |trans-chapter= when |title= is re-mapped |url= maps to |chapter-url= when |title= is remapped All other combinations of |encyclopedia=, |title=, and |article= are not modified ]] local Encyclopedia = A['Encyclopedia']; -- used as a flag by this module and by ~/COinS local ScriptEncyclopedia = A['ScriptEncyclopedia']; local TransEncyclopedia = A['TransEncyclopedia']; if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then -- emit error message when Encyclopedia set but template is other than {{cite encyclopedia}} or {{citation}} if 'encyclopaedia' ~= config.CitationClass and 'citation' ~= config.CitationClass then if utilities.is_set (Encyclopedia) then utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('Encyclopedia')}); else utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('ScriptEncyclopedia')}); end Encyclopedia = nil; -- unset these because not supported by this template ScriptEncyclopedia = nil; TransEncyclopedia = nil; end elseif utilities.is_set (TransEncyclopedia) then utilities.set_message ('err_trans_missing_title', {'encyclopedia'}); end if ('encyclopaedia' == config.CitationClass) or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Periodical) and utilities.is_set (Encyclopedia) then -- when both parameters set emit an error message; {{citation}} only; Periodical not allowed in {{cite encyclopedia}} utilities.set_message ('err_periodical_ignored', {Periodical_origin}); end if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then Periodical = Encyclopedia; -- error or no, set Periodical to Encyclopedia for rendering; {{citation}} could (not legitimately) have both; use Encyclopedia Periodical_origin = A:ORIGIN ('Encyclopedia'); ScriptPeriodical = ScriptEncyclopedia; ScriptPeriodical_origin = A:ORIGIN ('ScriptEncyclopedia'); if utilities.is_set (Title) or utilities.is_set (ScriptTitle) then if not utilities.is_set (Chapter) then Chapter = Title; -- |encyclopedia= and |title= are set so map |title= params to |article= params for rendering ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle') TransChapter = TransTitle; ChapterURL = URL; ChapterURL_origin = URL_origin; ChapterUrlAccess = UrlAccess; ChapterFormat = Format; if not utilities.is_set (ChapterURL) and utilities.is_set (TitleLink) then Chapter = utilities.make_wikilink (TitleLink, Chapter); end Title = Periodical; -- now map |encyclopedia= params to |title= params for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; URL = ''; Format = ''; TitleLink = ''; end elseif utilities.is_set (Chapter) or utilities.is_set (ScriptChapter) then -- |title= not set Title = Periodical; -- |encyclopedia= set and |article= set so map |encyclopedia= to |title= for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; end end end -- special case for cite techreport. local ID = A['ID']; if (config.CitationClass == "techreport") then -- special case for cite techreport if utilities.is_set (A['Number']) then -- cite techreport uses 'number', which other citations alias to 'issue' if not utilities.is_set (ID) then -- can we use ID for the "number"? ID = A['Number']; -- yes, use it else -- ID has a value so emit error message utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'id') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'number')}); end end end -- Account for the oddity that is {{cite conference}}, before generation of COinS data. local ChapterLink -- = A['ChapterLink']; -- deprecated as a parameter but still used internally by cite episode local Conference = A['Conference']; local BookTitle = A['BookTitle']; local TransTitle_origin = A:ORIGIN ('TransTitle'); if 'conference' == config.CitationClass then if utilities.is_set (BookTitle) then Chapter = Title; Chapter_origin = 'title'; -- ChapterLink = TitleLink; -- |chapter-link= is deprecated ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; URL_origin = ''; ChapterFormat = Format; TransChapter = TransTitle; TransChapter_origin = TransTitle_origin; Title = BookTitle; Format = ''; -- TitleLink = ''; TransTitle = ''; URL = ''; end elseif 'speech' ~= config.CitationClass then Conference = ''; -- not cite conference or cite speech so make sure this is empty string end local cs2_lower = function (text) -- if mode is cs2, use lower case if (sepc ~= '.') then return text:lower(); end return text; end local use_lowercase = ( sepc == ',' ); -- controls capitalization of certain static text -- cite map oddities local Cartography = ""; local Scale = ""; local Sheet = A['Sheet'] or ''; local Sheets = A['Sheets'] or ''; if config.CitationClass == "map" then if utilities.is_set (Chapter) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'map') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', Chapter_origin)}); -- add error message end Chapter = A['Map']; Chapter_origin = A:ORIGIN('Map'); ChapterURL = A['MapURL']; ChapterURL_origin = A:ORIGIN('MapURL'); TransChapter = A['TransMap']; ScriptChapter = A['ScriptMap'] ScriptChapter_origin = A:ORIGIN('ScriptMap') ChapterUrlAccess = MapUrlAccess; ChapterFormat = A['MapFormat']; Cartography = A['Cartography']; if utilities.is_set ( Cartography ) then Cartography = sepc .. " " .. wrap_msg ('cartography', Cartography, use_lowercase); end Scale = A['Scale']; if utilities.is_set ( Scale ) then Scale = sepc .. " " .. Scale; end end -- Account for the oddities that are {{cite episode}} and {{cite serial}}, before generation of COinS data. local Series = A['Series']; if 'episode' == config.CitationClass or 'serial' == config.CitationClass then local SeriesLink = A['SeriesLink']; SeriesLink = link_title_ok (SeriesLink, A:ORIGIN ('SeriesLink'), Series, 'series'); -- check for wiki-markup in |series-link= or wiki-markup in |series= when |series-link= is set local Network = A['Network']; local Station = A['Station']; local s, n = {}, {}; -- do common parameters first if utilities.is_set (Network) then table.insert(n, Network); end if utilities.is_set (Station) then table.insert(n, Station); end ID = table.concat(n, sepc .. ' '); if 'episode' == config.CitationClass then -- handle the oddities that are strictly {{cite episode}} local Season = A['Season']; local SeriesNumber = A['SeriesNumber']; if utilities.is_set (Season) and utilities.is_set (SeriesNumber) then -- these are mutually exclusive so if both are set TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'season') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'seriesno')}); -- add error message SeriesNumber = ''; -- unset; prefer |season= over |seriesno= end -- assemble a table of parts concatenated later into Series if utilities.is_set (Season) then table.insert(s, wrap_msg ('season', Season, use_lowercase)); end if utilities.is_set (SeriesNumber) then table.insert(s, wrap_msg ('seriesnum', SeriesNumber, use_lowercase)); end if utilities.is_set (Issue) then table.insert(s, wrap_msg ('episode', Issue, use_lowercase)); end Issue = ''; -- unset because this is not a unique parameter Chapter = Title; -- promote title parameters to chapter ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle'); ChapterLink = TitleLink; -- alias |episode-link= TransChapter = TransTitle; ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; ChapterFormat = Format; Title = Series; -- promote series to title TitleLink = SeriesLink; Series = table.concat(s, sepc .. ' '); -- this is concatenation of season, seriesno, episode number if utilities.is_set (ChapterLink) and not utilities.is_set (ChapterURL) then -- link but not URL Chapter = utilities.make_wikilink (ChapterLink, Chapter); elseif utilities.is_set (ChapterLink) and utilities.is_set (ChapterURL) then -- if both are set, URL links episode; Series = utilities.make_wikilink (ChapterLink, Series); end URL = ''; -- unset TransTitle = ''; ScriptTitle = ''; Format = ''; else -- now oddities that are cite serial Issue = ''; -- unset because this parameter no longer supported by the citation/core version of cite serial Chapter = A['Episode']; -- TODO: make |episode= available to cite episode someday? if utilities.is_set (Series) and utilities.is_set (SeriesLink) then Series = utilities.make_wikilink (SeriesLink, Series); end Series = utilities.wrap_style ('italic-title', Series); -- series is italicized end end -- end of {{cite episode}} stuff -- handle type parameter for those CS1 citations that have default values local TitleType = A['TitleType']; local Degree = A['Degree']; if utilities.in_array (config.CitationClass, {'AV-media-notes', 'document', 'interview', 'mailinglist', 'map', 'podcast', 'pressrelease', 'report', 'speech', 'techreport', 'thesis'}) then TitleType = set_titletype (config.CitationClass, TitleType); if utilities.is_set (Degree) and "Thesis" == TitleType then -- special case for cite thesis TitleType = Degree .. ' ' .. cfg.title_types ['thesis']:lower(); end end if utilities.is_set (TitleType) then -- if type parameter is specified TitleType = utilities.substitute ( cfg.messages['type'], TitleType); -- display it in parentheses -- TODO: Hack on TitleType to fix bunched parentheses problem end -- legacy: promote PublicationDate to Date if neither Date nor Year are set. local Date = A['Date']; local Date_origin; -- to hold the name of parameter promoted to Date; required for date error messaging local PublicationDate = A['PublicationDate']; local Year = A['Year']; if utilities.is_set (Year) then validation.year_check (Year); -- returns nothing; emits maint message when |year= doesn't hold a 'year' value end if not utilities.is_set (Date) then Date = Year; -- promote Year to Date Year = nil; -- make nil so Year as empty string isn't used for CITEREF if not utilities.is_set (Date) and utilities.is_set (PublicationDate) then -- use PublicationDate when |date= and |year= are not set Date = PublicationDate; -- promote PublicationDate to Date PublicationDate = ''; -- unset, no longer needed Date_origin = A:ORIGIN('PublicationDate'); -- save the name of the promoted parameter else Date_origin = A:ORIGIN('Year'); -- save the name of the promoted parameter end else Date_origin = A:ORIGIN('Date'); -- not a promotion; name required for error messaging end if PublicationDate == Date then PublicationDate = ''; end -- if PublicationDate is same as Date, don't display in rendered citation --[[ Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates. This must be done before we do COinS because here is where we get the date used in the metadata. Date validation supporting code is in Module:Citation/CS1/Date_validation ]] local DF = is_valid_parameter_value (A['DF'], A:ORIGIN('DF'), cfg.keywords_lists['df'], ''); if not utilities.is_set (DF) then DF = cfg.global_df; -- local |df= if present overrides global df set by {{use xxx date}} template end local ArchiveURL; local ArchiveDate; local ArchiveFormat = A['ArchiveFormat']; local archive_url_timestamp; -- timestamp from wayback machine url ArchiveURL, ArchiveDate, archive_url_timestamp = archive_url_check (A['ArchiveURL'], A['ArchiveDate']) ArchiveFormat = style_format (ArchiveFormat, ArchiveURL, 'archive-format', 'archive-url'); ArchiveURL, ArchiveDate = is_unique_archive_url (ArchiveURL, URL, ChapterURL, A:ORIGIN('ArchiveURL'), ArchiveDate); -- add error message when URL or ChapterURL == ArchiveURL local AccessDate = A['AccessDate']; local COinS_date = {}; -- holds date info extracted from |date= for the COinS metadata by Module:Date verification local DoiBroken = A['DoiBroken']; local Embargo = A['Embargo']; local anchor_year; -- used in the CITEREF identifier do -- create defined block to contain local variables error_message, date_parameters_list, mismatch local error_message = ''; -- AirDate has been promoted to Date so not necessary to check it local date_parameters_list = { ['access-date'] = {val = AccessDate, name = A:ORIGIN ('AccessDate')}, ['archive-date'] = {val = ArchiveDate, name = A:ORIGIN ('ArchiveDate')}, ['date'] = {val = Date, name = Date_origin}, ['doi-broken-date'] = {val = DoiBroken, name = A:ORIGIN ('DoiBroken')}, ['pmc-embargo-date'] = {val = Embargo, name = A:ORIGIN ('Embargo')}, ['publication-date'] = {val = PublicationDate, name = A:ORIGIN ('PublicationDate')}, ['year'] = {val = Year, name = A:ORIGIN ('Year')}, }; local error_list = {}; anchor_year, Embargo = validation.dates(date_parameters_list, COinS_date, error_list); if utilities.is_set (Year) and utilities.is_set (Date) then -- both |date= and |year= not normally needed; validation.year_date_check (Year, A:ORIGIN ('Year'), Date, A:ORIGIN ('Date'), error_list); end if 0 == #error_list then -- error free dates only; 0 when error_list is empty local modified = false; -- flag if utilities.is_set (DF) then -- if we need to reformat dates modified = validation.reformat_dates (date_parameters_list, DF); -- reformat to DF format, use long month names if appropriate end if true == validation.date_hyphen_to_dash (date_parameters_list) then -- convert hyphens to dashes where appropriate modified = true; utilities.set_message ('maint_date_format'); -- hyphens were converted so add maint category end -- for those wikis that can and want to have English date names translated to the local language; not supported at en.wiki if cfg.date_name_auto_xlate_enable and validation.date_name_xlate (date_parameters_list, cfg.date_digit_auto_xlate_enable ) then utilities.set_message ('maint_date_auto_xlated'); -- add maint cat modified = true; end if modified then -- if the date_parameters_list values were modified AccessDate = date_parameters_list['access-date'].val; -- overwrite date holding parameters with modified values ArchiveDate = date_parameters_list['archive-date'].val; Date = date_parameters_list['date'].val; DoiBroken = date_parameters_list['doi-broken-date'].val; PublicationDate = date_parameters_list['publication-date'].val; end if archive_url_timestamp and utilities.is_set (ArchiveDate) then validation.archive_date_check (ArchiveDate, archive_url_timestamp, DF); -- does YYYYMMDD in archive_url_timestamp match date in ArchiveDate end else utilities.set_message ('err_bad_date', {utilities.make_sep_list (#error_list, error_list)}); -- add this error message end end -- end of do if utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) or -- {{cite book}}, {{cite encyclopedia}}; TODO: {{cite conference}} and others? ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) or -- {{citation}} as an encylopedia citation ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then -- {{citation}} as a book citation if utilities.is_set (PublicationPlace) then if not utilities.is_set (PublisherName) then local date = COinS_date.rftdate and tonumber (COinS_date.rftdate:match ('%d%d%d%d')); -- get year portion of COinS date (because in Arabic numerals); convert string to number if date and (1850 <= date) then -- location has no publisher; if date is 1850 or later utilities.set_message ('maint_location_no_publisher'); -- add maint cat end else -- PublisherName has a value if cfg.keywords_xlate['none'] == PublisherName then -- if that value is 'none' (only for book and encyclopedia citations) PublisherName = ''; -- unset end end end end local ID_list = {}; -- sequence table of rendered identifiers local ID_list_coins = {}; -- table of identifiers and their values from args; key is same as cfg.id_handlers's key local Class = A['Class']; -- arxiv class identifier local ID_support = { {A['ASINTLD'], 'ASIN', 'err_asintld_missing_asin', A:ORIGIN ('ASINTLD')}, {DoiBroken, 'DOI', 'err_doibroken_missing_doi', A:ORIGIN ('DoiBroken')}, {Embargo, 'PMC', 'err_embargo_missing_pmc', A:ORIGIN ('Embargo')}, } ID_list, ID_list_coins = identifiers.identifier_lists_get (args, { DoiBroken = DoiBroken, -- for |doi= ASINTLD = A['ASINTLD'], -- for |asin= Embargo = Embargo, -- for |pmc= Class = Class, -- for |arxiv= CitationClass = config.CitationClass, -- for |arxiv= Year=anchor_year, -- for |isbn= }, ID_support); if 'citation' == config.CitationClass then -- catch ve/citoid malformed book cites in {{citation}} templates for _, id in ipairs (ID_list) do -- search through the ID_list sequence looking for an ISBN identifier string if id:find ('ISBN', 3, true) then -- plain find, start at index 3 ([[ISBN) if utilities.is_set (Periodical) then -- when a |work= alias is set utilities.set_message ('maint_work_isbn'); -- add maint cat end end end end -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, {{cite ssrn}}, before generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv=, |citeseerx=, |medrxiv=, |ssrn= required for their templates if not (args[cfg.id_handlers[config.CitationClass:upper()].parameters[1]] or -- can't use ID_list_coins k/v table here because invalid parameters omitted args[cfg.id_handlers[config.CitationClass:upper()].parameters[2]]) then -- which causes unexpected parameter missing error message utilities.set_message ('err_' .. config.CitationClass .. '_missing'); -- add error message end Periodical = ({['arxiv'] = 'arXiv', ['biorxiv'] = 'bioRxiv', ['citeseerx'] = 'CiteSeerX', ['medrxiv'] = 'medRxiv', ['ssrn'] = 'Social Science Research Network'})[config.CitationClass]; end -- Link the title of the work if no |url= was provided, but we have a |pmc= or a |doi= with |doi-access=free if config.CitationClass == "journal" and not utilities.is_set (URL) and not utilities.is_set (TitleLink) and not utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) then -- TODO: remove 'none' once existing citations have been switched to 'off', so 'none' can be used as token for "no title" instead if 'none' ~= cfg.keywords_xlate[auto_select] then -- if auto-linking not disabled if identifiers.auto_link_urls[auto_select] then -- manual selection URL = identifiers.auto_link_urls[auto_select]; -- set URL to be the same as identifier's external link URL_origin = cfg.id_handlers[auto_select:upper()].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['pmc'] then -- auto-select PMC URL = identifiers.auto_link_urls['pmc']; -- set URL to be the same as the PMC external link if not embargoed URL_origin = cfg.id_handlers['PMC'].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['doi'] then -- auto-select DOI URL = identifiers.auto_link_urls['doi']; URL_origin = cfg.id_handlers['DOI'].parameters[1]; end end if utilities.is_set (URL) then -- set when using an identifier-created URL if utilities.is_set (AccessDate) then -- |access-date= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_accessdate_missing_url'); -- add an error message AccessDate = ''; -- unset end if utilities.is_set (ArchiveURL) then -- |archive-url= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_archive_missing_url'); -- add an error message ArchiveURL = ''; -- unset end end end -- At this point fields may be nil if they weren't specified in the template use. We can use that fact. -- Test if citation has no title if not utilities.is_set (Title) and not utilities.is_set (TransTitle) and not utilities.is_set (ScriptTitle) then -- has special case for cite episode utilities.set_message ('err_citation_missing_title', {'episode' == config.CitationClass and 'series' or 'title'}); end if utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) and utilities.in_array (config.CitationClass, {'journal', 'citation'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and ('journal' == Periodical_origin or 'script-journal' == ScriptPeriodical_origin) then -- special case for journal cites Title = ''; -- set title to empty string utilities.set_message ('maint_untitled'); -- add maint cat end if 'journal' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then if is_page_art_num (((utilities.is_set (Page) and Page) or (utilities.is_set (Pages) and Pages)) or nil, ID_list_coins['DOI']) then -- does |page(s)= look like it holds an article number utilities.set_message ('maint_page_art_num'); -- add maint cat end end -- COinS metadata (see <http://ocoins.info/>) for automated parsing of citation information. -- handle the oddity that is cite encyclopedia and {{citation |encyclopedia=something}}. Here we presume that -- when Periodical, Title, and Chapter are all set, then Periodical is the book (encyclopedia) title, Title -- is the article title, and Chapter is a section within the article. So, we remap local coins_chapter = Chapter; -- default assuming that remapping not required local coins_title = Title; -- et tu if 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Chapter) and utilities.is_set (Title) and utilities.is_set (Periodical) then -- if all are used then coins_chapter = Title; -- remap coins_title = Periodical; end end local coins_author = a; -- default for coins rft.au if 0 < #c then -- but if contributor list coins_author = c; -- use that instead end -- this is the function call to COinS() local OCinSoutput = metadata.COinS({ ['Periodical'] = utilities.strip_apostrophe_markup (Periodical), -- no markup in the metadata ['Encyclopedia'] = Encyclopedia, -- just a flag; content ignored by ~/COinS ['Chapter'] = metadata.make_coins_title (coins_chapter, ScriptChapter), -- Chapter and ScriptChapter stripped of bold / italic / accept-as-written markup ['Degree'] = Degree; -- cite thesis only ['Title'] = metadata.make_coins_title (coins_title, ScriptTitle), -- Title and ScriptTitle stripped of bold / italic / accept-as-written markup ['PublicationPlace'] = PublicationPlace, ['Date'] = COinS_date.rftdate, -- COinS_date.* has correctly formatted date values if Date is valid; ['Season'] = COinS_date.rftssn, ['Quarter'] = COinS_date.rftquarter, ['Chron'] = COinS_date.rftchron, ['Series'] = Series, ['Volume'] = Volume, ['Issue'] = Issue, ['ArticleNumber'] = ArticleNumber, ['Pages'] = coins_pages or metadata.get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At, QuotePage, QuotePages}, 7)), -- pages stripped of external links ['Edition'] = Edition, ['PublisherName'] = PublisherName or Newsgroup, -- any apostrophe markup already removed from PublisherName ['URL'] = first_set ({ChapterURL, URL}, 2), ['Authors'] = coins_author, ['ID_list'] = ID_list_coins, ['RawPage'] = this_page.prefixedText, }, config.CitationClass); -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, and {{cite ssrn}} AFTER generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- we have set rft.jtitle in COinS to arXiv, bioRxiv, CiteSeerX, medRxiv, or ssrn now unset so it isn't displayed Periodical = ''; -- periodical not allowed in these templates; if article has been published, use cite journal end -- special case for cite newsgroup. Do this after COinS because we are modifying Publishername to include some static text if 'newsgroup' == config.CitationClass and utilities.is_set (Newsgroup) then PublisherName = utilities.substitute (cfg.messages['newsgroup'], external_link( 'news:' .. Newsgroup, Newsgroup, Newsgroup_origin, nil )); end local Editors; local EditorCount; -- used only for choosing {ed.) or (eds.) annotation at end of editor name-list local Contributors; -- assembled contributors name list local contributor_etal; local Translators; -- assembled translators name list local translator_etal; local t = {}; -- translators list from |translator-lastn= / translator-firstn= pairs t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= local Interviewers; local interviewers_list = {}; interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters local interviewer_etal; -- Now perform various field substitutions. -- We also add leading spaces and surrounding markup and punctuation to the -- various parts of the citation, but only when they are non-nil. do local last_first_list; local control = { format = NameListStyle, -- empty string, '&', 'amp', 'and', or 'vanc' maximum = nil, -- as if display-authors or display-editors not set mode = Mode }; do -- do editor name list first because the now unsupported coauthors used to modify control table local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayEditors'], A['DisplayEditors'], A:ORIGIN ('DisplayEditors'), #e); control.maximum, editor_etal = get_display_names (display_names, #e, 'editors', editor_etal, param); Editors, EditorCount = list_people (control, e, editor_etal); if 1 == EditorCount and (true == editor_etal or 1 < #e) then -- only one editor displayed but includes etal then EditorCount = 2; -- spoof to display (eds.) annotation end end do -- now do interviewers local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayInterviewers'], A['DisplayInterviewers'], A:ORIGIN ('DisplayInterviewers'), #interviewers_list); control.maximum, interviewer_etal = get_display_names (display_names, #interviewers_list, 'interviewers', interviewer_etal, param); Interviewers = list_people (control, interviewers_list, interviewer_etal); end do -- now do translators local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayTranslators'], A['DisplayTranslators'], A:ORIGIN ('DisplayTranslators'), #t); control.maximum, translator_etal = get_display_names (display_names, #t, 'translators', translator_etal, param); Translators = list_people (control, t, translator_etal); end do -- now do contributors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayContributors'], A['DisplayContributors'], A:ORIGIN ('DisplayContributors'), #c); control.maximum, contributor_etal = get_display_names (display_names, #c, 'contributors', contributor_etal, param); Contributors = list_people (control, c, contributor_etal); end do -- now do authors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayAuthors'], A['DisplayAuthors'], A:ORIGIN ('DisplayAuthors'), #a, author_etal); control.maximum, author_etal = get_display_names (display_names, #a, 'authors', author_etal, param); last_first_list = list_people (control, a, author_etal); if utilities.is_set (Authors) then Authors, author_etal = name_has_etal (Authors, author_etal, false, 'authors'); -- find and remove variations on et al. if author_etal then Authors = Authors .. ' ' .. cfg.messages['et al']; -- add et al. to authors parameter end else Authors = last_first_list; -- either an author name list or an empty string end end -- end of do if utilities.is_set (Authors) and utilities.is_set (Collaboration) then Authors = Authors .. ' (' .. Collaboration .. ')'; -- add collaboration after et al. end end local ConferenceFormat = A['ConferenceFormat']; local ConferenceURL = A['ConferenceURL']; ConferenceFormat = style_format (ConferenceFormat, ConferenceURL, 'conference-format', 'conference-url'); Format = style_format (Format, URL, 'format', 'url'); -- special case for chapter format so no error message or cat when chapter not supported if not (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia))) then ChapterFormat = style_format (ChapterFormat, ChapterURL, 'chapter-format', 'chapter-url'); end if not utilities.is_set (URL) then if utilities.in_array (config.CitationClass, {"web", "podcast", "mailinglist"}) or -- |url= required for cite web, cite podcast, and cite mailinglist ('citation' == config.CitationClass and ('website' == Periodical_origin or 'script-website' == ScriptPeriodical_origin)) then -- and required for {{citation}} with |website= or |script-website= utilities.set_message ('err_cite_web_url'); end -- do we have |accessdate= without either |url= or |chapter-url=? if utilities.is_set (AccessDate) and not utilities.is_set (ChapterURL) then -- ChapterURL may be set when URL is not set; utilities.set_message ('err_accessdate_missing_url'); AccessDate = ''; end end local UrlStatus = is_valid_parameter_value (A['UrlStatus'], A:ORIGIN('UrlStatus'), cfg.keywords_lists['url-status'], ''); local OriginalURL local OriginalURL_origin local OriginalFormat local OriginalAccess; UrlStatus = UrlStatus:lower(); -- used later when assembling archived text if utilities.is_set ( ArchiveURL ) then if utilities.is_set (ChapterURL) then -- if chapter-url= is set apply archive url to it OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text OriginalURL_origin = ChapterURL_origin; -- name of |chapter-url= parameter for error messages OriginalFormat = ChapterFormat; -- and original |chapter-format= if 'live' ~= UrlStatus then ChapterURL = ArchiveURL -- swap-in the archive's URL ChapterURL_origin = A:ORIGIN('ArchiveURL') -- name of |archive-url= parameter for error messages ChapterFormat = ArchiveFormat or ''; -- swap in archive's format ChapterUrlAccess = nil; -- restricted access levels do not make sense for archived URLs end elseif utilities.is_set (URL) then OriginalURL = URL; -- save copy of original source URL OriginalURL_origin = URL_origin; -- name of URL parameter for error messages OriginalFormat = Format; -- and original |format= OriginalAccess = UrlAccess; if 'live' ~= UrlStatus then -- if URL set then |archive-url= applies to it URL = ArchiveURL -- swap-in the archive's URL URL_origin = A:ORIGIN('ArchiveURL') -- name of archive URL parameter for error messages Format = ArchiveFormat or ''; -- swap in archive's format UrlAccess = nil; -- restricted access levels do not make sense for archived URLs end end elseif utilities.is_set (UrlStatus) then -- if |url-status= is set when |archive-url= is not set utilities.set_message ('maint_url_status'); -- add maint cat end if utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or -- if any of the 'periodical' cites except encyclopedia ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) then local chap_param; if utilities.is_set (Chapter) then -- get a parameter name from one of these chapter related meta-parameters chap_param = A:ORIGIN ('Chapter') elseif utilities.is_set (TransChapter) then chap_param = A:ORIGIN ('TransChapter') elseif utilities.is_set (ChapterURL) then chap_param = A:ORIGIN ('ChapterURL') elseif utilities.is_set (ScriptChapter) then chap_param = ScriptChapter_origin; else utilities.is_set (ChapterFormat) chap_param = A:ORIGIN ('ChapterFormat') end if utilities.is_set (chap_param) then -- if we found one utilities.set_message ('err_chapter_ignored', {chap_param}); -- add error message Chapter = ''; -- and set them to empty string to be safe with concatenation TransChapter = ''; ChapterURL = ''; ScriptChapter = ''; ChapterFormat = ''; end else -- otherwise, format chapter / article title local no_quotes = false; -- default assume that we will be quoting the chapter parameter value if utilities.is_set (Contribution) and 0 < #c then -- if this is a contribution with contributor(s) if utilities.in_array (Contribution:lower(), cfg.keywords_lists.contribution) then -- and a generic contribution title no_quotes = true; -- then render it unquoted end end Chapter = format_chapter_title (ScriptChapter, ScriptChapter_origin, Chapter, Chapter_origin, TransChapter, TransChapter_origin, ChapterURL, ChapterURL_origin, no_quotes, ChapterUrlAccess); -- Contribution is also in Chapter if utilities.is_set (Chapter) then Chapter = Chapter .. ChapterFormat ; if 'map' == config.CitationClass and utilities.is_set (TitleType) then Chapter = Chapter .. ' ' .. TitleType; -- map annotation here; not after title end Chapter = Chapter .. sepc .. ' '; elseif utilities.is_set (ChapterFormat) then -- |chapter= not set but |chapter-format= is so ... Chapter = ChapterFormat .. sepc .. ' '; -- ... ChapterFormat has error message, we want to see it end end -- Format main title local plain_title = false; local accept_title; Title, accept_title = utilities.has_accept_as_written (Title, true); -- remove accept-this-as-written markup when it wraps all of <Title> if accept_title and ('' == Title) then -- only support forced empty for now "(())" Title = cfg.messages['notitle']; -- replace by predefined "No title" message -- TODO: utilities.set_message ( 'err_redundant_parameters', ...); -- issue proper error message instead of muting ScriptTitle = ''; -- just mute for now TransTitle = ''; -- just mute for now plain_title = true; -- suppress text decoration for descriptive title utilities.set_message ('maint_untitled'); -- add maint cat end if not accept_title then -- <Title> not wrapped in accept-as-written markup if '...' == Title:sub (-3) then -- if ellipsis is the last three characters of |title= Title = Title:gsub ('(%.%.%.)%.+$', '%1'); -- limit the number of dots to three elseif not mw.ustring.find (Title, '%.%s*%a%.$') and -- end of title is not a 'dot-(optional space-)letter-dot' initialism ... not mw.ustring.find (Title, '%s+%a%.$') then -- ...and not a 'space-letter-dot' initial (''Allium canadense'' L.) Title = mw.ustring.gsub(Title, '%' .. sepc .. '$', ''); -- remove any trailing separator character; sepc and ms.ustring() here for languages that use multibyte separator characters end if utilities.is_set (ArchiveURL) and is_archived_copy (Title) then utilities.set_message ('maint_archived_copy'); -- add maintenance category before we modify the content of Title end if is_generic ('generic_titles', Title) then utilities.set_message ('err_generic_title'); -- set an error message end end if (not plain_title) and (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'document', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) or ('map' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)))) then -- special case for cite map when the map is in a periodical treat as an article Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from module provided quote marks Title = utilities.wrap_style ('quoted-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); elseif plain_title or ('report' == config.CitationClass) then -- no styling for cite report and descriptive titles (otherwise same as above) Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); -- for cite report, use this form for trans-title else Title = utilities.wrap_style ('italic-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-italic-title', TransTitle); end if utilities.is_set (TransTitle) then if utilities.is_set (Title) then TransTitle = " " .. TransTitle; else utilities.set_message ('err_trans_missing_title', {'title'}); end end if utilities.is_set (Title) then -- TODO: is this the right place to be making Wikisource URLs? if utilities.is_set (TitleLink) and utilities.is_set (URL) then utilities.set_message ('err_wikilink_in_url'); -- set an error message because we can't have both TitleLink = ''; -- unset end if not utilities.is_set (TitleLink) and utilities.is_set (URL) then Title = external_link (URL, Title, URL_origin, UrlAccess) .. TransTitle .. Format; URL = ''; -- unset these because no longer needed Format = ""; elseif utilities.is_set (TitleLink) and not utilities.is_set (URL) then local ws_url; ws_url = wikisource_url_make (TitleLink); -- ignore ws_label return; not used here if ws_url then Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title-link'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], TitleLink, Title}); Title = Title .. TransTitle; else Title = utilities.make_wikilink (TitleLink, Title) .. TransTitle; end else local ws_url, ws_label, L; -- Title has italic or quote markup by the time we get here which causes is_wikilink() to return 0 (not a wikilink) ws_url, ws_label, L = wikisource_url_make (Title:gsub('^[\'"]*(.-)[\'"]*$', '%1')); -- make ws URL from |title= interwiki link (strip italic or quote markup); link portion L becomes tooltip label if ws_url then Title = Title:gsub ('%b[]', ws_label); -- replace interwiki link with ws_label to retain markup Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, Title}); Title = Title .. TransTitle; else Title = Title .. TransTitle; end end else Title = TransTitle; end if utilities.is_set (Place) then Place = " " .. wrap_msg ('written', Place, use_lowercase) .. sepc .. " "; end local ConferenceURL_origin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL if utilities.is_set (Conference) then if utilities.is_set (ConferenceURL) then Conference = external_link( ConferenceURL, Conference, ConferenceURL_origin, nil ); end Conference = sepc .. " " .. Conference .. ConferenceFormat; elseif utilities.is_set (ConferenceURL) then Conference = sepc .. " " .. external_link( ConferenceURL, nil, ConferenceURL_origin, nil ); end local Position = ''; if not utilities.is_set (Position) then local Minutes = A['Minutes']; local Time = A['Time']; if utilities.is_set (Minutes) then if utilities.is_set (Time) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'minutes') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'time')}); end Position = utilities.substitute (cfg.messages.minutes, Minutes); else if utilities.is_set (Time) then local TimeCaption = A['TimeCaption'] if not utilities.is_set (TimeCaption) then TimeCaption = cs2_lower(cfg.messages['event']); end Position = " " .. TimeCaption .. " " .. Time; end end else Position = " " .. Position; At = ''; end Page, Pages, Sheet, Sheets = format_pages_sheets (Page, Pages, Sheet, Sheets, config.CitationClass, Periodical_origin, sepc, NoPP, use_lowercase); At = utilities.is_set (At) and (sepc .. " " .. At) or ""; Position = utilities.is_set (Position) and (sepc .. " " .. Position) or ""; if config.CitationClass == 'map' then local Sections = A['Sections']; -- Section (singular) is an alias of Chapter so set earlier local Inset = A['Inset']; if utilities.is_set ( Inset ) then Inset = sepc .. " " .. wrap_msg ('inset', Inset, use_lowercase); end if utilities.is_set ( Sections ) then Section = sepc .. " " .. wrap_msg ('sections', Sections, use_lowercase); elseif utilities.is_set ( Section ) then Section = sepc .. " " .. wrap_msg ('section', Section, use_lowercase); end At = At .. Inset .. Section; end local Others = A['Others']; if utilities.is_set (Others) and 0 == #a and 0 == #e then -- add maint cat when |others= has value and used without |author=, |editor= if config.CitationClass == "AV-media-notes" or config.CitationClass == "audio-visual" then -- special maint for AV/M which has a lot of 'false' positives right now utilities.set_message ('maint_others_avm') else utilities.set_message ('maint_others'); end end Others = utilities.is_set (Others) and (sepc .. " " .. Others) or ""; if utilities.is_set (Translators) then Others = safe_join ({sepc .. ' ', wrap_msg ('translated', Translators, use_lowercase), Others}, sepc); end if utilities.is_set (Interviewers) then Others = safe_join ({sepc .. ' ', wrap_msg ('interview', Interviewers, use_lowercase), Others}, sepc); end local TitleNote = A['TitleNote']; TitleNote = utilities.is_set (TitleNote) and (sepc .. " " .. TitleNote) or ""; if utilities.is_set (Edition) then if Edition:match ('%f[%a][Ee]d%n?%.?$') or Edition:match ('%f[%a][Ee]dition$') then -- Ed, ed, Ed., ed., Edn, edn, Edn., edn. utilities.set_message ('err_extra_text_edition'); -- add error message end Edition = " " .. wrap_msg ('edition', Edition); else Edition = ''; end Series = utilities.is_set (Series) and wrap_msg ('series', {sepc, Series}) or ""; -- not the same as SeriesNum local Agency = A['Agency'] or ''; -- |agency= is supported by {{cite magazine}}, {{cite news}}, {{cite press release}}, {{cite web}}, and certain {{citation}} templates if utilities.is_set (Agency) then -- this testing done here because {{citation}} supports 'news' citations if utilities.in_array (config.CitationClass, {'magazine', 'news', 'pressrelease', 'web'}) or ('citation' == config.CitationClass and utilities.in_array (Periodical_origin, {"magazine", "newspaper", "work"})) then Agency = wrap_msg ('agency', {sepc, Agency}); -- format for rendering else Agency = ''; -- unset; not supported utilities.set_message ('err_parameter_ignored', {'agency'}); -- add error message end end Volume = format_volume_issue (Volume, Issue, ArticleNumber, config.CitationClass, Periodical_origin, sepc, use_lowercase); if utilities.is_set (AccessDate) then local retrv_text = " " .. cfg.messages['retrieved']; AccessDate = nowrap_date (AccessDate); -- wrap in nowrap span if date in appropriate format retrv_text = cs2_lower(retrv_text); -- if mode is cs2, lower case AccessDate = utilities.substitute (retrv_text, AccessDate); -- add retrieved text AccessDate = utilities.substitute (cfg.presentation['accessdate'], {sepc, AccessDate}); -- allow editors to hide accessdates end if utilities.is_set (ID) then ID = sepc .. " " .. ID; end local Docket = A['Docket']; if "thesis" == config.CitationClass and utilities.is_set (Docket) then ID = sepc .. " Docket " .. Docket .. ID; end if "report" == config.CitationClass and utilities.is_set (Docket) then -- for cite report when |docket= is set ID = sepc .. ' ' .. Docket; -- overwrite ID even if |id= is set end if utilities.is_set (URL) then URL = " " .. external_link( URL, nil, URL_origin, UrlAccess ); end -- We check length of PostScript here because it will have been nuked by -- the quote parameters. We'd otherwise emit a message even if there wasn't -- a displayed postscript. -- TODO: Should the max size (1) be configurable? -- TODO: Should we check a specific pattern? if utilities.is_set(PostScript) and mw.ustring.len(PostScript) > 1 then utilities.set_message ('maint_postscript') end local Archived; if utilities.is_set (ArchiveURL) then if not utilities.is_set (ArchiveDate) then -- ArchiveURL set but ArchiveDate not set utilities.set_message ('err_archive_missing_date'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end else if utilities.is_set (ArchiveDate) then -- ArchiveURL not set but ArchiveDate is set utilities.set_message ('err_archive_date_missing_url'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end end if utilities.is_set (ArchiveURL) then local arch_text; if "live" == UrlStatus then if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cfg.messages['archived-live'], { external_link( ArchiveURL, cs2_lower(cfg.messages['archived']), A:ORIGIN('ArchiveURL'), nil) .. ArchiveFormat, ArchiveDate } ); else Archived = ''; end if not utilities.is_set (OriginalURL) then utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (OriginalURL) then -- UrlStatus is empty, 'dead', 'unfit', 'usurped', 'bot: unknown' if utilities.in_array (UrlStatus, {'unfit', 'usurped', 'bot: unknown'}) then Archived = sepc .. ' ' .. utilities.substitute ( cs2_lower(cfg.messages['archived-unfit']), ArchiveDate); if 'bot: unknown' == UrlStatus then utilities.set_message ('maint_bot_unknown'); -- and add a category if not already added else utilities.add_prop_cat ('unfit'); -- and add a category if not already added end else -- UrlStatus is empty, 'dead' if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cs2_lower(cfg.messages['archived-dead']), { external_link( OriginalURL, cfg.messages['original'], OriginalURL_origin, OriginalAccess ) .. OriginalFormat, ArchiveDate } ); else Archived = ''; -- unset for concatenation end end else -- OriginalUrl not set utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (ArchiveFormat) then Archived = ArchiveFormat; -- if set and ArchiveURL not set ArchiveFormat has error message else Archived = ''; end local TranscriptURL = A['TranscriptURL'] local TranscriptFormat = A['TranscriptFormat']; TranscriptFormat = style_format (TranscriptFormat, TranscriptURL, 'transcript-format', 'transcripturl'); local Transcript = A['Transcript']; local TranscriptURL_origin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL if utilities.is_set (Transcript) then if utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, Transcript, TranscriptURL_origin, nil ); end Transcript = sepc .. ' ' .. Transcript .. TranscriptFormat; elseif utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, nil, TranscriptURL_origin, nil ); end local Publisher; if utilities.is_set (PublicationDate) then PublicationDate = wrap_msg ('published', PublicationDate); end if utilities.is_set (PublisherName) then if utilities.is_set (PublicationPlace) then Publisher = sepc .. " " .. PublicationPlace .. ": " .. PublisherName .. PublicationDate; else Publisher = sepc .. " " .. PublisherName .. PublicationDate; end elseif utilities.is_set (PublicationPlace) then Publisher= sepc .. " " .. PublicationPlace .. PublicationDate; else Publisher = PublicationDate; end -- Several of the above rely upon detecting this as nil, so do it last. if (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical)) then if utilities.is_set (Title) or utilities.is_set (TitleNote) then Periodical = sepc .. " " .. format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); else Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); end end local Language = A['Language']; if utilities.is_set (Language) then Language = language_parameter (Language); -- format, categories, name from ISO639-1, etc. else Language=''; -- language not specified so make sure this is an empty string; --[[ TODO: need to extract the wrap_msg from language_parameter so that we can solve parentheses bunching problem with Format/Language/TitleType ]] end --[[ Handle the oddity that is cite speech. This code overrides whatever may be the value assigned to TitleNote (through |department=) and forces it to be " (Speech)" so that the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided). ]] if "speech" == config.CitationClass then -- cite speech only TitleNote = TitleType; -- move TitleType to TitleNote so that it renders ahead of |event= TitleType = ''; -- and unset if utilities.is_set (Periodical) then -- if Periodical, perhaps because of an included |website= or |journal= parameter if utilities.is_set (Conference) then -- and if |event= is set Conference = Conference .. sepc .. " "; -- then add appropriate punctuation to the end of the Conference variable before rendering end end end -- Piece all bits together at last. Here, all should be non-nil. -- We build things this way because it is more efficient in LUA -- not to keep reassigning to the same string variable over and over. local tcommon; local tcommon2; -- used for book cite when |contributor= is set if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (Periodical) then -- special cases for book cites if utilities.is_set (Contributors) then -- when we are citing foreword, preface, introduction, etc. tcommon = safe_join ({Title, TitleNote}, sepc); -- author and other stuff will come after this and before tcommon2 tcommon2 = safe_join ({TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); else tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); end elseif 'map' == config.CitationClass then -- special cases for cite map if utilities.is_set (Chapter) then -- map in a book; TitleType is part of Chapter tcommon = safe_join ({Title, Edition, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); elseif utilities.is_set (Periodical) then -- map in a periodical tcommon = safe_join ({Title, TitleType, Periodical, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); else -- a sheet or stand-alone map tcommon = safe_join ({Title, TitleType, Edition, Scale, Series, Language, Cartography, Others, Publisher}, sepc); end elseif 'episode' == config.CitationClass then -- special case for cite episode tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Edition, Publisher}, sepc); else -- all other CS1 templates tcommon = safe_join ({Title, TitleNote, Conference, Periodical, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc); end if #ID_list > 0 then ID_list = safe_join( { sepc .. " ", table.concat( ID_list, sepc .. " " ), ID }, sepc ); else ID_list = ID; end local Via = A['Via']; Via = utilities.is_set (Via) and wrap_msg ('via', Via) or ''; local idcommon; if 'audio-visual' == config.CitationClass or 'episode' == config.CitationClass then -- special case for cite AV media & cite episode position transcript idcommon = safe_join( { ID_list, URL, Archived, Transcript, AccessDate, Via, Quote }, sepc ); else idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, Quote }, sepc ); end local text; local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; local OrigDate = A['OrigDate']; OrigDate = utilities.is_set (OrigDate) and wrap_msg ('origdate', OrigDate) or ''; if utilities.is_set (Date) then if utilities.is_set (Authors) or utilities.is_set (Editors) then -- date follows authors or editors when authors not set Date = " (" .. Date .. ")" .. OrigDate .. sepc .. " "; -- in parentheses else -- neither of authors and editors set if (string.sub(tcommon, -1, -1) == sepc) then -- if the last character of tcommon is sepc Date = " " .. Date .. OrigDate; -- Date does not begin with sepc else Date = sepc .. " " .. Date .. OrigDate; -- Date begins with sepc end end end if utilities.is_set (Authors) then if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Authors termination Authors = terminate_name_list (Authors, sepc); -- when no date, terminate with 0 or 1 sepc and a space end if utilities.is_set (Editors) then local in_text = ''; local post_text = ''; if utilities.is_set (Chapter) and 0 == #c then in_text = cfg.messages['in'] .. ' '; in_text = cs2_lower(in_text); -- lowercase for cs2 end if EditorCount <= 1 then post_text = ' (' .. cfg.messages['editor'] .. ')'; -- be consistent with no-author, no-date case else post_text = ' (' .. cfg.messages['editors'] .. ')'; end Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space end if utilities.is_set (Contributors) then -- book cite and we're citing the intro, preface, etc. local by_text = sepc .. ' ' .. cfg.messages['by'] .. ' '; by_text = cs2_lower(by_text); -- lowercase for cs2 Authors = by_text .. Authors; -- author follows title so tweak it here if utilities.is_set (Editors) and utilities.is_set (Date) then -- when Editors make sure that Authors gets terminated Authors = terminate_name_list (Authors, sepc); -- terminate with 0 or 1 sepc and a space end if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Contributors termination Contributors = terminate_name_list (Contributors, sepc); -- terminate with 0 or 1 sepc and a space end text = safe_join( {Contributors, Date, Chapter, tcommon, Authors, Place, Editors, tcommon2, pgtext, idcommon }, sepc ); else text = safe_join( {Authors, Date, Chapter, Place, Editors, tcommon, pgtext, idcommon }, sepc ); end elseif utilities.is_set (Editors) then if utilities.is_set (Date) then if EditorCount <= 1 then Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editor']; else Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editors']; end else if EditorCount <= 1 then Editors = Editors .. " (" .. cfg.messages['editor'] .. ")" .. sepc .. " " else Editors = Editors .. " (" .. cfg.messages['editors'] .. ")" .. sepc .. " " end end text = safe_join( {Editors, Date, Chapter, Place, tcommon, pgtext, idcommon}, sepc ); else if utilities.in_array (config.CitationClass, {"journal", "citation"}) and utilities.is_set (Periodical) then text = safe_join( {Chapter, Place, tcommon, pgtext, Date, idcommon}, sepc ); else text = safe_join( {Chapter, Place, tcommon, Date, pgtext, idcommon}, sepc ); end end if utilities.is_set (PostScript) and PostScript ~= sepc then text = safe_join( {text, sepc}, sepc ); -- Deals with italics, spaces, etc. if '.' == sepc then -- remove final seperator if present text = text:gsub ('%' .. sepc .. '$', ''); -- dot must be escaped here else text = mw.ustring.gsub (text, sepc .. '$', ''); -- using ustring for non-dot sepc (likely a non-Latin character) end end text = safe_join( {text, PostScript}, sepc ); -- Now enclose the whole thing in a <cite> element local options_t = {}; options_t.class = cite_class_attribute_make (config.CitationClass, Mode); local Ref = is_valid_parameter_value (A['Ref'], A:ORIGIN('Ref'), cfg.keywords_lists['ref'], nil, true); -- nil when |ref=harv; A['Ref'] else if 'none' ~= cfg.keywords_xlate[(Ref and Ref:lower()) or ''] then local namelist_t = {}; -- holds selected contributor, author, editor name list local year = first_set ({Year, anchor_year}, 2); -- Year first for legacy citations and for YMD dates that require disambiguation if #c > 0 then -- if there is a contributor list namelist_t = c; -- select it elseif #a > 0 then -- or an author list namelist_t = a; elseif #e > 0 then -- or an editor list namelist_t = e; end local citeref_id; if #namelist_t > 0 then -- if there are names in namelist_t citeref_id = make_citeref_id (namelist_t, year); -- go make the CITEREF anchor if mw.uri.anchorEncode (citeref_id) == ((Ref and mw.uri.anchorEncode (Ref)) or '') then -- Ref may already be encoded (by {{sfnref}}) so citeref_id must be encoded before comparison utilities.set_message ('maint_ref_duplicates_default'); end else citeref_id = ''; -- unset end options_t.id = Ref or citeref_id; end if string.len (text:gsub('%b<>', '')) <= 2 then -- remove html and html-like tags; then get length of what remains; z.error_cats_t = {}; -- blank the categories list z.error_msgs_t = {}; -- blank the error messages list OCinSoutput = nil; -- blank the metadata string text = ''; -- blank the the citation utilities.set_message ('err_empty_citation'); -- set empty citation message and category end local render_t = {}; -- here we collect the final bits for concatenation into the rendered citation if is_preview_mode then -- when in preview mode if not utilities.is_set (options_t.id) then -- and when this template has not created an anchor ID math.randomseed (tonumber (mw.getLanguage ('en'):formatDate ('U')) * 10000 + os.clock() * 10000); options_t.id = 'CITEREF_temp_preview_id_' .. math.random (100000, 999999); -- create temporary anchor ID for preview mode end end if utilities.is_set (options_t.id) then -- here we wrap the rendered citation in <cite ...>...</cite> tags options_t.id = mw.uri.anchorEncode(options_t.id); -- do this here; also used when adding preview warning messages table.insert (render_t, utilities.substitute (cfg.presentation['cite-id'], {options_t.id, mw.text.nowiki(options_t.class), text})); -- when |ref= is set or when there is a namelist else table.insert (render_t, utilities.substitute (cfg.presentation['cite'], {mw.text.nowiki(options_t.class), text})); -- when |ref=none or when namelist_t empty and |ref= is missing or is empty end if OCinSoutput then -- blanked when citation is 'empty' so don't bother to add boilerplate metadata span table.insert (render_t, utilities.substitute (cfg.presentation['ocins'], OCinSoutput)); -- format and append metadata to the citation end local template_name = cfg.citation_class_map_t[config.CitationClass]; local template_link = '[[Template:' .. template_name .. '|' .. template_name .. ']]'; local msg_prefix = '<code class="cs1-code">{{' .. template_link .. '}}</code>: '; if 0 ~= #z.error_msgs_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_e, {template_link, options_t.id})); table.insert (render_t, ' '); -- insert a space between citation and its error messages table.sort (z.error_msgs_t); -- sort the error messages list; sorting includes wrapping <span> and <code> tags; hidden-error sorts ahead of visible-error local hidden = true; -- presume that the only error messages emited by this template are hidden for _, v in ipairs (z.error_msgs_t) do -- spin through the list of error messages if v:find ('cs1-visible-error', 1, true) then -- look for the visible error class name hidden = false; -- found one; so don't hide the error message prefix break; -- and done because no need to look further end end z.error_msgs_t[1] = table.concat ({utilities.error_comment (msg_prefix, hidden), z.error_msgs_t[1]}); -- add error message prefix to first error message to prevent extraneous punctuation table.insert (render_t, table.concat (z.error_msgs_t, '; ')); -- make a big string of error messages and add it to the rendering end if 0 ~= #z.maint_cats_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_m, {template_link, options_t.id})); table.sort (z.maint_cats_t); -- sort the maintenance messages list local maint_msgs_t = {}; -- here we collect all of the maint messages if 0 == #z.error_msgs_t then -- if no error messages table.insert (maint_msgs_t, msg_prefix); -- insert message prefix in maint message livery end for _, v in ipairs( z.maint_cats_t ) do -- append maintenance categories table.insert (maint_msgs_t, -- assemble new maint message and add it to the maint_msgs_t table table.concat ({v, ' (', utilities.substitute (cfg.messages[':cat wikilink'], v), ')'}) ); end table.insert (render_t, utilities.substitute (cfg.presentation['hidden-maint'], table.concat (maint_msgs_t, ' '))); -- wrap the group of maint messages with proper presentation and save end if not no_tracking_cats then local sort_key; local cat_wikilink = 'cat wikilink'; if cfg.enable_sort_keys then -- when namespace sort keys enabled local namespace_number = mw.title.getCurrentTitle().namespace; -- get namespace number for this wikitext sort_key = (0 ~= namespace_number and (cfg.name_space_sort_keys[namespace_number] or cfg.name_space_sort_keys.other)) or nil; -- get sort key character; nil for mainspace cat_wikilink = (not sort_key and 'cat wikilink') or 'cat wikilink sk'; -- make <cfg.messages> key end for _, v in ipairs (z.error_cats_t) do -- append error categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end if cfg.id_limits_data_load_fail then -- boolean true when load failed utilities.set_message ('maint_id_limit_load_fail'); -- done here because this maint cat emits no message end for _, v in ipairs (z.maint_cats_t) do -- append maintenance categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end for _, v in ipairs (z.prop_cats_t) do -- append properties categories table.insert (render_t, utilities.substitute (cfg.messages['cat wikilink'], v)); -- no sort keys end end return table.concat (render_t); -- make a big string and done end --[[--------------------------< V A L I D A T E >-------------------------------------------------------------- Looks for a parameter's name in one of several whitelists. Parameters in the whitelist can have three values: true - active, supported parameters false - deprecated, supported parameters nil - unsupported parameters ]] local function validate (name, cite_class, empty) local name = tostring (name); local enum_name; -- parameter name with enumerator (if any) replaced with '#' local state; local function state_test (state, name) -- local function to do testing of state values if true == state then return true; end -- valid actively supported parameter if false == state then if empty then return nil; end -- empty deprecated parameters are treated as unknowns deprecated_parameter (name); -- parameter is deprecated but still supported return true; end if 'tracked' == state then local base_name = name:gsub ('%d', ''); -- strip enumerators from parameter names that have them to get the base name utilities.add_prop_cat ('tracked-param', {base_name}, base_name); -- add a properties category; <base_name> modifies <key> return true; end return nil; end if name:find ('#') then -- # is a cs1|2 reserved character so parameters with # not permitted return nil; end -- replace enumerator digit(s) with # (|last25= becomes |last#=) (mw.ustring because non-Western 'local' digits) enum_name = mw.ustring.gsub (name, '%d+$', '#'); -- where enumerator is last charaters in parameter name (these to protect |s2cid=) enum_name = mw.ustring.gsub (enum_name, '%d+([%-l])', '#%1'); -- where enumerator is in the middle of the parameter name; |author#link= is the oddity if 'document' == cite_class then -- special case for {{cite document}} state = whitelist.document_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end return false; end if utilities.in_array (cite_class, whitelist.preprint_template_list_t) then -- limited parameter sets allowed for these templates state = whitelist.limited_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end state = whitelist.preprint_arguments_t[cite_class][name]; -- look in the parameter-list for the template identified by cite_class if true == state_test (state, name) then return true; end return false; -- not supported because not found or name is set to nil end -- end limited parameter-set templates if utilities.in_array (cite_class, whitelist.unique_param_template_list_t) then -- template-specific parameters for templates that accept parameters from the basic argument list state = whitelist.unique_arguments_t[cite_class][name]; -- look in the template-specific parameter-lists for the template identified by cite_class if true == state_test (state, name) then return true; end end -- if here, fall into general validation state = whitelist.common_parameters_t[enum_name]; -- all other templates; all normal parameters allowed; this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end return false; -- not supported because not found or name is set to nil end --[=[-------------------------< I N T E R _ W I K I _ C H E C K >---------------------------------------------- check <value> for inter-language interwiki-link markup. <prefix> must be a MediaWiki-recognized language code. when these values have the form (without leading colon): [[<prefix>:link|label]] return label as plain-text [[<prefix>:link]] return <prefix>:link as plain-text return value as is else ]=] local function inter_wiki_check (parameter, value) local prefix = value:match ('%[%[(%a+):'); -- get an interwiki prefix if one exists local _; if prefix and cfg.inter_wiki_map[prefix:lower()] then -- if prefix is in the map, needs preceding colon so utilities.set_message ('err_bad_paramlink', parameter); -- emit an error message _, value, _ = utilities.is_wikilink (value); -- extract label portion from wikilink end return value; end --[[--------------------------< M I S S I N G _ P I P E _ C H E C K >------------------------------------------ Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal sign, compare the alphanumeric string to the list of cs1|2 parameters. If found, then the string is possibly a parameter that is missing its pipe. There are two tests made: {{cite ... |title=Title access-date=2016-03-17}} -- the first parameter has a value and whitespace separates that value from the missing pipe parameter name {{cite ... |title=access-date=2016-03-17}} -- the first parameter has no value (whitespace after the first = is trimmed by MediaWiki) cs1|2 shares some parameter names with XML/HTML attributes: class=, title=, etc. To prevent false positives XML/HTML tags are removed before the search. If a missing pipe is detected, this function adds the missing pipe maintenance category. ]] local function missing_pipe_check (parameter, value) local capture; value = value:gsub ('%b<>', ''); -- remove XML/HTML tags because attributes: class=, title=, etc. capture = value:match ('%s+(%a[%w%-]+)%s*=') or value:match ('^(%a[%w%-]+)%s*='); -- find and categorize parameters with possible missing pipes if capture and validate (capture) then -- if the capture is a valid parameter name utilities.set_message ('err_missing_pipe', parameter); end end --[[--------------------------< H A S _ E X T R A N E O U S _ P U N C T >-------------------------------------- look for extraneous terminal punctuation in most parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_punc (param, value) if 'number' == type (param) then return; end param = param:gsub ('%d+', '#'); -- enumerated name-list mask params allow terminal punct; normalize if cfg.punct_skip[param] then return; -- parameter name found in the skip table so done end if value:match ('[,;:]$') then utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end if value:match ('^=') then -- sometimes an extraneous '=' character appears ... utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end end --[[--------------------------< H A S _ T W L _ U R L >-------------------------------------------------------- look for The Wikipedia Library urls in url-holding parameters. TWL urls are accessible only for readers who are active extended confirmed Wikipedia editors. This function sets an error message when such urls are discovered and when appropriate, sets the |<param>-url-access=subscription. returns nothing. looks for: '.wikipedialibrary.idm.oclc.org' ]] local function has_twl_url (url_params_t, cite_args_t) local url_error_t = {}; -- sequence of url-holding parameters that have a TWL url for param, value in pairs (url_params_t) do if value:find ('%.wikipedialibrary%.idm%.oclc%.org') then -- has the TWL base url? table.insert (url_error_t, param); -- add parameter name to the error list end end if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); -- sor for error messaging for i, param in ipairs (url_error_t) do if cfg.url_access_map_t[param] then -- if <param> has a matching -access parameter cite_args_t[cfg.url_access_map_t[param]] = cfg.keywords_xlate.subscription; -- set |<param>-url-access=subscription end url_error_t[i] = utilities.wrap_style ('parameter', param); -- make the parameter pretty for error message end utilities.set_message ('err_param_has_twl_url', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< H A S _ E X T R A N E O U S _ U R L >------------------------------------------ look for extraneous url parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_url (non_url_param_t) local url_error_t = {}; check_for_url (non_url_param_t, url_error_t); -- extraneous url check if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); utilities.set_message ('err_param_has_ext_link', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< _ C I T A T I O N >------------------------------------------------------------ Module entry point frame – from template call (citation()); may be nil when called from another module args_t – table of all cs1|2 parameters in the template (the parent frame) config_t – table of template-supplied parameter (the #invoke frame) ]] local function _citation (frame, args_t, config_t) -- save a copy in case we need to display an error message in preview mode if not frame then frame = mw.getCurrentFrame(); -- if called from another module, get a frame for frame-provided functions end -- i18n: set the name that your wiki uses to identify sandbox subpages from sandbox template invoke (or can be set here) local sandbox = ((config_t.SandboxPath and '' ~= config_t.SandboxPath) and config_t.SandboxPath) or '/sandbox'; -- sandbox path from {{#invoke:Citation/CS1/sandbox|citation|SandboxPath=/...}} is_sandbox = nil ~= string.find (frame:getTitle(), sandbox, 1, true); -- is this invoke the sandbox module? sandbox = is_sandbox and sandbox or ''; -- use i18n sandbox to load sandbox modules when this module is the sandox; live modules else cfg = mw.loadData ('Module:Citation/CS1/Configuration' .. sandbox); -- load sandbox versions of support modules when {{#invoke:Citation/CS1/sandbox|...}}; live modules else whitelist = mw.loadData ('Module:Citation/CS1/Whitelist' .. sandbox); utilities = require ('Module:Citation/CS1/Utilities' .. sandbox); validation = require ('Module:Citation/CS1/Date_validation' .. sandbox); identifiers = require ('Module:Citation/CS1/Identifiers' .. sandbox); metadata = require ('Module:Citation/CS1/COinS' .. sandbox); utilities.set_selected_modules (cfg); -- so that functions in Utilities can see the selected cfg tables identifiers.set_selected_modules (cfg, utilities); -- so that functions in Identifiers can see the selected cfg tables and selected Utilities module validation.set_selected_modules (cfg, utilities); -- so that functions in Date validataion can see selected cfg tables and the selected Utilities module metadata.set_selected_modules (cfg, utilities); -- so that functions in COinS can see the selected cfg tables and selected Utilities module z = utilities.z; -- table of error and category tables in Module:Citation/CS1/Utilities local cite_args_t = {}; -- because args_t is the parent (template) frame args (which cannot be modified); params and their values will be placed here is_preview_mode = not utilities.is_set (frame:preprocess ('{{REVISIONID}}')); local suggestions = {}; -- table where we store suggestions if we need to loadData them local error_text; -- used as a flag local capture; -- the single supported capture when matching unknown parameters using patterns local empty_unknowns = {}; -- sequence table to hold empty unknown params for error message listing for k, v in pairs (args_t) do -- get parameters from the parent (template) frame v = mw.ustring.gsub (v, '^%s*(.-)%s*$', '%1'); -- trim leading/trailing whitespace; when v is only whitespace, becomes empty string if v ~= '' then if ('string' == type (k)) then k = mw.ustring.gsub (k, '%d', cfg.date_names.local_digits); -- for enumerated parameters, translate 'local' digits to Western 0-9 end if not validate( k, config_t.CitationClass ) then if type (k) ~= 'string' then -- exclude empty numbered parameters if v:match("%S+") ~= nil then error_text = utilities.set_message ('err_text_ignored', {v}); end elseif validate (k:lower(), config_t.CitationClass) then error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, k:lower()}); -- suggest the lowercase version of the parameter else if nil == suggestions.suggestions then -- if this table is nil then we need to load it suggestions = mw.loadData ('Module:Citation/CS1/Suggestions' .. sandbox); --load sandbox version of suggestion module when {{#invoke:Citation/CS1/sandbox|...}}; live module else end for pattern, param in pairs (suggestions.patterns) do -- loop through the patterns to see if we can suggest a proper parameter capture = k:match (pattern); -- the whole match if no capture in pattern else the capture if a match if capture then -- if the pattern matches param = utilities.substitute (param, capture); -- add the capture to the suggested parameter (typically the enumerator) if validate (param, config_t.CitationClass) then -- validate the suggestion to make sure that the suggestion is supported by this template (necessary for limited parameter lists) error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, param}); -- set the suggestion error message else error_text = utilities.set_message ('err_parameter_ignored', {k}); -- suggested param not supported by this template v = ''; -- unset end end end if not utilities.is_set (error_text) then -- couldn't match with a pattern, is there an explicit suggestion? if (suggestions.suggestions[ k:lower() ] ~= nil) and validate (suggestions.suggestions[ k:lower() ], config_t.CitationClass) then utilities.set_message ('err_parameter_ignored_suggest', {k, suggestions.suggestions[ k:lower() ]}); else utilities.set_message ('err_parameter_ignored', {k}); v = ''; -- unset value assigned to unrecognized parameters (this for the limited parameter lists) end end end end cite_args_t[k] = v; -- save this parameter and its value elseif not utilities.is_set (v) then -- for empty parameters if not validate (k, config_t.CitationClass, true) then -- is this empty parameter a valid parameter k = ('' == k) and cfg.err_msg_supl.empty_str or k; -- when k is empty string (or was space(s) trimmed to empty string), replace with descriptive text table.insert (empty_unknowns, utilities.wrap_style ('parameter', k)); -- format for error message and add to the list end end end if 0 ~= #empty_unknowns then -- create empty unknown error message utilities.set_message ('err_param_unknown_empty', { 1 == #empty_unknowns and '' or 's', utilities.make_sep_list (#empty_unknowns, empty_unknowns) }); end local non_url_param_t = {}; -- table of parameters and values that are not url-holding parameters local url_param_t = {}; -- table of url-holding paramters and their values for k, v in pairs (cite_args_t) do if 'string' == type (k) then -- don't evaluate positional parameters has_invisible_chars (k, v); -- look for invisible characters end has_extraneous_punc (k, v); -- look for extraneous terminal punctuation in parameter values missing_pipe_check (k, v); -- do we think that there is a parameter that is missing a pipe? cite_args_t[k] = inter_wiki_check (k, v); -- when language interwiki-linked parameter missing leading colon replace with wiki-link label if 'string' == type (k) then -- when parameter k is not positional if not cfg.url_skip[k] then -- and not in url skip table non_url_param_t[k] = v; -- make a parameter/value list for extraneous url check else -- and is in url skip table (a url-holding parameter) url_param_t[k] = v; -- make a parameter/value list to check for values that are The Wikipedia Library url end end end has_extraneous_url (non_url_param_t); -- look for url in parameter values where a url does not belong has_twl_url (url_param_t, cite_args_t); -- look for url-holding parameters that hold a The Wikipedia Library url return table.concat ({ frame:extensionTag ('templatestyles', '', {src='Module:Citation/CS1' .. sandbox .. '/styles.css'}), citation0 (config_t, cite_args_t) }); end --[[--------------------------< C I T A T I O N >-------------------------------------------------------------- Template entry point ]] local function citation (frame) local config_t = {}; -- table to store parameters from the module {{#invoke:}} local args_t = frame:getParent().args; -- get template's preset parameters for k, v in pairs (frame.args) do -- get parameters from the {{#invoke}} frame config_t[k] = v; -- args_t[k] = v; -- crude debug support that allows us to render a citation from module {{#invoke:}}; skips parameter validation; TODO: keep? end return _citation (frame, args_t, config_t) end --[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------ ]] return { citation = citation, -- template entry point _citation = _citation, -- module entry point } 91h7amg34vfj8rsg33ukxle1oetj1iw 736733 736732 2026-02-28T15:14:46Z en>Trappist the monk 0 synch from sandbox; 736733 Scribunto text/plain require ('strict'); --[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- each of these counts against the Lua upvalue limit ]] local validation; -- functions in Module:Citation/CS1/Date_validation local utilities; -- functions in Module:Citation/CS1/Utilities local z = {}; -- table of tables in Module:Citation/CS1/Utilities local identifiers; -- functions and tables in Module:Citation/CS1/Identifiers local metadata; -- functions in Module:Citation/CS1/COinS local cfg = {}; -- table of configuration tables that are defined in Module:Citation/CS1/Configuration local whitelist = {}; -- table of tables listing valid template parameter names; defined in Module:Citation/CS1/Whitelist --[[------------------< P A G E S C O P E V A R I A B L E S >--------------- declare variables here that have page-wide scope that are not brought in from other modules; that are created here and used here ]] local added_deprecated_cat; -- boolean flag so that the category is added only once local added_vanc_errs; -- boolean flag so we only emit one Vancouver error / category local added_generic_name_errs; -- boolean flag so we only emit one generic name error / category and stop testing names once an error is encountered local added_numeric_name_errs; -- boolean flag so we only emit one numeric name error / category and stop testing names once an error is encountered local added_numeric_name_maint; -- boolean flag so we only emit one numeric name maint category and stop testing names once a category has been emitted local is_preview_mode; -- true when article is in preview mode; false when using 'Preview page with this template' (previewing the module) local is_sandbox; -- true when using sandbox modules to render citation local url_was_archive_today; -- boolean flag set to true when has_archive_today_url() has unset |url= because it held a deprecated archive.today url --[[--------------------------< F I R S T _ S E T >------------------------------------------------------------ Locates and returns the first set value in a table of values where the order established in the table, left-to-right (or top-to-bottom), is the order in which the values are evaluated. Returns nil if none are set. This version replaces the original 'for _, val in pairs do' and a similar version that used ipairs. With the pairs version the order of evaluation could not be guaranteed. With the ipairs version, a nil value would terminate the for-loop before it reached the actual end of the list. ]] local function first_set (list, count) local i = 1; while i <= count do -- loop through all items in list if utilities.is_set( list[i] ) then return list[i]; -- return the first set list member end i = i + 1; -- point to next end end --[[--------------------------< A D D _ V A N C _ E R R O R >---------------------------------------------------- Adds a single Vancouver system error message to the template's output regardless of how many error actually exist. To prevent duplication, added_vanc_errs is nil until an error message is emitted. added_vanc_errs is a Boolean declared in page scope variables above ]] local function add_vanc_error (source, position) if added_vanc_errs then return end added_vanc_errs = true; -- note that we've added this category utilities.set_message ('err_vancouver', {source, position}); end --[[--------------------------< I S _ S C H E M E >------------------------------------------------------------ does this thing that purports to be a URI scheme seem to be a valid scheme? The scheme is checked to see if it is in agreement with http://tools.ietf.org/html/std66#section-3.1 which says: Scheme names consist of a sequence of characters beginning with a letter and followed by any combination of letters, digits, plus ("+"), period ("."), or hyphen ("-"). returns true if it does, else false ]] local function is_scheme (scheme) return scheme and scheme:match ('^%a[%a%d%+%.%-]*:'); -- true if scheme is set and matches the pattern end --[=[-------------------------< I S _ D O M A I N _ N A M E >-------------------------------------------------- Does this thing that purports to be a domain name seem to be a valid domain name? Syntax defined here: http://tools.ietf.org/html/rfc1034#section-3.5 BNF defined here: https://tools.ietf.org/html/rfc4234 Single character names are generally reserved; see https://tools.ietf.org/html/draft-ietf-dnsind-iana-dns-01#page-15; see also [[Single-letter second-level domain]] list of TLDs: https://www.iana.org/domains/root/db RFC 952 (modified by RFC 1123) requires the first and last character of a hostname to be a letter or a digit. Between the first and last characters the name may use letters, digits, and the hyphen. Also allowed are IPv4 addresses. IPv6 not supported domain is expected to be stripped of any path so that the last character in the last character of the TLD. tld is two or more alpha characters. Any preceding '//' (from splitting a URL with a scheme) will be stripped here. Perhaps not necessary but retained in case it is necessary for IPv4 dot decimal. There are several tests: the first character of the whole domain name including subdomains must be a letter or a digit internationalized domain name (ASCII characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the TLD) see https://tools.ietf.org/html/rfc3490 single-letter/digit second-level domains in the .org, .cash, and .today TLDs q, x, and z SL domains in the .com TLD i and q SL domains in the .net TLD single-letter SL domains in the ccTLDs (where the ccTLD is two letters) two-character SL domains in gTLDs (where the gTLD is two or more letters) three-plus-character SL domains in gTLDs (where the gTLD is two or more letters) IPv4 dot-decimal address format; TLD not allowed returns true if domain appears to be a proper name and TLD or IPv4 address, else false ]=] local function is_domain_name (domain) if not domain then return false; -- if not set, abandon end domain = domain:gsub ('^//', ''); -- strip '//' from domain name if present; done here so we only have to do it once if not domain:match ('^[%w]') then -- first character must be letter or digit return false; end if domain:match ('^%a+:') then -- hack to detect things that look like s:Page:Title where Page: is namespace at Wikisource return false; end local patterns = { -- patterns that look like URLs '%f[%w][%w][%w%-]+[%w]%.%a%a+$', -- three or more character hostname.hostname or hostname.tld '%f[%w][%w][%w%-]+[%w]%.xn%-%-[%w]+$', -- internationalized domain name with ACE prefix '%f[%a][qxz]%.com$', -- assigned one character .com hostname (x.com times out 2015-12-10) '%f[%a][iq]%.net$', -- assigned one character .net hostname (q.net registered but not active 2015-12-10) '%f[%w][%w]%.%a%a$', -- one character hostname and ccTLD (2 chars) '%f[%w][%w][%w]%.%a%a+$', -- two character hostname and TLD '^%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?', -- IPv4 address '[%a%d]+%:?' -- IPv6 address } for _, pattern in ipairs (patterns) do -- loop through the patterns list if domain:match (pattern) then return true; -- if a match then we think that this thing that purports to be a URL is a URL end end for _, d in ipairs (cfg.single_letter_2nd_lvl_domains_t) do -- look for single letter second level domain names for these top level domains if domain:match ('%f[%w][%w]%.' .. d) then return true end end return false; -- no matches, we don't know what this thing is end --[[--------------------------< I S _ U R L >------------------------------------------------------------------ returns true if the scheme and domain parts of a URL appear to be a valid URL; else false. This function is the last step in the validation process. This function is separate because there are cases that are not covered by split_url(), for example is_parameter_ext_wikilink() which is looking for bracketted external wikilinks. ]] local function is_url (scheme, domain) if utilities.is_set (scheme) then -- if scheme is set check it and domain return is_scheme (scheme) and is_domain_name (domain); else return is_domain_name (domain); -- scheme not set when URL is protocol-relative end end --[[--------------------------< S P L I T _ U R L >------------------------------------------------------------ Split a URL into a scheme, authority indicator, and domain. First remove Fully Qualified Domain Name terminator (a dot following TLD) (if any) and any path(/), query(?) or fragment(#). If protocol-relative URL, return nil scheme and domain else return nil for both scheme and domain. When not protocol-relative, get scheme, authority indicator, and domain. If there is an authority indicator (one or more '/' characters immediately following the scheme's colon), make sure that there are only 2. Any URL that does not have news: scheme must have authority indicator (//). TODO: are there other common schemes like news: that don't use authority indicator? Strip off any port and path; ]] local function split_url (url_str) local scheme, authority, domain; url_str = url_str:gsub ('([%a%d])%.?[/%?#].*$', '%1'); -- strip FQDN terminator and path(/), query(?), fragment (#) (the capture prevents false replacement of '//') if url_str:match ('^//%S*') then -- if there is what appears to be a protocol-relative URL domain = url_str:match ('^//(%S*)') elseif url_str:match ('%S-:/*%S+') then -- if there is what appears to be a scheme, optional authority indicator, and domain name scheme, authority, domain = url_str:match ('(%S-:)(/*)(%S+)'); -- extract the scheme, authority indicator, and domain portions if utilities.is_set (authority) then authority = authority:gsub ('//', '', 1); -- replace place 1 pair of '/' with nothing; if utilities.is_set(authority) then -- if anything left (1 or 3+ '/' where authority should be) then return scheme; -- return scheme only making domain nil which will cause an error message end else if not scheme:match ('^news:') then -- except for news:..., MediaWiki won't link URLs that do not have authority indicator; TODO: a better way to do this test? return scheme; -- return scheme only making domain nil which will cause an error message end end domain = domain:gsub ('(%a):%d+', '%1'); -- strip port number if present end return scheme, domain; end --[[--------------------------< L I N K _ P A R A M _ O K >--------------------------------------------------- checks the content of |title-link=, |series-link=, |author-link=, etc. for properly formatted content: no wikilinks, no URLs Link parameters are to hold the title of a Wikipedia article, so none of the WP:TITLESPECIALCHARACTERS are allowed: # < > [ ] | { } _ except the underscore which is used as a space in wiki URLs and # which is used for section links returns false when the value contains any of these characters. When there are no illegal characters, this function returns TRUE if value DOES NOT appear to be a valid URL (the |<param>-link= parameter is ok); else false when value appears to be a valid URL (the |<param>-link= parameter is NOT ok). ]] local function link_param_ok (value) local scheme, domain; if value:find ('[<>%[%]|{}]') then -- if any prohibited characters return false; end scheme, domain = split_url (value); -- get scheme or nil and domain or nil from URL; return not is_url (scheme, domain); -- return true if value DOES NOT appear to be a valid URL end --[[--------------------------< L I N K _ T I T L E _ O K >--------------------------------------------------- Use link_param_ok() to validate |<param>-link= value and its matching |<title>= value. |<title>= may be wiki-linked but not when |<param>-link= has a value. This function emits an error message when that condition exists check <link> for inter-language interwiki-link prefix. prefix must be a MediaWiki-recognized language code and must begin with a colon. ]] local function link_title_ok (link, lorig, title, torig) local orig; if utilities.is_set (link) then -- don't bother if <param>-link doesn't have a value if not link_param_ok (link) then -- check |<param>-link= markup orig = lorig; -- identify the failing link parameter elseif title:find ('%[%[') then -- check |title= for wikilink markup orig = torig; -- identify the failing |title= parameter elseif link:match ('^%a+:') then -- if the link is what looks like an interwiki local prefix = link:match ('^(%a+):'):lower(); -- get the interwiki prefix if cfg.inter_wiki_map[prefix] then -- if prefix is in the map, must have preceding colon orig = lorig; -- flag as error end end end if utilities.is_set (orig) then link = ''; -- unset utilities.set_message ('err_bad_paramlink', orig); -- URL or wikilink in |title= with |title-link=; end return link; -- link if ok, empty string else end --[[--------------------------< C H E C K _ U R L >------------------------------------------------------------ Determines whether a URL string appears to be valid. First we test for space characters. If any are found, return false. Then split the URL into scheme and domain portions, or for protocol-relative (//example.com) URLs, just the domain. Use is_url() to validate the two portions of the URL. If both are valid, or for protocol-relative if domain is valid, return true, else false. Because it is different from a standard URL, and because this module used external_link() to make external links that work for standard and news: links, we validate newsgroup names here. The specification for a newsgroup name is at https://tools.ietf.org/html/rfc5536#section-3.1.4 ]] local function check_url( url_str ) if nil == url_str:match ("^%S+$") then -- if there are any spaces in |url=value it can't be a proper URL return false; end local scheme, domain; scheme, domain = split_url (url_str); -- get scheme or nil and domain or nil from URL; if 'news:' == scheme then -- special case for newsgroups return domain:match('^[%a%d%+%-_]+%.[%a%d%+%-_%.]*[%a%d%+%-_]$'); end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[=[-------------------------< I S _ P A R A M E T E R _ E X T _ W I K I L I N K >---------------------------- Return true if a parameter value has a string that begins and ends with square brackets [ and ] and the first non-space characters following the opening bracket appear to be a URL. The test will also find external wikilinks that use protocol-relative URLs. Also finds bare URLs. The frontier pattern prevents a match on interwiki-links which are similar to scheme:path URLs. The tests that find bracketed URLs are required because the parameters that call this test (currently |title=, |chapter=, |work=, and |publisher=) may have wikilinks and there are articles or redirects like '//Hus' so, while uncommon, |title=[[//Hus]] is possible as might be [[en://Hus]]. ]=] local function is_parameter_ext_wikilink (value) local scheme, domain; if value:match ('%f[%[]%[%a%S*:%S+.*%]') then -- if ext. wikilink with scheme and domain: [xxxx://yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(%a%S*:%S+).*%]')); elseif value:match ('%f[%[]%[//%S+.*%]') then -- if protocol-relative ext. wikilink: [//yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(//%S+).*%]')); elseif value:match ('%a%S*:%S+') then -- if bare URL with scheme; may have leading or trailing plain text scheme, domain = split_url (value:match ('(%a%S*:%S+)')); elseif value:match ('^//%S+') or value:match ('%s//%S+') then -- if protocol-relative bare URL: //yyyyy.zzz; authority indicator (//) must be be preceded nothing or by whitespace scheme, domain = split_url (value:match ('(//%S+)')); -- what is left should be the domain else return false; -- didn't find anything that is obviously a URL end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[[--------------------------< I S _ A R C H I V E _ T O D A Y _ U R L >-------------------------------------- archive.today (and .ph, .is, .md, .li, .fo, .vn) are deprecated. See Wikipedia:Requests_for_comment/Archive.is_RFC_5 (Special:Permalink/1339352976) <val> is a string that may or may not be a url ]] local function is_archive_today_url (val) if is_parameter_ext_wikilink (val) then -- is <val> a url? local tld = val:match ('archive%.(%l+)'); -- get the tld return tld and cfg.archive_today_tlds_t[tld]; -- return true if <tld> is one of the archive.today tlds; nil else end end --[[--------------------------< H A S _ A R C H I V E _ T O D A Y _ U R L >------------------------------------ blank any parameter that holds one of the archive.today tlds (.today, .ph, .is, .md, .li, .fo, .vn) and also blank parameters that are dependent on the offending parameter. input <cite_args_t> is a table of all of this template's parameters This function modifies <cite_args_t> when |url= or its alias |URL= hold an archive.today url, this function sets the flag <url_was_archive_today> which is used later to suppress the missing url error message from {{citation}} when it has |website=<summat> or from the templates {{cite web}}, {{cite podcast}}, {{cite mailing list}} which all require a url. returns nothing ]] local function has_archive_today_url (cite_args_t) local unset_params_t = {}; -- to hold a sequence of parameters to unset from cite_args_t for p, v in pairs (cite_args_t) do -- look at each parameter in the template if is_archive_today_url (v:lower()) then -- if it has a parameter with an archive.today url table.insert (unset_params_t, p); -- add the url-holding parameter name to our list of parameters to unset (may or may not be a legitimate url parameter) if 'url' == p:lower() then -- if this parameter is |url= or |URL= url_was_archive_today = true; -- set a flag so that cite web / podcast / mailinglist don't emit a missing url error message end if cfg.dependencies_t[p] then -- if this url-holding parameter (<p>) has dependencies for _, dependent in ipairs (cfg.dependencies_t[p]) do -- loop through the url-holding parameter's dependency sequence table.insert (unset_params_t, dependent); -- add dependent parameter to the list to be unset end end end end if 0 < #unset_params_t then -- when there are parameters to unset if not is_preview_mode then -- when in preview mode do not suppress any parameters for _, unset_param in ipairs (unset_params_t) do -- loop through the sequence cite_args_t[unset_param] = nil; -- and unset the url-holding parameter and its dependent parameters to avoid parameter-requires-other-parameter errors end end utilities.set_message ('maint_deprecated_archive'); -- add a maintenance message end end --[[-------------------------< C H E C K _ F O R _ U R L >----------------------------------------------------- loop through a list of parameters and their values. Look at the value and if it has an external link, emit an error message. ]] local function check_for_url (parameter_list, error_list) for k, v in pairs (parameter_list) do -- for each parameter in the list if is_parameter_ext_wikilink (v) then -- look at the value; if there is a URL add an error message table.insert (error_list, utilities.wrap_style ('parameter', k)); end end end --[[--------------------------< S A F E _ F O R _ U R L >------------------------------------------------------ Escape sequences for content that will be used for URL descriptions ]] local function safe_for_url( str ) if str:match( "%[%[.-%]%]" ) ~= nil then utilities.set_message ('err_wikilink_in_url', {}); end return str:gsub( '[%[%]\n]', { ['['] = '&#91;', [']'] = '&#93;', ['\n'] = ' ' } ); end --[[--------------------------< E X T E R N A L _ L I N K >---------------------------------------------------- Format an external link with error checking ]] local function external_link (URL, label, source, access) local err_msg = ''; local domain; local path; local base_url; if not utilities.is_set (label) then label = URL; if utilities.is_set (source) then utilities.set_message ('err_bare_url_missing_title', {utilities.wrap_style ('parameter', source)}); else error (cfg.messages["bare_url_no_origin"]); -- programmer error; valid parameter name does not have matching meta-parameter end end if not check_url (URL) then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); end domain, path = URL:match ('^([/%.%-%+:%a%d]+)([/%?#].*)$'); -- split the URL into scheme plus domain and path if path then -- if there is a path portion path = path:gsub ('[%[%]]', {['['] = '%5b', [']'] = '%5d'}); -- replace '[' and ']' with their percent-encoded values URL = table.concat ({domain, path}); -- and reassemble end base_url = table.concat ({ "[", URL, " ", safe_for_url (label), "]" }); -- assemble a wiki-markup URL if utilities.is_set (access) then -- access level (subscription, registration, limited) base_url = utilities.substitute (cfg.presentation['ext-link-access-signal'], {cfg.presentation[access].class, cfg.presentation[access].title, base_url}); -- add the appropriate icon end return base_url; end --[[--------------------------< D E P R E C A T E D _ P A R A M E T E R >-------------------------------------- Categorize and emit an error message when the citation contains one or more deprecated parameters. The function includes the offending parameter name to the error message. Only one error message is emitted regardless of the number of deprecated parameters in the citation. added_deprecated_cat is a Boolean declared in page scope variables above ]] local function deprecated_parameter(name) if not added_deprecated_cat then added_deprecated_cat = true; -- note that we've added this category utilities.set_message ('err_deprecated_params', {name}); -- add error message end end --[=[-------------------------< K E R N _ Q U O T E S >-------------------------------------------------------- Apply kerning to open the space between the quote mark provided by the module and a leading or trailing quote mark contained in a |title= or |chapter= parameter's value. This function will positive kern either single or double quotes: "'Unkerned title with leading and trailing single quote marks'" " 'Kerned title with leading and trailing single quote marks' " (in real life the kerning isn't as wide as this example) Double single quotes (italic or bold wiki-markup) are not kerned. Replaces Unicode quote marks in plain text or in the label portion of a [[L|D]] style wikilink with typewriter quote marks regardless of the need for kerning. Unicode quote marks are not replaced in simple [[D]] wikilinks. Call this function for chapter titles, for website titles, etc.; not for book titles. ]=] local function kern_quotes (str) local cap = ''; local wl_type, label, link; wl_type, label, link = utilities.is_wikilink (str); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] if 1 == wl_type then -- [[D]] simple wikilink with or without quote marks if mw.ustring.match (str, '%[%[[\"“”\'‘’].+[\"“”\'‘’]%]%]') then -- leading and trailing quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); str = utilities.substitute (cfg.presentation['kern-right'], str); elseif mw.ustring.match (str, '%[%[[\"“”\'‘’].+%]%]') then -- leading quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); elseif mw.ustring.match (str, '%[%[.+[\"“”\'‘’]%]%]') then -- trailing quote marks str = utilities.substitute (cfg.presentation['kern-right'], str); end else -- plain text or [[L|D]]; text in label variable label = mw.ustring.gsub (label, '[“”]', '\"'); -- replace “” (U+201C & U+201D) with " (typewriter double quote mark) label = mw.ustring.gsub (label, '[‘’]', '\''); -- replace ‘’ (U+2018 & U+2019) with ' (typewriter single quote mark) cap = mw.ustring.match (label, "^([\"\'][^\'].+)"); -- match leading double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-left'], cap); end cap = mw.ustring.match (label, "^(.+[^\'][\"\'])$") -- match trailing double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-right'], cap); end if 2 == wl_type then str = utilities.make_wikilink (link, label); -- reassemble the wikilink else str = label; end end return str; end --[[--------------------------< F O R M A T _ S C R I P T _ V A L U E >---------------------------------------- |script-title= holds title parameters that are not written in Latin-based scripts: Chinese, Japanese, Arabic, Hebrew, etc. These scripts should not be italicized and may be written right-to-left. The value supplied by |script-title= is concatenated onto Title after Title has been wrapped in italic markup. Regardless of language, all values provided by |script-title= are wrapped in <bdi>...</bdi> tags to isolate RTL languages from the English left to right. |script-title= provides a unique feature. The value in |script-title= may be prefixed with a two-character ISO 639-1 language code and a colon: |script-title=ja:*** *** (where * represents a Japanese character) Spaces between the two-character code and the colon and the colon and the first script character are allowed: |script-title=ja : *** *** |script-title=ja: *** *** |script-title=ja :*** *** Spaces preceding the prefix are allowed: |script-title = ja:*** *** The prefix is checked for validity. If it is a valid ISO 639-1 language code, the lang attribute (lang="ja") is added to the <bdi> tag so that browsers can know the language the tag contains. This may help the browser render the script more correctly. If the prefix is invalid, the lang attribute is not added. At this time there is no error message for this condition. Supports |script-title=, |script-chapter=, |script-<periodical>= ]] local function format_script_value (script_value, script_param) local lang=''; -- initialize to empty string local name; if script_value:match('^%l%l%l?%s*:') then -- if first 3 or 4 non-space characters are script language prefix lang = script_value:match('^(%l%l%l?)%s*:%s*%S.*'); -- get the language prefix or nil if there is no script if not utilities.is_set (lang) then utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing title part']}); -- prefix without 'title'; add error message return ''; -- script_value was just the prefix so return empty string end -- if we get this far we have prefix and script name = cfg.lang_tag_remap[lang] or mw.language.fetchLanguageName( lang, cfg.this_wiki_code ); -- get language name so that we can use it to categorize if utilities.is_set (name) then -- is prefix a proper ISO 639-1 language code? script_value = script_value:gsub ('^%l+%s*:%s*', ''); -- strip prefix from script -- is prefix one of these language codes? if utilities.in_array (lang, cfg.script_lang_codes) then utilities.add_prop_cat ('script', {name, lang}) else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['unknown language code']}); -- unknown script-language; add error message end lang = ' lang="' .. lang .. '" '; -- convert prefix into a lang attribute else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['invalid language code']}); -- invalid language code; add error message lang = ''; -- invalid so set lang to empty string end else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing prefix']}); -- no language code prefix; add error message end script_value = utilities.substitute (cfg.presentation['bdi'], {lang, script_value}); -- isolate in case script is RTL return script_value; end --[[--------------------------< S C R I P T _ C O N C A T E N A T E >------------------------------------------ Initially for |title= and |script-title=, this function concatenates those two parameter values after the script value has been wrapped in <bdi> tags. ]] local function script_concatenate (title, script, script_param) if utilities.is_set (script) then script = format_script_value (script, script_param); -- <bdi> tags, lang attribute, categorization, etc.; returns empty string on error if utilities.is_set (script) then title = title .. ' ' .. script; -- concatenate title and script title end end return title; end --[[--------------------------< W R A P _ M S G >-------------------------------------------------------------- Applies additional message text to various parameter values. Supplied string is wrapped using a message_list configuration taking one argument. Supports lower case text for {{citation}} templates. Additional text taken from citation_config.messages - the reason this function is similar to but separate from wrap_style(). ]] local function wrap_msg (key, str, lower) if not utilities.is_set ( str ) then return ""; end if true == lower then local msg; msg = cfg.messages[key]:lower(); -- set the message to lower case before return utilities.substitute ( msg, str ); -- including template text else return utilities.substitute ( cfg.messages[key], str ); end end --[[----------------< W I K I S O U R C E _ U R L _ M A K E >------------------- Makes a Wikisource URL from Wikisource interwiki-link. Returns the URL and appropriate label; nil else. str is the value assigned to |chapter= (or aliases) or |title= or |title-link= ]] local function wikisource_url_make (str) local wl_type, D, L; local ws_url, ws_label; local wikisource_prefix = table.concat ({'https://', cfg.this_wiki_code, '.wikisource.org/wiki/'}); wl_type, D, L = utilities.is_wikilink (str); -- wl_type is 0 (not a wikilink), 1 (simple wikilink), 2 (complex wikilink) if 0 == wl_type then -- not a wikilink; might be from |title-link= str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 1 == wl_type then -- simple wikilink: [[Wikisource:ws article]] str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 2 == wl_type then -- non-so-simple wikilink: [[Wikisource:ws article|displayed text]] ([[L|D]]) str = L:match ('^[Ww]ikisource:(.+)') or L:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_label = D; -- get ws article name from display portion of interwiki link ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title without namespace from link portion of wikilink }); end end if ws_url then ws_url = mw.uri.encode (ws_url, 'WIKI'); -- make a usable URL ws_url = ws_url:gsub ('%%23', '#'); -- undo percent-encoding of fragment marker end return ws_url, ws_label, L or D; -- return proper URL or nil and a label or nil end --[[----------------< F O R M A T _ P E R I O D I C A L >----------------------- Format the three periodical parameters: |script-<periodical>=, |<periodical>=, and |trans-<periodical>= into a single Periodical meta-parameter. ]] local function format_periodical (script_periodical, script_periodical_source, periodical, trans_periodical) if not utilities.is_set (periodical) then periodical = ''; -- to be safe for concatenation else periodical = utilities.wrap_style ('italic-title', periodical); -- style end periodical = script_concatenate (periodical, script_periodical, script_periodical_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (trans_periodical) then trans_periodical = utilities.wrap_style ('trans-italic-title', trans_periodical); if utilities.is_set (periodical) then periodical = periodical .. ' ' .. trans_periodical; else -- here when trans-periodical without periodical or script-periodical periodical = trans_periodical; utilities.set_message ('err_trans_missing_title', {'periodical'}); end end return periodical; end --[[------------------< F O R M A T _ C H A P T E R _ T I T L E >--------------- Format the four chapter parameters: |script-chapter=, |chapter=, |trans-chapter=, and |chapter-url= into a single chapter meta- parameter (chapter_url_source used for error messages). ]] local function format_chapter_title (script_chapter, script_chapter_source, chapter, chapter_source, trans_chapter, trans_chapter_source, chapter_url, chapter_url_source, no_quotes, access) local ws_url, ws_label, L = wikisource_url_make (chapter); -- make a wikisource URL and label from a wikisource interwiki link if ws_url then ws_label = ws_label:gsub ('_', ' '); -- replace underscore separators with space characters chapter = ws_label; end if not utilities.is_set (chapter) then chapter = ''; -- to be safe for concatenation else if false == no_quotes then chapter = kern_quotes (chapter); -- if necessary, separate chapter title's leading and trailing quote marks from module provided quote marks chapter = utilities.wrap_style ('quoted-title', chapter); end end chapter = script_concatenate (chapter, script_chapter, script_chapter_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (chapter_url) then chapter = external_link (chapter_url, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate elseif ws_url then chapter = external_link (ws_url, chapter .. '&nbsp;', 'ws link in chapter'); -- adds bare_url_missing_title error if appropriate; space char to move icon away from chap text; TODO: better way to do this? chapter = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, chapter}); end if utilities.is_set (trans_chapter) then trans_chapter = utilities.wrap_style ('trans-quoted-title', trans_chapter); if utilities.is_set (chapter) then chapter = chapter .. ' ' .. trans_chapter; else -- here when trans_chapter without chapter or script-chapter chapter = trans_chapter; chapter_source = trans_chapter_source:match ('trans%-?(.+)'); -- when no chapter, get matching name from trans-<param> utilities.set_message ('err_trans_missing_title', {chapter_source}); end end return chapter; end --[[----------------< H A S _ I N V I S I B L E _ C H A R S >------------------- This function searches a parameter's value for non-printable or invisible characters. The search stops at the first match. This function will detect the visible replacement character when it is part of the Wikisource. Detects but ignores nowiki and math stripmarkers. Also detects other named stripmarkers (gallery, math, pre, ref) and identifies them with a slightly different error message. See also coins_cleanup(). Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker that was detected along with its position (or, for multi-byte characters, the position of its first byte) in the parameter value. ]] local function has_invisible_chars (param, v) local position = ''; -- position of invisible char or starting position of stripmarker local capture; -- used by stripmarker detection to hold name of the stripmarker local stripmarker; -- boolean set true when a stripmarker is found capture = string.match (v, '[%w%p ]*'); -- test for values that are simple ASCII text and bypass other tests if true if capture == v then -- if same there are no Unicode characters return; end for _, invisible_char in ipairs (cfg.invisible_chars) do local char_name = invisible_char[1]; -- the character or group name local pattern = invisible_char[2]; -- the pattern used to find it position, _, capture = mw.ustring.find (v, pattern); -- see if the parameter value contains characters that match the pattern if position and (cfg.invisible_defs.zwj == capture) then -- if we found a zero-width joiner character if mw.ustring.find (v, cfg.indic_script) then -- it's ok if one of the Indic scripts position = nil; -- unset position elseif cfg.emoji_t[mw.ustring.codepoint (v, position+1)] then -- is zwj followed by a character listed in emoji{}? position = nil; -- unset position end end if position then if 'nowiki' == capture or 'math' == capture or -- nowiki and math stripmarkers (not an error condition) ('templatestyles' == capture and utilities.in_array (param, {'id', 'quote'})) then -- templatestyles stripmarker allowed in these parameters stripmarker = true; -- set a flag elseif true == stripmarker and cfg.invisible_defs.del == capture then -- because stripmakers begin and end with the delete char, assume that we've found one end of a stripmarker position = nil; -- unset else local err_msg; if capture and not (cfg.invisible_defs.del == capture or cfg.invisible_defs.zwj == capture) then err_msg = utilities.substitute (cfg.messages.invisible_1, {capture, char_name}); -- <capture> here is stripmarker name else err_msg = utilities.substitute (cfg.messages.invisible_2, char_name); end utilities.set_message ('err_invisible_char', {err_msg, utilities.wrap_style ('parameter', param), position}); -- add error message return; -- and done with this parameter end end end end --[[-------------------< A R G U M E N T _ W R A P P E R >---------------------- Argument wrapper. This function provides support for argument mapping defined in the configuration file so that multiple names can be transparently aliased to single internal variable. ]] local function argument_wrapper ( args ) local origin = {}; return setmetatable({ ORIGIN = function ( self, k ) local dummy = self[k]; -- force the variable to be loaded. return origin[k]; end }, { __index = function ( tbl, k ) if origin[k] ~= nil then return nil; end local args, list, v = args, cfg.aliases[k]; if type( list ) == 'table' then v, origin[k] = utilities.select_one ( args, list, 'err_redundant_parameters' ); if origin[k] == nil then origin[k] = ''; -- Empty string, not nil end elseif list ~= nil then v, origin[k] = args[list], list; else -- maybe let through instead of raising an error? -- v, origin[k] = args[k], k; error( cfg.messages['unknown_argument_map'] .. ': ' .. k); end -- Empty strings, not nil; if v == nil then v = ''; origin[k] = ''; end tbl = rawset( tbl, k, v ); return v; end, }); end --[[--------------------------< N O W R A P _ D A T E >------------------------- When date is YYYY-MM-DD format wrap in nowrap span: <span ...>YYYY-MM-DD</span>. When date is DD MMMM YYYY or is MMMM DD, YYYY then wrap in nowrap span: <span ...>DD MMMM</span> YYYY or <span ...>MMMM DD,</span> YYYY DOES NOT yet support MMMM YYYY or any of the date ranges. ]] local function nowrap_date (date) local cap = ''; local cap2 = ''; if date:match("^%d%d%d%d%-%d%d%-%d%d$") then date = utilities.substitute (cfg.presentation['nowrap1'], date); elseif date:match("^%a+%s*%d%d?,%s+%d%d%d%d$") or date:match ("^%d%d?%s*%a+%s+%d%d%d%d$") then cap, cap2 = string.match (date, "^(.*)%s+(%d%d%d%d)$"); date = utilities.substitute (cfg.presentation['nowrap2'], {cap, cap2}); end return date; end --[[--------------------------< S E T _ T I T L E T Y P E >--------------------- This function sets default title types (equivalent to the citation including |type=<default value>) for those templates that have defaults. Also handles the special case where it is desirable to omit the title type from the rendered citation (|type=none). ]] local function set_titletype (cite_class, title_type) if utilities.is_set (title_type) then if 'none' == cfg.keywords_xlate[title_type] then title_type = ''; -- if |type=none then type parameter not displayed end return title_type; -- if |type= has been set to any other value use that value end return cfg.title_types [cite_class] or ''; -- set template's default title type; else empty string for concatenation end --[[--------------------------< S A F E _ J O I N >----------------------------- Joins a sequence of strings together while checking for duplicate separation characters. ]] local function safe_join( tbl, duplicate_char ) local f = {}; -- create a function table appropriate to type of 'duplicate character' if 1 == #duplicate_char then -- for single byte ASCII characters use the string library functions f.gsub = string.gsub f.match = string.match f.sub = string.sub else -- for multi-byte characters use the ustring library functions f.gsub = mw.ustring.gsub f.match = mw.ustring.match f.sub = mw.ustring.sub end local str = ''; -- the output string local comp = ''; -- what does 'comp' mean? local end_chr = ''; local trim; for _, value in ipairs( tbl ) do if value == nil then value = ''; end if str == '' then -- if output string is empty str = value; -- assign value to it (first time through the loop) elseif value ~= '' then if value:sub(1, 1) == '<' then -- special case of values enclosed in spans and other markup. comp = value:gsub( "%b<>", "" ); -- remove HTML markup (<span>string</span> -> string) else comp = value; end -- typically duplicate_char is sepc if f.sub(comp, 1, 1) == duplicate_char then -- is first character same as duplicate_char? why test first character? -- Because individual string segments often (always?) begin with terminal punct for the -- preceding segment: 'First element' .. 'sepc next element' .. etc.? trim = false; end_chr = f.sub(str, -1, -1); -- get the last character of the output string -- str = str .. "<HERE(enchr=" .. end_chr .. ")" -- debug stuff? if end_chr == duplicate_char then -- if same as separator str = f.sub(str, 1, -2); -- remove it elseif end_chr == "'" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "''" then -- if last three chars of str are sepc'' str = f.sub(str, 1, -4) .. "''"; -- remove them and add back '' elseif f.sub(str, -5, -1) == duplicate_char .. "]]''" then -- if last five chars of str are sepc]]'' trim = true; -- why? why do this and next differently from previous? elseif f.sub(str, -4, -1) == duplicate_char .. "]''" then -- if last four chars of str are sepc]'' trim = true; -- same question end elseif end_chr == "]" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "]]" then -- if last three chars of str are sepc]] wikilink trim = true; elseif f.sub(str, -3, -1) == duplicate_char .. '"]' then -- if last three chars of str are sepc"] quoted external link trim = true; elseif f.sub(str, -2, -1) == duplicate_char .. "]" then -- if last two chars of str are sepc] external link trim = true; elseif f.sub(str, -4, -1) == duplicate_char .. "'']" then -- normal case when |url=something & |title=Title. trim = true; end elseif end_chr == " " then -- if last char of output string is a space if f.sub(str, -2, -1) == duplicate_char .. " " then -- if last two chars of str are <sepc><space> str = f.sub(str, 1, -3); -- remove them both end end if trim then if value ~= comp then -- value does not equal comp when value contains HTML markup local dup2 = duplicate_char; if f.match(dup2, "%A" ) then dup2 = "%" .. dup2; end -- if duplicate_char not a letter then escape it value = f.gsub(value, "(%b<>)" .. dup2, "%1", 1 ) -- remove duplicate_char if it follows HTML markup else value = f.sub(value, 2, -1 ); -- remove duplicate_char when it is first character end end end str = str .. value; -- add it to the output string end end return str; end --[[--------------------------< I S _ S U F F I X >----------------------------- returns true if suffix is properly formed Jr, Sr, or ordinal in the range 1–9. Puncutation not allowed. ]] local function is_suffix (suffix) if utilities.in_array (suffix, {'Jr', 'Sr', 'Jnr', 'Snr', '1st', '2nd', '3rd'}) or suffix:match ('^%dth$') then return true; end return false; end --[[--------------------< I S _ G O O D _ V A N C _ N A M E >------------------- For Vancouver style, author/editor names are supposed to be rendered in Latin (read ASCII) characters. When a name uses characters that contain diacritical marks, those characters are to be converted to the corresponding Latin character. When a name is written using a non-Latin alphabet or logogram, that name is to be transliterated into Latin characters. The module doesn't do this so editors may/must. This test allows |first= and |last= names to contain any of the letters defined in the four Unicode Latin character sets [http://www.unicode.org/charts/PDF/U0000.pdf C0 Controls and Basic Latin] 0041–005A, 0061–007A [http://www.unicode.org/charts/PDF/U0080.pdf C1 Controls and Latin-1 Supplement] 00C0–00D6, 00D8–00F6, 00F8–00FF [http://www.unicode.org/charts/PDF/U0100.pdf Latin Extended-A] 0100–017F [http://www.unicode.org/charts/PDF/U0180.pdf Latin Extended-B] 0180–01BF, 01C4–024F |lastn= also allowed to contain hyphens, spaces, and apostrophes. (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) |firstn= also allowed to contain hyphens, spaces, apostrophes, and periods This original test: if nil == mw.ustring.find (last, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%'%.]+[2-6%a]*$") then was written outside of the code editor and pasted here because the code editor gets confused between character insertion point and cursor position. The test has been rewritten to use decimal character escape sequence for the individual bytes of the Unicode characters so that it is not necessary to use an external editor to maintain this code. \195\128-\195\150 – À-Ö (U+00C0–U+00D6 – C0 controls) \195\152-\195\182 – Ø-ö (U+00D8-U+00F6 – C0 controls) \195\184-\198\191 – ø-ƿ (U+00F8-U+01BF – C0 controls, Latin extended A & B) \199\132-\201\143 – DŽ-ɏ (U+01C4-U+024F – Latin extended B) ]] local function is_good_vanc_name (last, first, suffix, position) if not suffix then if first:find ('[,%s]') then -- when there is a space or comma, might be first name/initials + generational suffix first = first:match ('(.-)[,%s]+'); -- get name/initials suffix = first:match ('[,%s]+(.+)$'); -- get generational suffix end end if utilities.is_set (suffix) then if not is_suffix (suffix) then add_vanc_error (cfg.err_msg_supl.suffix, position); return false; -- not a name with an appropriate suffix end end if nil == mw.ustring.find (last, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%'%.]*$") then add_vanc_error (cfg.err_msg_supl['non-Latin char'], position); return false; -- not a string of Latin characters; Vancouver requires Romanization end; return true; end --[[--------------------------< R E D U C E _ T O _ I N I T I A L S >------------------------------------------ Attempts to convert names to initials in support of |name-list-style=vanc. Names in |firstn= may be separated by spaces or hyphens, or for initials, a period. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35062/. Vancouver style requires family rank designations (Jr, II, III, etc.) to be rendered as Jr, 2nd, 3rd, etc. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35085/. This code only accepts and understands generational suffix in the Vancouver format because Roman numerals look like, and can be mistaken for, initials. This function uses ustring functions because firstname initials may be any of the Unicode Latin characters accepted by is_good_vanc_name (). ]] local function reduce_to_initials (first, position) if first:find (',', 1, true) then return first; -- commas not allowed; abandon end local name, suffix = mw.ustring.match (first, "^(%u+) ([%dJS][%drndth]+)$"); if not name then -- if not initials and a suffix name = mw.ustring.match (first, "^(%u+)$"); -- is it just initials? end if name then -- if first is initials with or without suffix if 3 > mw.ustring.len (name) then -- if one or two initials if suffix then -- if there is a suffix if is_suffix (suffix) then -- is it legitimate? return first; -- one or two initials and a valid suffix so nothing to do else add_vanc_error (cfg.err_msg_supl.suffix, position); -- one or two initials with invalid suffix so error message return first; -- and return first unmolested end else return first; -- one or two initials without suffix; nothing to do end end end -- if here then name has 3 or more uppercase letters so treat them as a word local initials_t, names_t = {}, {}; -- tables to hold name parts and initials local i = 1; -- counter for number of initials names_t = mw.text.split (first, '[%s%-]+'); -- split into a sequence of names and possible suffix while names_t[i] do -- loop through the sequence if 1 < i and names_t[i]:match ('[%dJS][%drndth]+%.?$') then -- if not the first name, and looks like a suffix (may have trailing dot) names_t[i] = names_t[i]:gsub ('%.', ''); -- remove terminal dot if present if is_suffix (names_t[i]) then -- if a legitimate suffix table.insert (initials_t, ' ' .. names_t[i]); -- add a separator space, insert at end of initials sequence break; -- and done because suffix must fall at the end of a name end -- no error message if not a suffix; possibly because of Romanization end if 3 > i then table.insert (initials_t, mw.ustring.sub (names_t[i], 1, 1)); -- insert the initial at end of initials sequence end i = i + 1; -- bump the counter end return table.concat (initials_t); -- Vancouver format does not include spaces. end --[[--------------------------< I N T E R W I K I _ P R E F I X E N _ G E T >---------------------------------- extract interwiki prefixen from <value>. Returns two one or two values: false – no prefixen nil – prefix exists but not recognized project prefix, language prefix – when value has either of: :<project>:<language>:<article> :<language>:<project>:<article> project prefix, nil – when <value> has only a known single-letter prefix nil, language prefix – when <value> has only a known language prefix accepts single-letter project prefixen: 'd' (wikidata), 's' (wikisource), and 'w' (wikipedia) prefixes; at this writing, the other single-letter prefixen (b (wikibook), c (commons), m (meta), n (wikinews), q (wikiquote), and v (wikiversity)) are not supported. ]] local function interwiki_prefixen_get (value, is_link) if not value:find (':%l+:') then -- if no prefix return false; -- abandon; boolean here to distinguish from nil fail returns later end local prefix_patterns_linked_t = { -- sequence of valid interwiki and inter project prefixen '^%[%[:([dsw]):(%l%l+):', -- wikilinked; project and language prefixes '^%[%[:(%l%l+):([dsw]):', -- wikilinked; language and project prefixes '^%[%[:([dsw]):', -- wikilinked; project prefix '^%[%[:(%l%l+):', -- wikilinked; language prefix } local prefix_patterns_unlinked_t = { -- sequence of valid interwiki and inter project prefixen '^:([dsw]):(%l%l+):', -- project and language prefixes '^:(%l%l+):([dsw]):', -- language and project prefixes '^:([dsw]):', -- project prefix '^:(%l%l+):', -- language prefix } local cap1, cap2; for _, pattern in ipairs ((is_link and prefix_patterns_linked_t) or prefix_patterns_unlinked_t) do cap1, cap2 = value:match (pattern); if cap1 then break; -- found a match so stop looking end end if cap1 and cap2 then -- when both then :project:language: or :language:project: (both forms allowed) if 1 == #cap1 then -- length == 1 then :project:language: if cfg.inter_wiki_map[cap2] then -- is language prefix in the interwiki map? return cap1, cap2; -- return interwiki project and interwiki language end else -- here when :language:project: if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return cap2, cap1; -- return interwiki project and interwiki language end end return nil; -- unknown interwiki language elseif not (cap1 or cap2) then -- both are nil? return nil; -- we got something that looks like a project prefix but isn't; return fail elseif 1 == #cap1 then -- here when one capture return cap1, nil; -- length is 1 so return project, nil language else -- here when one capture and its length it more than 1 if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return nil, cap1; -- return nil project, language end end end --[[--------------------------< L I S T _ P E O P L E >-------------------------- Formats a list of people (authors, contributors, editors, interviewers, translators) names in the list will be linked when |<name>-link= has a value |<name>-mask- does NOT have a value; masked names are presumed to have been rendered previously so should have been linked there when |<name>-mask=0, the associated name is not rendered ]] local function list_people (control, people, etal) local sep; local namesep; local format = control.format; local maximum = control.maximum; local name_list = {}; if 'vanc' == format then -- Vancouver-like name styling? sep = cfg.presentation['sep_nl_vanc']; -- name-list separator between names is a comma namesep = cfg.presentation['sep_name_vanc']; -- last/first separator is a space else sep = cfg.presentation['sep_nl']; -- name-list separator between names is a semicolon namesep = cfg.presentation['sep_name']; -- last/first separator is <comma><space> end if sep:sub (-1, -1) ~= " " then sep = sep .. " " end if utilities.is_set (maximum) and maximum < 1 then return "", 0; end -- returned 0 is for EditorCount; not used for other names for i, person in ipairs (people) do if utilities.is_set (person.last) then local mask = person.mask; local one; local sep_one = sep; if utilities.is_set (maximum) and i > maximum then etal = true; break; end if mask then local n = tonumber (mask); -- convert to a number if it can be converted; nil else if n then one = 0 ~= n and string.rep("&mdash;", n) or nil; -- make a string of (n > 0) mdashes, nil else, to replace name person.link = nil; -- don't create link to name if name is replaces with mdash string or has been set nil else one = mask; -- replace name with mask text (must include name-list separator) sep_one = " "; -- modify name-list separator end else one = person.last; -- get surname local first = person.first -- get given name if utilities.is_set (first) then if ("vanc" == format) then -- if Vancouver format one = one:gsub ('%.', ''); -- remove periods from surnames (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) if not person.corporate and is_good_vanc_name (one, first, nil, i) then -- and name is all Latin characters; corporate authors not tested first = reduce_to_initials (first, i); -- attempt to convert first name(s) to initials end end one = one .. namesep .. first; end end if utilities.is_set (person.link) then one = utilities.make_wikilink (person.link, one); -- link author/editor end if one then -- if <one> has a value (name, mdash replacement, or mask text replacement) local proj, tag = interwiki_prefixen_get (one, true); -- get the interwiki prefixen if present if 'w' == proj and ('Wikipedia' == mw.site.namespaces.Project['name']) then proj = nil; -- for stuff like :w:de:<article>, :w is unnecessary TODO: maint cat? end if proj then local proj_name = ({['d'] = cfg.messages.wikidata, ['s'] = cfg.messages.wikisource, ['w'] = cfg.messages.wikipedia})[proj]; -- :w (wikipedia) for linking from a non-wikipedia project if proj_name then one = one .. utilities.wrap_style ('interproj', proj_name); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interproj-linked-name', proj); -- categorize it; <proj> is sort key tag = nil; -- unset; don't do both project and language end end if tag == cfg.this_wiki_code then tag = nil; -- stuff like :en:<article> at en.wiki is pointless TODO: maint cat? end if tag then local lang = cfg.lang_tag_remap[tag] or cfg.mw_languages_by_tag_t[tag]; if lang then -- error messaging done in extract_names() where we know parameter names one = one .. utilities.wrap_style ('interwiki', lang); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interwiki-linked-name', tag); -- categorize it; <tag> is sort key end end table.insert (name_list, one); -- add it to the list of names table.insert (name_list, sep_one); -- add the proper name-list separator end end end local count = #name_list / 2; -- (number of names + number of separators) divided by 2 if 0 < count then if 1 < count and not etal then if 'amp' == format then name_list[#name_list-2] = " & "; -- replace last separator with ampersand text elseif 'and' == format then if 2 == count then name_list[#name_list-2] = cfg.presentation.sep_nl_and; -- replace last separator with 'and' text else name_list[#name_list-2] = cfg.presentation.sep_nl_end; -- replace last separator with '(sep) and' text end end end name_list[#name_list] = nil; -- erase the last separator end local result = table.concat (name_list); -- construct list if etal and utilities.is_set (result) then -- etal may be set by |display-authors=etal but we might not have a last-first list result = result .. sep .. cfg.messages['et al']; -- we've got a last-first list and etal so add et al. end return result, count; -- return name-list string and count of number of names (count used for editor names only) end --[[--------------------< M A K E _ C I T E R E F _ I D >----------------------- Generates a CITEREF anchor ID if we have at least one name or a date. Otherwise returns an empty string. namelist is one of the contributor-, author-, or editor-name lists chosen in that order. year is Year or anchor_year. ]] local function make_citeref_id (namelist, year) local names={}; -- a table for the one to four names and year for i,v in ipairs (namelist) do -- loop through the list and take up to the first four last names names[i] = v.last if i == 4 then break end -- if four then done end table.insert (names, year); -- add the year at the end local id = table.concat(names); -- concatenate names and year for CITEREF id if utilities.is_set (id) then -- if concatenation is not an empty string return "CITEREF" .. id; -- add the CITEREF portion else return ''; -- return an empty string; no reason to include CITEREF id in this citation end end --[[--------------------------< C I T E _ C L A S S _A T T R I B U T E _M A K E >------------------------------ construct <cite> tag class attribute for this citation. <cite_class> – config.CitationClass from calling template <mode> – value from |mode= parameter ]] local function cite_class_attribute_make (cite_class, mode) local class_t = {}; table.insert (class_t, 'citation'); -- required for blue highlight if 'citation' ~= cite_class then table.insert (class_t, cite_class); -- identify this template for user css table.insert (class_t, utilities.is_set (mode) and mode or 'cs1'); -- identify the citation style for user css or javascript else table.insert (class_t, utilities.is_set (mode) and mode or 'cs2'); -- identify the citation style for user css or javascript end for _, prop_key in ipairs (z.prop_keys_t) do table.insert (class_t, prop_key); -- identify various properties for user css or javascript end return table.concat (class_t, ' '); -- make a big string and done end --[[---------------------< N A M E _ H A S _ E T A L >-------------------------- Evaluates the content of name parameters (author, editor, etc.) for variations on the theme of et al. If found, the et al. is removed, a flag is set to true and the function returns the modified name and the flag. This function never sets the flag to false but returns its previous state because it may have been set by previous passes through this function or by the associated |display-<names>=etal parameter ]] local function name_has_etal (name, etal, nocat, param) if utilities.is_set (name) then -- name can be nil in which case just return local patterns = cfg.et_al_patterns; -- get patterns from configuration for _, pattern in ipairs (patterns) do -- loop through all of the patterns if name:match (pattern) then -- if this 'et al' pattern is found in name name = name:gsub (pattern, ''); -- remove the offending text etal = true; -- set flag (may have been set previously here or by |display-<names>=etal) if not nocat then -- no categorization for |vauthors= utilities.set_message ('err_etal', {param}); -- and set an error if not added end end end end return name, etal; end --[[---------------------< N A M E _ I S _ N U M E R I C >---------------------- Add an error message and category when <name> parameter value does not contain letters. Add a maintenance category when <name> parameter value has numeric characters mixed with characters that are not numeric characters; could be letters and/or punctuation characters. This function will only emit one error and one maint message for the current template. Does not emit both error and maint messages/categories for the same parameter value. returns nothing ]] local function name_is_numeric (name, name_alias, list_name) local patterns = { '^%D+%d', -- <name> must have digits preceded by other characters '^%D*%d+%D+', -- <name> must have digits followed by other characters } if not added_numeric_name_errs and mw.ustring.match (name, '^[%A]+$') then -- if we have not already set an error message and <name> does not have any alpha characters utilities.set_message ('err_numeric_names', name_alias); -- add an error message added_numeric_name_errs = true; -- set the flag so we emit only one error message return; -- when here no point in further testing; abandon end if not added_numeric_name_maint then -- if we have already set a maint message for _, pattern in ipairs (patterns) do -- spin through list of patterns if mw.ustring.match (name, pattern) then -- digits preceded or followed by anything but digits; %D+ includes punctuation utilities.set_message ('maint_numeric_names', cfg.special_case_translation [list_name]); -- add a maint cat for this template added_numeric_name_maint = true; -- set the flag so we emit only one maint message return; -- when here no point in further testing; abandon end end end end --[[-----------------< N A M E _ H A S _ M U L T _ N A M E S >------------------ Evaluates the content of last/surname (authors etc.) parameters for multiple names. Multiple names are indicated if there is more than one comma or any "unescaped" semicolons. Escaped semicolons are ones used as part of selected HTML entities. If the condition is met, the function adds the multiple name maintenance category. Same test for first except that commas should not appear in given names (MOS:JR says that the generational suffix does not take a separator character). Titles, degrees, postnominals, affiliations, all normally comma separated don't belong in a citation. <name> – name parameter value <list_name> – AuthorList, EditorList, etc <limit> – number of allowed commas; 1 (default) for surnames; 0 for given names returns nothing ]] local function name_has_mult_names (name, list_name, limit) local _, commas, semicolons, nbsps; limit = limit and limit or 1; if utilities.is_set (name) then _, commas = name:gsub (',', ''); -- count the number of commas _, semicolons = name:gsub (';', ''); -- count the number of semicolons -- nbsps probably should be its own separate count rather than merged in -- some way with semicolons because Lua patterns do not support the -- grouping operator that regex does, which means there is no way to add -- more entities to escape except by adding more counts with the new -- entities _, nbsps = name:gsub ('&nbsp;',''); -- count nbsps -- There is exactly 1 semicolon per &nbsp; entity, so subtract nbsps -- from semicolons to 'escape' them. If additional entities are added, -- they also can be subtracted. if limit < commas or 0 < (semicolons - nbsps) then utilities.set_message ('maint_mult_names', cfg.special_case_translation [list_name]); -- add a maint message end end end --[=[-------------------------< I S _ G E N E R I C >---------------------------------------------------------- Compares values assigned to various parameters according to the string provided as <item> in the function call. <item> can have on of two values: 'generic_names' – for name-holding parameters: |last=, |first=, |editor-last=, etc 'generic_titles' – for |title= There are two types of generic tests. The 'accept' tests look for a pattern that should not be rejected by the 'reject' test. For example, |author=[[John Smith (author)|Smith, John]] would be rejected by the 'author' reject test. But piped wikilinks with 'author' disambiguation should not be rejected so the 'accept' test prevents that from happening. Accept tests are always performed before reject tests. Each of the 'accept' and 'reject' sequence tables hold tables for en.wiki (['en']) and local.wiki (['local']) that each can hold a test sequence table The sequence table holds, at index [1], a test pattern, and, at index [2], a boolean control value. The control value tells string.find() or mw.ustring.find() to do plain-text search (true) or a pattern search (false). The intent of all this complexity is to make these searches as fast as possible so that we don't run out of processing time on very large articles. Returns true when a reject test finds the pattern or string false when an accept test finds the pattern or string nil else ]=] local function is_generic (item, value, wiki) local test_val; local str_lower = { -- use string.lower() for en.wiki (['en']) and use mw.ustring.lower() or local.wiki (['local']) ['en'] = string.lower, ['local'] = mw.ustring.lower, } local str_find = { -- use string.find() for en.wiki (['en']) and use mw.ustring.find() or local.wiki (['local']) ['en'] = string.find, ['local'] = mw.ustring.find, } local function test (val, test_t, wiki) -- local function to do the testing; <wiki> selects lower() and find() functions val = test_t[2] and str_lower[wiki](value) or val; -- when <test_t[2]> set to 'true', plaintext search using lowercase value return str_find[wiki] (val, test_t[1], 1, test_t[2]); -- return nil when not found or matched end local test_types_t = {'accept', 'reject'}; -- test accept patterns first, then reject patterns local wikis_t = {'en', 'local'}; -- do tests for each of these keys; en.wiki first, local.wiki second for _, test_type in ipairs (test_types_t) do -- for each test type for _, generic_value in pairs (cfg.special_case_translation[item][test_type]) do -- spin through the list of generic value fragments to accept or reject for _, wiki in ipairs (wikis_t) do if generic_value[wiki] then if test (value, generic_value[wiki], wiki) then -- go do the test return ('reject' == test_type); -- param value rejected, return true; false else end end end end end end --[[--------------------------< N A M E _ I S _ G E N E R I C >------------------------------------------------ calls is_generic() to determine if <name> is a 'generic name' listed in cfg.generic_names; <name_alias> is the parameter name used in error messaging ]] local function name_is_generic (name, name_alias) if not added_generic_name_errs and is_generic ('generic_names', name) then utilities.set_message ('err_generic_name', name_alias); -- set an error message added_generic_name_errs = true; end end --[[--------------------------< N A M E _ C H E C K S >-------------------------------------------------------- This function calls various name checking functions used to validate the content of the various name-holding parameters. ]] local function name_checks (last, first, list_name, last_alias, first_alias) local accept_name; if utilities.is_set (last) then last, accept_name = utilities.has_accept_as_written (last); -- remove accept-this-as-written markup when it wraps all of <last> if not accept_name then -- <last> not wrapped in accept-as-written markup name_has_mult_names (last, list_name); -- check for multiple names in the parameter name_is_numeric (last, last_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (last, last_alias); -- check for names found in the generic names list end end if utilities.is_set (first) then first, accept_name = utilities.has_accept_as_written (first); -- remove accept-this-as-written markup when it wraps all of <first> if not accept_name then -- <first> not wrapped in accept-as-written markup name_has_mult_names (first, list_name, 0); -- check for multiple names in the parameter; 0 is number of allowed commas in a given name name_is_numeric (first, first_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (first, first_alias); -- check for names found in the generic names list end local wl_type, D = utilities.is_wikilink (first); if 0 ~= wl_type then first = D; utilities.set_message ('err_bad_paramlink', first_alias); end end return last, first; -- done end --[[----------------------< E X T R A C T _ N A M E S >------------------------- Gets name list from the input arguments Searches through args in sequential order to find |lastn= and |firstn= parameters (or their aliases), and their matching link and mask parameters. Stops searching when both |lastn= and |firstn= are not found in args after two sequential attempts: found |last1=, |last2=, and |last3= but doesn't find |last4= and |last5= then the search is done. This function emits an error message when there is a |firstn= without a matching |lastn=. When there are 'holes' in the list of last names, |last1= and |last3= are present but |last2= is missing, an error message is emitted. |lastn= is not required to have a matching |firstn=. When an author or editor parameter contains some form of 'et al.', the 'et al.' is stripped from the parameter and a flag (etal) returned that will cause list_people() to add the static 'et al.' text from Module:Citation/CS1/Configuration. This keeps 'et al.' out of the template's metadata. When this occurs, an error is emitted. ]] local function extract_names(args, list_name) local names = {}; -- table of names local last; -- individual name components local first; local link; local mask; local i = 1; -- loop counter/indexer local n = 1; -- output table indexer local count = 0; -- used to count the number of times we haven't found a |last= (or alias for authors, |editor-last or alias for editors) local etal = false; -- return value set to true when we find some form of et al. in an author parameter local last_alias, first_alias, link_alias; -- selected parameter aliases used in error messaging while true do last, last_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'err_redundant_parameters', i ); -- search through args for name components beginning at 1 first, first_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'err_redundant_parameters', i ); link, link_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ); mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); if last then -- error check |lastn= alias for unknown interwiki link prefix; done here because this is where we have the parameter name local project, language = interwiki_prefixen_get (last, true); -- true because we expect interwiki links in |lastn= to be wikilinked if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', last_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? last = utilities.remove_wiki_link (last); -- remove wikilink markup; show display value only end end if link then -- error check |linkn= alias for unknown interwiki link prefix local project, language = interwiki_prefixen_get (link, false); -- false because wiki links in |author-linkn= is an error if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', link_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? link = nil; -- unset so we don't link link_alias = nil; end end last, etal = name_has_etal (last, etal, false, last_alias); -- find and remove variations on et al. first, etal = name_has_etal (first, etal, false, first_alias); -- find and remove variations on et al. last, first = name_checks (last, first, list_name, last_alias, first_alias); -- multiple names, extraneous annotation, etc. checks if first and not last then -- if there is a firstn without a matching lastn local alias = first_alias:find ('given', 1, true) and 'given' or 'first'; -- get first or given form of the alias utilities.set_message ('err_first_missing_last', { first_alias, -- param name of alias missing its mate first_alias:gsub (alias, {['first'] = 'last', ['given'] = 'surname'}), -- make param name appropriate to the alias form }); -- add this error message elseif not first and not last then -- if both firstn and lastn aren't found, are we done? count = count + 1; -- number of times we haven't found last and first if 2 <= count then -- two missing names and we give up break; -- normal exit or there is a two-name hole in the list; can't tell which end else -- we have last with or without a first local result; link = link_title_ok (link, link_alias, last, last_alias); -- check for improper wiki-markup if first then link = link_title_ok (link, link_alias, first, first_alias); -- check for improper wiki-markup end names[n] = {last = last, first = first, link = link, mask = mask, corporate = false}; -- add this name to our names list (corporate for |vauthors= only) n = n + 1; -- point to next location in the names table if 1 == count then -- if the previous name was missing utilities.set_message ('err_missing_name', {list_name:match ("(%w+)List"):lower(), i - 1}); -- add this error message end count = 0; -- reset the counter, we're looking for two consecutive missing names end i = i + 1; -- point to next args location end return names, etal; -- all done, return our list of names and the etal flag end --[[--------------------------< N A M E _ T A G _ G E T >------------------------------------------------------ attempt to decode |language=<lang_param> and return language name and matching tag; nil else. This function looks for: <lang_param> as a tag in cfg.lang_tag_remap{} <lang_param> as a name in cfg.lang_name_remap{} <lang_param> as a name in cfg.mw_languages_by_name_t <lang_param> as a tag in cfg.mw_languages_by_tag_t when those fail, presume that <lang_param> is an IETF-like tag that MediaWiki does not recognize. Strip all script, region, variant, whatever subtags from <lang_param> to leave just a two or three character language tag and look for the new <lang_param> in cfg.mw_languages_by_tag_t{} on success, returns name (in properly capitalized form) and matching tag (in lowercase); on failure returns nil ]] local function name_tag_get (lang_param) local lang_param_lc = mw.ustring.lower (lang_param); -- use lowercase as an index into the various tables local name; local tag; name = cfg.lang_tag_remap[lang_param_lc]; -- assume <lang_param_lc> is a tag; attempt to get remapped language name if name then -- when <name>, <lang_param> is a tag for a remapped language name if cfg.lang_name_remap[name:lower()][2] ~= lang_param_lc then utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added return name, cfg.lang_name_remap[name:lower()][2]; -- so return name and tag from lang_name_remap[name]; special case to xlate sr-ec and sr-el to sr-cyrl and sr-latn end return name, lang_param_lc; -- so return <name> from remap and <lang_param_lc> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- still assuming that <lang_param_lc> is a tag; strip script, region, variant subtags name = cfg.lang_tag_remap[tag]; -- attempt to get remapped language name with language subtag only if name then -- when <name>, <tag> is a tag for a remapped language name return name, tag; -- so return <name> from remap and <tag> end if cfg.lang_name_remap[lang_param_lc] then -- not a remapped tag, assume <lang_param_lc> is a name; attempt to get remapped language tag return cfg.lang_name_remap[lang_param_lc][1], cfg.lang_name_remap[lang_param_lc][2]; -- for this <lang_param_lc>, return a (possibly) new name and appropriate tag end name = cfg.mw_languages_by_tag_t[lang_param_lc]; -- assume that <lang_param_lc> is a tag; attempt to get its matching language name if name then return name, lang_param_lc; -- <lang_param_lc> is a tag so return it and <name> end tag = cfg.mw_languages_by_name_t[lang_param_lc]; -- assume that <lang_param_lc> is a language name; attempt to get its matching tag if tag then return cfg.mw_languages_by_tag_t[tag], tag; -- <lang_param_lc> is a name so return the name from the table and <tag> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- is <lang_param_lc> an IETF-like tag that MediaWiki doesn't recognize? <tag> gets the language subtag; nil else if tag then name = cfg.mw_languages_by_tag_t[tag]; -- attempt to get a language name using the shortened <tag> if name then return name, tag; -- <lang_param_lc> is an unrecognized IETF-like tag so return <name> and language subtag end end end --[[-------------------< L A N G U A G E _ P A R A M E T E R >------------------ Gets language name from a provided two- or three-character ISO 639 code. If a code is recognized by MediaWiki, use the returned name; if not, then use the value that was provided with the language parameter. When |language= contains a recognized language (either code or name), the page is assigned to the category for that code: Category:Norwegian-language sources (no). For valid three-character code languages, the page is assigned to the single category for '639-2' codes: Category:CS1 ISO 639-2 language sources. Languages that are the same as the local wiki are not categorized. MediaWiki does not recognize three-character equivalents of two-character codes: code 'ar' is recognized but code 'ara' is not. This function supports multiple languages in the form |language=nb, French, th where the language names or codes are separated from each other by commas with optional space characters. ]] local function language_parameter (lang) local tag; -- some form of IETF-like language tag; language subtag with optional region, sript, vatiant, etc subtags local lang_subtag; -- ve populates |language= with mostly unecessary region subtags the MediaWiki does not recognize; this is the base language subtag local name; -- the language name local language_list = {}; -- table of language names to be rendered local names_t = {}; -- table made from the value assigned to |language= local this_wiki_name = mw.language.fetchLanguageName (cfg.this_wiki_code, cfg.this_wiki_code); -- get this wiki's language name names_t = mw.text.split (lang, '%s*,%s*'); -- names should be a comma separated list for _, lang in ipairs (names_t) do -- reuse lang here because we don't yet know if lang is a language name or a language tag name, tag = name_tag_get (lang); -- attempt to get name/tag pair for <lang>; <name> has proper capitalization; <tag> is lowercase if utilities.is_set (tag) then lang_subtag = tag:gsub ('^(%a%a%a?)%-.*', '%1'); -- for categorization, strip any IETF-like tags from language tag if cfg.this_wiki_code ~= lang_subtag then -- when the language is not the same as this wiki's language if 2 == lang_subtag:len() then -- and is a two-character tag utilities.add_prop_cat ('foreign-lang-source', {name, tag}, lang_subtag); -- categorize it; tag appended to allow for multiple language categorization else -- or is a recognized language (but has a three-character tag) utilities.add_prop_cat ('foreign-lang-source-2', {lang_subtag}, lang_subtag); -- categorize it differently TODO: support multiple three-character tag categories per cs1|2 template? end elseif cfg.local_lang_cat_enable then -- when the language and this wiki's language are the same and categorization is enabled utilities.add_prop_cat ('local-lang-source', {name, lang_subtag}); -- categorize it end else name = lang; -- return whatever <lang> has so that we show something utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added end table.insert (language_list, name); name = ''; -- so we can reuse it end name = utilities.make_sep_list (#language_list, language_list); if (1 == #language_list) and (lang_subtag == cfg.this_wiki_code) then -- when only one language, find lang name in this wiki lang name; for |language=en-us, 'English' in 'American English' return ''; -- if one language and that language is this wiki's return an empty string (no annotation) end return (" " .. wrap_msg ('language', name)); -- otherwise wrap with '(in ...)' --[[ TODO: should only return blank or name rather than full list so we can clean up the bunched parenthetical elements Language, Type, Format ]] end --[[-----------------------< S E T _ C S _ S T Y L E >-------------------------- Gets the default CS style configuration for the given mode. Returns default separator and either postscript as passed in or the default. In CS1, the default postscript and separator are '.'. In CS2, the default postscript is the empty string and the default separator is ','. ]] local function set_cs_style (postscript, mode) if utilities.is_set(postscript) then -- emit a maintenance message if user postscript is the default cs1 postscript -- we catch the opposite case for cs2 in set_style if mode == 'cs1' and postscript == cfg.presentation['ps_' .. mode] then utilities.set_message ('maint_postscript'); end else postscript = cfg.presentation['ps_' .. mode]; end return cfg.presentation['sep_' .. mode], postscript; end --[[--------------------------< S E T _ S T Y L E >----------------------------- Sets the separator and postscript styles. Checks the |mode= first and the #invoke CitationClass second. Removes the postscript if postscript == none. ]] local function set_style (mode, postscript, cite_class) local sep; if 'cs2' == mode then sep, postscript = set_cs_style (postscript, 'cs2'); elseif 'cs1' == mode then sep, postscript = set_cs_style (postscript, 'cs1'); elseif 'citation' == cite_class then sep, postscript = set_cs_style (postscript, 'cs2'); else sep, postscript = set_cs_style (postscript, 'cs1'); end if cfg.keywords_xlate[postscript:lower()] == 'none' then -- emit a maintenance message if user postscript is the default cs2 postscript -- we catch the opposite case for cs1 in set_cs_style if 'cs2' == mode or ('cs1' ~= mode and 'citation' == cite_class) then -- {{citation |title=Title |mode=cs1 |postscript=none}} should not emit maint message utilities.set_message ('maint_postscript'); end postscript = ''; end return sep, postscript end --[=[-------------------------< I S _ P D F >----------------------------------- Determines if a URL has the file extension that is one of the PDF file extensions used by [[MediaWiki:Common.css]] when applying the PDF icon to external links. returns true if file extension is one of the recognized extensions, else false ]=] local function is_pdf (url) return url:match ('%.pdf$') or url:match ('%.PDF$') or url:match ('%.pdf[%?#]') or url:match ('%.PDF[%?#]') or url:match ('%.PDF&#035') or url:match ('%.pdf&#035'); end --[[--------------------------< S T Y L E _ F O R M A T >----------------------- Applies CSS style to |format=, |chapter-format=, etc. Also emits an error message if the format parameter does not have a matching URL parameter. If the format parameter is not set and the URL contains a file extension that is recognized as a PDF document by MediaWiki's commons.css, this code will set the format parameter to (PDF) with the appropriate styling. ]] local function style_format (format, url, fmt_param, url_param) if utilities.is_set (format) then format = utilities.wrap_style ('format', format); -- add leading space, parentheses, resize if not utilities.is_set (url) then utilities.set_message ('err_format_missing_url', {fmt_param, url_param}); -- add an error message end elseif is_pdf (url) then -- format is not set so if URL is a PDF file then format = utilities.wrap_style ('format', 'PDF'); -- set format to PDF else format = ''; -- empty string for concatenation end return format; end --[[---------------------< G E T _ D I S P L A Y _ N A M E S >------------------ Returns a number that defines the number of names displayed for author and editor name lists and a Boolean flag to indicate when et al. should be appended to the name list. When the value assigned to |display-xxxxors= is a number greater than or equal to zero, return the number and the previous state of the 'etal' flag (false by default but may have been set to true if the name list contains some variant of the text 'et al.'). When the value assigned to |display-xxxxors= is the keyword 'etal', return a number that is one greater than the number of authors in the list and set the 'etal' flag true. This will cause the list_people() to display all of the names in the name list followed by 'et al.' In all other cases, returns nil and the previous state of the 'etal' flag. inputs: max: A['DisplayAuthors'] or A['DisplayEditors'], etc; a number or some flavor of etal count: #a or #e list_name: 'authors' or 'editors' etal: author_etal or editor_etal This function sets an error message when |display-xxxxors= value greater than or equal to number of names but not when <max> comes from {{cs1 config}} global settings. When using global settings, <param> is set to the keyword 'cs1 config' which is used to supress the normal error. Error is suppressed because it is to be expected that some citations in an article will have the same or fewer names that the limit specified in {{cs1 config}}. ]] local function get_display_names (max, count, list_name, etal, param) if utilities.is_set (max) then if 'etal' == max:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings max = count + 1; -- number of authors + 1 so display all author name plus et al. etal = true; -- overrides value set by extract_names() elseif max:match ('^%d+$') then -- if is a string of numbers max = tonumber (max); -- make it a number if (max >= count) and ('cs1 config' ~= param) then -- error when local |display-xxxxors= value greater than or equal to number of names; not an error when using global setting utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; end else -- not a valid keyword or number utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; -- unset; as if |display-xxxxors= had not been set end end return max, etal; end --[[----------< E X T R A _ T E X T _ I N _ P A G E _ C H E C K >--------------- Adds error if |page=, |pages=, |quote-page=, |quote-pages= has what appears to be some form of p. or pp. abbreviation in the first characters of the parameter content. check page for extraneous p, p., pp, pp., pg, pg. at start of parameter value: good pattern: '^P[^%.P%l]' matches when page begins PX or P# but not Px where x and X are letters and # is a digit bad pattern: '^[Pp][PpGg]' matches when page begins pp, pP, Pp, PP, pg, pG, Pg, PG ]] local function extra_text_in_page_check (val, name) if not val:match (cfg.vol_iss_pg_patterns.good_ppattern) then for _, pattern in ipairs (cfg.vol_iss_pg_patterns.bad_ppatterns) do -- spin through the selected sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message ('err_extra_text_pages', name); -- add error message return; -- and done end end end end --[[--------------------------< E X T R A _ T E X T _ I N _ V O L _ I S S _ C H E C K >------------------------ Adds error if |volume= or |issue= has what appears to be some form of redundant 'type' indicator. Applies to both; this function looks for issue text in both |issue= and |volume= and looks for volume-like text in |voluem= and |issue=. For |volume=: 'V.', or 'Vol.' (with or without the dot) abbreviations or 'Volume' in the first characters of the parameter content (all case insensitive). 'V' and 'v' (without the dot) are presumed to be roman numerals so are allowed. For |issue=: 'No.', 'I.', 'Iss.' (with or without the dot) abbreviations, or 'Issue' in the first characters of the parameter content (all case insensitive); numero styling: 'n°' with degree sign U+00B0, and № precomposed numero sign U+2116. Single character values ('v', 'i', 'n') allowed when not followed by separator character ('.', ':', '=', or whitespace character) – param values are trimmed of whitespace by MediaWiki before delivered to the module. <val> is |volume= or |issue= parameter value <name> is |volume= or |issue= parameter name for error message <selector> is 'v' for |volume=, 'i' for |issue= sets error message on failure; returns nothing ]] local function extra_text_in_vol_iss_check (val, name, selector) if not utilities.is_set (val) then return; end local handler = 'v' == selector and 'err_extra_text_volume' or 'err_extra_text_issue'; local accept_val; val, accept_val = utilities.has_accept_as_written (val); --if accept_val then -- if uncomment this, |volume=((vol. 1)) suppresses error -- return; --end --val = mw.text.unstripNoWiki (val); -- if uncomment this, |volume=<nowiki>vol. 1</nowiki> shows error val = val:lower(); -- force parameter value to lower case for _, pattern in ipairs (cfg.vol_iss_pg_patterns.vi_patterns_t) do -- spin through the sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message (handler, name); -- add error message return; -- and done end end end --[=[-------------------------< G E T _ V _ N A M E _ T A B L E >---------------------------------------------- split apart a |vauthors= or |veditors= parameter. This function allows for corporate names, wrapped in doubled parentheses to also have commas; in the old version of the code, the doubled parentheses were included in the rendered citation and in the metadata. Individual author names may be wikilinked |vauthors=Jones AB, [[E. B. White|White EB]], ((Black, Brown, and Co.)) ]=] local function get_v_name_table (vparam, output_table, output_link_table) local _, accept = utilities.has_accept_as_written (vparam); if accept then utilities.add_prop_cat ('vanc-accept'); -- add properties category end local name_table = mw.text.split(vparam, "%s*,%s*"); -- names are separated by commas local wl_type, label, link; -- wl_type not used here; just a placeholder local i = 1; while name_table[i] do if name_table[i]:match ('^%(%(.*[^%)][^%)]$') then -- first segment of corporate with one or more commas; this segment has the opening doubled parentheses local name = name_table[i]; i = i + 1; -- bump indexer to next segment while name_table[i] do name = name .. ', ' .. name_table[i]; -- concatenate with previous segments if name_table[i]:match ('^.*%)%)$') then -- if this table member has the closing doubled parentheses break; -- and done reassembling so end i = i + 1; -- bump indexer end table.insert (output_table, name); -- and add corporate name to the output table table.insert (output_link_table, ''); -- no wikilink else wl_type, label, link = utilities.is_wikilink (name_table[i]); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] table.insert (output_table, label); -- add this name if 1 == wl_type then table.insert (output_link_table, label); -- simple wikilink [[D]] else table.insert (output_link_table, link); -- no wikilink or [[L|D]]; add this link if there is one, else empty string end end i = i + 1; end return output_table; end --[[--------------------------< P A R S E _ V A U T H O R S _ V E D I T O R S >-------------------------------- This function extracts author / editor names from |vauthors= or |veditors= and finds matching |xxxxor-maskn= and |xxxxor-linkn= in args. It then returns a table of assembled names just as extract_names() does. Author / editor names in |vauthors= or |veditors= must be in Vancouver system style. Corporate or institutional names may sometimes be required and because such names will often fail the is_good_vanc_name() and other format compliance tests, are wrapped in doubled parentheses ((corporate name)) to suppress the format tests. Supports generational suffixes Jr, 2nd, 3rd, 4th–6th. This function sets the Vancouver error when a required comma is missing and when there is a space between an author's initials. ]] local function parse_vauthors_veditors (args, vparam, list_name) local names = {}; -- table of names assembled from |vauthors=, |author-maskn=, |author-linkn= local v_name_table = {}; local v_link_table = {}; -- when name is wikilinked, targets go in this table local etal = false; -- return value set to true when we find some form of et al. vauthors parameter local last, first, link, mask, suffix; local corporate = false; vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period) v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); -- names are separated by commas for i, v_name in ipairs(v_name_table) do first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor local accept_name; v_name, accept_name = utilities.has_accept_as_written (v_name); -- remove accept-this-as-written markup when it wraps all of <v_name> if accept_name then last = v_name; corporate = true; -- flag used in list_people() elseif string.find(v_name, "%s") then if v_name:find('[;%.]') then -- look for commonly occurring punctuation characters; add_vanc_error (cfg.err_msg_supl.punctuation, i); end local lastfirstTable = {} lastfirstTable = mw.text.split(v_name, "%s+") first = table.remove(lastfirstTable); -- removes and returns value of last element in table which should be initials or generational suffix if not mw.ustring.match (first, '^%u+$') then -- mw.ustring here so that later we will catch non-Latin characters suffix = first; -- not initials so assume that whatever we got is a generational suffix first = table.remove(lastfirstTable); -- get what should be the initials from the table end last = table.concat(lastfirstTable, ' ') -- returns a string that is the concatenation of all other names that are not initials and generational suffix if not utilities.is_set (last) then first = ''; -- unset last = v_name; -- last empty because something wrong with first add_vanc_error (cfg.err_msg_supl.name, i); end if mw.ustring.match (last, '%a+%s+%u+%s+%a+') then add_vanc_error (cfg.err_msg_supl['missing comma'], i); -- matches last II last; the case when a comma is missing end if mw.ustring.match (v_name, ' %u %u$') then -- this test is in the wrong place TODO: move or replace with a more appropriate test add_vanc_error (cfg.err_msg_supl.initials, i); -- matches a space between two initials end else last = v_name; -- last name or single corporate name? Doesn't support multiword corporate names? do we need this? end if utilities.is_set (first) then if not mw.ustring.match (first, "^%u?%u$") then -- first shall contain one or two upper-case letters, nothing else add_vanc_error (cfg.err_msg_supl.initials, i); -- too many initials; mixed case initials (which may be ok Romanization); hyphenated initials end is_good_vanc_name (last, first, suffix, i); -- check first and last before restoring the suffix which may have a non-Latin digit if utilities.is_set (suffix) then first = first .. ' ' .. suffix; -- if there was a suffix concatenate with the initials suffix = ''; -- unset so we don't add this suffix to all subsequent names end else if not corporate then is_good_vanc_name (last, '', nil, i); end end link = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ) or v_link_table[i]; mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); names[i] = {last = last, first = first, link = link, mask = mask, corporate = corporate}; -- add this assembled name to our names list end return names, etal; -- all done, return our list of names end --[[--------------------------< S E L E C T _ A U T H O R _ E D I T O R _ S O U R C E >------------------------ Select one of |authors=, |authorn= / |lastn / firstn=, or |vauthors= as the source of the author name list or select one of |editorn= / editor-lastn= / |editor-firstn= or |veditors= as the source of the editor name list. Only one of these appropriate three will be used. The hierarchy is: |authorn= (and aliases) highest and |authors= lowest; |editorn= (and aliases) highest and |veditors= lowest (support for |editors= withdrawn) When looking for |authorn= / |editorn= parameters, test |xxxxor1= and |xxxxor2= (and all of their aliases); stops after the second test which mimicks the test used in extract_names() when looking for a hole in the author name list. There may be a better way to do this, I just haven't discovered what that way is. Emits an error message when more than one xxxxor name source is provided. In this function, vxxxxors = vauthors or veditors; xxxxors = authors as appropriate. ]] local function select_author_editor_source (vxxxxors, xxxxors, args, list_name) local lastfirst = false; if utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 1 ) or -- do this twice in case we have a |first1= without a |last1=; this ... utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 1 ) or -- ... also catches the case where |first= is used with |vauthors= utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 2 ) or utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 2 ) then lastfirst = true; end if (utilities.is_set (vxxxxors) and true == lastfirst) or -- these are the three error conditions (utilities.is_set (vxxxxors) and utilities.is_set (xxxxors)) or (true == lastfirst and utilities.is_set (xxxxors)) then utilities.set_message ('err_redundant_parameters', utilities.substitute (cfg.special_case_translation.name_list_params, ('AuthorList' == list_name) and cfg.special_case_translation.author or cfg.special_case_translation.editor)); -- add error message end if true == lastfirst then return 1 end; -- return a number indicating which author name source to use if utilities.is_set (vxxxxors) then return 2 end; if utilities.is_set (xxxxors) then return 3 end; return 1; -- no authors so return 1; this allows missing author name test to run in case there is a first without last end --[[--------------------------< I S _ V A L I D _ P A R A M E T E R _ V A L U E >------------------------------ This function is used to validate a parameter's assigned value for those parameters that have only a limited number of allowable values (yes, y, true, live, dead, etc.). When the parameter value has not been assigned a value (missing or empty in the source template) the function returns the value specified by ret_val. If the parameter value is one of the list of allowed values returns the translated value; else, emits an error message and returns the value specified by ret_val. TODO: explain <invert> ]] local function is_valid_parameter_value (value, name, possible, ret_val, invert) if not utilities.is_set (value) then return ret_val; -- an empty parameter is ok end if (not invert and utilities.in_array (value, possible)) then -- normal; <value> is in <possible> table return cfg.keywords_xlate[value]; -- return translation of parameter keyword elseif invert and not utilities.in_array (value, possible) then -- invert; <value> is not in <possible> table return value; -- return <value> as it is else utilities.set_message ('err_invalid_param_val', {name, value}); -- not an allowed value so add error message return ret_val; end end --[[--------------------------< T E R M I N A T E _ N A M E _ L I S T >---------------------------------------- This function terminates a name list (author, contributor, editor) with a separator character (sepc) and a space when the last character is not a sepc character or when the last three characters are not sepc followed by two closing square brackets (close of a wikilink). When either of these is true, the name_list is terminated with a single space character. ]] local function terminate_name_list (name_list, sepc) if (string.sub (name_list, -3, -1) == sepc .. '. ') then -- if already properly terminated return name_list; -- just return the name list elseif (string.sub (name_list, -1, -1) == sepc) or (string.sub (name_list, -3, -1) == sepc .. ']]') then -- if last name in list ends with sepc char return name_list .. " "; -- don't add another else return name_list .. sepc .. ' '; -- otherwise terminate the name list end end --[[-------------------------< F O R M A T _ V O L U M E _ I S S U E >----------------------------------------- returns the concatenation of the formatted volume and issue (or journal article number) parameters as a single string; or formatted volume or formatted issue, or an empty string if neither are set. ]] local function format_volume_issue (volume, issue, article, cite_class, origin, sepc, lower) if not utilities.is_set (volume) and not utilities.is_set (issue) and not utilities.is_set (article) then return ''; end -- same condition as in format_pages_sheets() local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); local is_numeric_vol = volume and (volume:match ('^[MDCLXVI]+$') or volume:match ('^%d+$')); -- is only uppercase roman numerals or only digits? local is_long_vol = volume and (4 < mw.ustring.len(volume)); -- is |volume= value longer than 4 characters? if volume and (not is_numeric_vol and is_long_vol) then -- when not all digits or Roman numerals, is |volume= longer than 4 characters? utilities.add_prop_cat ('long-vol'); -- yes, add properties cat end if is_journal then -- journal-style formatting local vol = ''; if utilities.is_set (volume) then if is_numeric_vol then -- |volume= value all digits or all uppercase Roman numerals? vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, volume}); -- render in bold face elseif is_long_vol then -- not all digits or Roman numerals; longer than 4 characters? vol = utilities.substitute (cfg.messages['j-vol'], {sepc, utilities.hyphen_to_dash (volume)}); -- not bold else -- four or fewer characters vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, utilities.hyphen_to_dash (volume)}); -- bold end end vol = vol .. (utilities.is_set (issue) and utilities.substitute (cfg.messages['j-issue'], issue) or '') vol = vol .. (utilities.is_set (article) and utilities.substitute (cfg.messages['j-article-num'], article) or '') return vol; end if 'podcast' == cite_class and utilities.is_set (issue) then return wrap_msg ('issue', {sepc, issue}, lower); end if 'conference' == cite_class and utilities.is_set (article) then -- |article-number= supported only in journal and conference cites if utilities.is_set (volume) and utilities.is_set (article) then -- both volume and article number return wrap_msg ('vol-art', {sepc, utilities.hyphen_to_dash (volume), article}, lower); elseif utilities.is_set (article) then -- article number alone; when volume alone, handled below return wrap_msg ('art', {sepc, article}, lower); end end -- all other types of citation if utilities.is_set (volume) and utilities.is_set (issue) then return wrap_msg ('vol-no', {sepc, utilities.hyphen_to_dash (volume), issue}, lower); elseif utilities.is_set (volume) then return wrap_msg ('vol', {sepc, utilities.hyphen_to_dash (volume)}, lower); else return wrap_msg ('issue', {sepc, issue}, lower); end end --[[-------------------------< F O R M A T _ P A G E S _ S H E E T S >----------------------------------------- adds static text to one of |page(s)= or |sheet(s)= values and returns it with all of the others set to empty strings. The return order is: page, pages, sheet, sheets Singular has priority over plural when both are provided. ]] local function format_pages_sheets (page, pages, sheet, sheets, cite_class, origin, sepc, nopp, lower) if 'map' == cite_class then -- only cite map supports sheet(s) as in-source locators if utilities.is_set (sheet) then if 'journal' == origin then return '', '', wrap_msg ('j-sheet', sheet, lower), ''; else return '', '', wrap_msg ('sheet', {sepc, sheet}, lower), ''; end elseif utilities.is_set (sheets) then if 'journal' == origin then return '', '', '', wrap_msg ('j-sheets', sheets, lower); else return '', '', '', wrap_msg ('sheets', {sepc, sheets}, lower); end end end local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); if utilities.is_set (page) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], page), '', '', ''; elseif not nopp then return utilities.substitute (cfg.messages['p-prefix'], {sepc, page}), '', '', ''; else return utilities.substitute (cfg.messages['nopp'], {sepc, page}), '', '', ''; end elseif utilities.is_set (pages) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], pages), '', '', ''; elseif tonumber(pages) ~= nil and not nopp then -- if pages is only digits, assume a single page number return '', utilities.substitute (cfg.messages['p-prefix'], {sepc, pages}), '', ''; elseif not nopp then return '', utilities.substitute (cfg.messages['pp-prefix'], {sepc, pages}), '', ''; else return '', utilities.substitute (cfg.messages['nopp'], {sepc, pages}), '', ''; end end return '', '', '', ''; -- return empty strings end --[[--------------------------< I N S O U R C E _ L O C _ G E T >---------------------------------------------- returns one of the in-source locators: page, pages, or at. If any of these are interwiki links to Wikisource, returns the label portion of the interwiki-link as plain text for use in COinS. This COinS thing is done because here we convert an interwiki-link to an external link and add an icon span around that; get_coins_pages() doesn't know about the span. TODO: should it? TODO: add support for sheet and sheets?; streamline; TODO: make it so that this function returns only one of the three as the single in-source (the return value assigned to a new name)? ]] local function insource_loc_get (page, page_orig, pages, pages_orig, at) local ws_url, ws_label, coins_pages, L; -- for Wikisource interwiki-links; TODO: this corrupts page metadata (span remains in place after cleanup; fix there?) if utilities.is_set (page) then if utilities.is_set (pages) or utilities.is_set (at) then pages = ''; -- unset the others at = ''; end extra_text_in_page_check (page, page_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (page); -- make ws URL from |page= interwiki link; link portion L becomes tooltip label if ws_url then page = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in page'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? page = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, page}); coins_pages = ws_label; end elseif utilities.is_set (pages) then if utilities.is_set (at) then at = ''; -- unset end extra_text_in_page_check (pages, pages_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (pages); -- make ws URL from |pages= interwiki link; link portion L becomes tooltip label if ws_url then pages = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in pages'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? pages = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, pages}); coins_pages = ws_label; end elseif utilities.is_set (at) then ws_url, ws_label, L = wikisource_url_make (at); -- make ws URL from |at= interwiki link; link portion L becomes tooltip label if ws_url then at = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in at'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? at = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, at}); coins_pages = ws_label; end end return page, pages, at, coins_pages; end --[[--------------------------< I S _ U N I Q U E _ A R C H I V E _ U R L >------------------------------------ add error message when |archive-url= value is same as |url= or chapter-url= (or alias...) value ]] local function is_unique_archive_url (archive, url, c_url, source, date) if utilities.is_set (archive) then if archive == url or archive == c_url then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); -- add error message return '', ''; -- unset |archive-url= and |archive-date= because same as |url= or |chapter-url= end end return archive, date; end --[=[-------------------------< A R C H I V E _ U R L _ C H E C K >-------------------------------------------- Check archive.org URLs to make sure they at least look like they are pointing at valid archives and not to the save snapshot URL or to calendar pages. When the archive URL is 'https://web.archive.org/save/' (or http://...) archive.org saves a snapshot of the target page in the URL. That is something that Wikipedia should not allow unwitting readers to do. When the archive.org URL does not have a complete timestamp, archive.org chooses a snapshot according to its own algorithm or provides a calendar 'search' result. [[WP:ELNO]] discourages links to search results. This function looks at the value assigned to |archive-url= and returns empty strings for |archive-url= and |archive-date= and an error message when: |archive-url= holds an archive.org save command URL |archive-url= is an archive.org URL that does not have a complete timestamp (YYYYMMDDhhmmss 14 digits) in the correct place otherwise returns |archive-url= and |archive-date= There are two mostly compatible archive.org URLs: //web.archive.org/<timestamp>... -- the old form //web.archive.org/web/<timestamp>... -- the new form The old form does not support or map to the new form when it contains a display flag. There are four identified flags ('id_', 'js_', 'cs_', 'im_') but since archive.org ignores others following the same form (two letters and an underscore) we don't check for these specific flags but we do check the form. This function supports a preview mode. When the article is rendered in preview mode, this function may return a modified archive URL: for save command errors, return undated wildcard (/*/) for timestamp errors when the timestamp has a wildcard, return the URL unmodified for timestamp errors when the timestamp does not have a wildcard, return with timestamp limited to six digits plus wildcard (/yyyymm*/) A secondary function is to return an archive-url timestamp from those archive urls that have them. The timestamp is used by validation.archive_date_check() to see if the value in |archive-date= matches the timestamp in the archive url. ]=] local function archive_url_check (url, date) local err_msg = ''; -- start with the error message empty local path, timestamp, flag; -- portions of the archive.org URL local function is_ts_date_valid (timestamp, origin_date) -- local function to validate archive url taimestamp date; time ignored local y, m, d = timestamp:match ('(%d%d%d%d)(%d%d)(%d%d)'); -- split into parts if y and validation.is_valid_date (y, m, d) and (tonumber (y) >= 1996) then return true, tonumber (y) >= origin_date; -- <origin_date> is 1996 for archive.org end end if (not url:match('//web%.archive%.org/')) and (not url:match('//liveweb%.archive%.org/')) then -- also deprecated liveweb Wayback machine URL return url, date; -- not an archive.org archive, return ArchiveURL and ArchiveDate end if url:match('//web%.archive%.org/save/') then -- if a save command URL, we don't want to allow saving of the target page err_msg = cfg.err_msg_supl.save; url = url:gsub ('(//web%.archive%.org)/save/', '%1/*/', 1); -- for preview mode: modify ArchiveURL elseif url:match('//liveweb%.archive%.org/') then err_msg = cfg.err_msg_supl.liveweb; else path, timestamp, flag = url:match('//web%.archive%.org/([^%d]*)(%d+)([^/]*)/'); -- split out some of the URL parts for evaluation if not path then -- malformed in some way; pattern did not match err_msg = cfg.err_msg_supl.timestamp; elseif 14 ~= timestamp:len() then -- path and flag optional, must have 14-digit timestamp here err_msg = cfg.err_msg_supl.timestamp; if '*' ~= flag then local replacement = timestamp:match ('^%d%d%d%d%d%d') or timestamp:match ('^%d%d%d%d'); -- get the first 6 (YYYYMM) or first 4 digits (YYYY) if replacement then -- nil if there aren't at least 4 digits (year) replacement = replacement .. string.rep ('0', 14 - replacement:len()); -- year or yearmo (4 or 6 digits) zero-fill to make 14-digit timestamp url=url:gsub ('(//web%.archive%.org/[^%d]*)%d[^/]*', '%1' .. replacement .. '*', 1) -- for preview, modify ts to 14 digits plus splat for calendar display end end elseif not is_ts_date_valid (timestamp, 1996) then -- is ymd portion of timestamp a valid date? err_msg = cfg.err_msg_supl.timestamp; timestamp = nil; -- unset because invalid elseif utilities.is_set (path) and 'web/' ~= path then -- older archive URLs do not have the extra 'web/' path element err_msg = cfg.err_msg_supl.path; elseif utilities.is_set (flag) and not utilities.is_set (path) then -- flag not allowed with the old form URL (without the 'web/' path element) err_msg = cfg.err_msg_supl.flag; elseif utilities.is_set (flag) and not flag:match ('%a%a_') then -- flag if present must be two alpha characters and underscore (requires 'web/' path element) err_msg = cfg.err_msg_supl.flag; else return url, date, timestamp; -- return ArchiveURL, ArchiveDate, and timestamp from |archive-url= end end -- if here, something not right so utilities.set_message ('err_archive_url', {err_msg}); -- add error message and if is_preview_mode then return url, date, timestamp; -- preview mode so return ArchiveURL, ArchiveDate, and timestamp from |archive-url= else return '', ''; -- return empty strings for ArchiveURL and ArchiveDate end end --[[--------------------------< P L A C E _ C H E C K >-------------------------------------------------------- check |place=, |publication-place=, |location= to see if these params include digits. This function added because many editors misuse location to specify the in-source location (|page(s)= and |at= are supposed to do that) returns the original parameter value without modification; added maint cat when parameter value contains digits ]] local function place_check (param_val) if not utilities.is_set (param_val) then -- parameter empty or omitted return param_val; -- return that empty state end if mw.ustring.find (param_val, '%d') then -- not empty, are there digits in the parameter value utilities.set_message ('maint_location'); -- yep, add maint cat end return param_val; -- and done end --[[--------------------------< I S _ A R C H I V E D _ C O P Y >---------------------------------------------- compares |title= to 'Archived copy' (placeholder added by bots that can't find proper title); if matches, return true; nil else ]] local function is_archived_copy (title) title = mw.ustring.lower(title); -- switch title to lower case if title:find (cfg.special_case_translation.archived_copy.en) then -- if title is 'Archived copy' return true; elseif cfg.special_case_translation.archived_copy['local'] then if mw.ustring.find (title, cfg.special_case_translation.archived_copy['local']) then -- mw.ustring() because might not be Latin script return true; end end end --[[--------------------------< D I S P L A Y _ N A M E S _ S E L E C T >-------------------------------------- for any of the |display-authors=, |display-editors=, etc parameters, select either the local or global setting. When both are present, look at <local_display_names> value. When the value is some sort of 'et al.'string, special handling is required. When {{cs1 config}} has |display-<namelist>= AND this template has |display-<namelist>=etal AND: the number of names specified by <number_of_names> is: greater than the number specified in the global |display-<namelist>= parameter (<global_display_names>) use global |display-<namelist>= parameter value set overridden maint category less than or equal to the number specified in the global |display-<namelist>= parameter use local |display-<namelist>= parameter value The purpose of this function is to prevent categorizing a template that has fewer names than the global setting to keep the etal annotation specified by <local_display_names>. ]] local function display_names_select (global_display_names, local_display_names, param_name, number_of_names, test) if global_display_names and utilities.is_set (local_display_names) then -- when both if 'etal' == local_display_names:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings number_of_names = tonumber (number_of_names); -- convert these to numbers for comparison local global_display_names_num = tonumber (global_display_names); -- <global_display_names> not set when parameter value is not digits if number_of_names > global_display_names_num then -- template has more names than global config allows to be displayed? utilities.set_message ('maint_overridden_setting'); -- set a maint message because global is overriding local |display-<namelist>=etal return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local because fewer names so let <local_display_names> control end end -- here when <global_display_names> and <local_display_names> both numbers; <global_display_names> controls utilities.set_message ('maint_overridden_setting'); -- set a maint message return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) end -- here when only one of <global_display_names> or <local_display_names> set if global_display_names then return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local end end --[[--------------------------< M O D E _ S E T >-------------------------------------------------------------- fetch global mode setting from {{cs1 config}} (if present) or from |mode= (if present); global setting overrides local |mode= parameter value. When both are present, emit maintenance message ]] local function mode_set (Mode, Mode_origin) local mode; if cfg.global_cs1_config_t['Mode'] then -- global setting in {{cs1 config}}; nil when empty or assigned value invalid mode = is_valid_parameter_value (cfg.global_cs1_config_t['Mode'], 'cs1 config: mode', cfg.keywords_lists['mode'], ''); -- error messaging 'param' here is a hoax else mode = is_valid_parameter_value (Mode, Mode_origin, cfg.keywords_lists['mode'], ''); end if cfg.global_cs1_config_t['Mode'] and utilities.is_set (Mode) then -- when template has |mode=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end return mode; end --[[--------------------------< Q U O T E _ M A K E >---------------------------------------------------------- create quotation from |quote=, |trans-quote=, and/or script-quote= with or without |quote-page= or |quote-pages= when any of those three quote parameters are set, this function unsets <PostScript>. When none of those parameters are set, |quote-page= and |quote-pages= are unset to nil so that they are not included in the template's metadata ]] local function quote_make (quote, trans_quote, script_quote, quote_page, quote_pages, nopp, sepc, postscript) if utilities.is_set (quote) or utilities.is_set (trans_quote) or utilities.is_set (script_quote) then if utilities.is_set (quote) then if quote:sub(1, 1) == '"' and quote:sub(-1, -1) == '"' then -- if first and last characters of quote are quote marks quote = quote:sub(2, -2); -- strip them off end end quote = kern_quotes (quote); -- kern if needed quote = utilities.wrap_style ('quoted-text', quote ); -- wrap in <q>...</q> tags if utilities.is_set (script_quote) then quote = script_concatenate (quote, script_quote, 'script-quote'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after quote is wrapped end if utilities.is_set (trans_quote) then if trans_quote:sub(1, 1) == '"' and trans_quote:sub(-1, -1) == '"' then -- if first and last characters of |trans-quote are quote marks trans_quote = trans_quote:sub(2, -2); -- strip them off end quote = quote .. " " .. utilities.wrap_style ('trans-quoted-title', trans_quote ); end if utilities.is_set (quote_page) or utilities.is_set (quote_pages) then -- add page prefix local quote_prefix = ''; if utilities.is_set (quote_page) then extra_text_in_page_check (quote_page, 'quote-page'); -- add to maint cat if |quote-page= value begins with what looks like p., pp., etc. if not nopp then quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_page}), '', '', ''; else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_page}), '', '', ''; end elseif utilities.is_set (quote_pages) then extra_text_in_page_check (quote_pages, 'quote-pages'); -- add to maint cat if |quote-pages= value begins with what looks like p., pp., etc. if tonumber(quote_pages) ~= nil and not nopp then -- if only digits, assume single page quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_pages}), '', ''; elseif not nopp then quote_prefix = utilities.substitute (cfg.messages['pp-prefix'], {sepc, quote_pages}), '', ''; else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_pages}), '', ''; end end quote = quote_prefix .. ": " .. quote; else quote = sepc .. " " .. quote; end postscript = ""; -- cs1|2 does not supply terminal punctuation when |quote= is set elseif utilities.is_set (quote_page) or utilities.is_set (quote_pages) then quote_page = nil; -- unset; these require |quote=; TODO: error message? quote_pages = nil; end return quote, quote_page, quote_pages, postscript; end --[[--------------------------< C H E C K _ P U B L I S H E R _ N A M E >-------------------------------------- look for variations of '<text>: <text>' that might be '<location>: <publisher>' in |publisher= parameter value. when found, emit a maintenance message; return nil else <publisher> is the value assigned to |publisher= or |institution= ]] local function check_publisher_name (publisher) local patterns_t = { '^[%w%s]+%s*:%s*[%w%s]+$', -- plain text <location>: <publisher> '^%[+[%w%s:|]+%]+%s*:%s*[%w%s]+$', -- partially wikilinked [[<location>]]: <publisher> '^[%w%s]+%s*:%s*%[+[%w%s:|]+%]+$', -- partially wikilinked <location>: [[<publisher>]] '^%[+[%w%s:|]+%]+%s*:%s*%[+[%w%s:|]+%]+$', -- wikilinked [[<location>]]: [[<publisher>]] } for _, pattern in ipairs (patterns_t) do -- spin through the patterns_t sequence if mw.ustring.match (publisher, pattern) then -- does this pattern match? utilities.set_message ('maint_publisher_location'); -- set a maint message return; -- and done end end end --[[--------------------------< I S _ P A G E _ A R T _ N U M >------------------------------------------------ compare the trailing (rightmost) characters of the |doi= value against the whole value assigned to |page(s)=. return boolean true when: |page(s)= has exactly 8 digits and a dot between the fourth and fifth digits matches the trailing 9 characters of the |doi= value: |page=12345678 → |page=1234.5678 matches |doi=10.xxxx/yyyy1234.5678 |page(s)= is 5 or more characters and matches |doi= values's trailing characters |page(s)= begins with a lowercase 'e' and |page(s)= without the 'e' matches |doi= values's trailing characters: |page=e12345 → |page=12345 matches |doi=10.xxxx/yyyy12345 |page(s)= begins with a uppercase 'CD' followed by (typically) six digits matches |doi= values that ends with 'CDxxxxxx.pubx' (where 'x' is any single digit) return nil when |page(s)= values: are ranges separated by underscore, hyphen, emdash, endash, figure dash, or minus character are comma- or semicolon-separated lists of pages have external urls (has text 'http') are digit-only values less than 10000 do not match |doi= values's trailing characters ]] local function is_page_art_num (page, doi) if not (utilities.is_set (page) and utilities.is_set (doi)) then -- both required return; -- abandon; nothing to do end if page:match ('[,;_−–—‒%-]') then -- when |page(s)= might be a page range or a separated list of pages return; -- abandon end page = page:lower(); -- because doi names are case insensitive doi = doi:lower(); -- force these to lowercase for testing if page:match ('http') then -- when |page(s)= appears to hold a url return; -- abandon end if tonumber (page) then -- is |page(s)= digits only if 10000 > tonumber (page) then -- when |page(s)= less than 10000 return; -- abandon end if doi:match (page .. '$') then -- digits only page number match the last digits in |doi=? return true; end if 8 == page:len() then -- special case when |page(s)= is exactly 8 digits local dot_page = page:gsub ('(%d%d%d%d)(%d%d%d%d)', '%1.%2'); -- make a |page=xxxx.yyyy version commonly used in |doi= if doi:match (dot_page .. '$') then -- 8-digit dotted page number match the last characters in |doi=? return true; end end else -- here when |page(s)= is alpha-numeric if 4 < page:len() then -- when |page(s)= is five or more characters if doi:match (page .. '$') then -- alpha-numeric page match the last characters in |doi=? return true; end local epage = page:match ('^e([%w]+)$'); -- if first character of |page= is 'e', remove it if epage and doi:match (epage .. '$') then -- page number match the last characters in |doi=? return true; end local cdpage = page:match ('^cd%d+$'); -- if first characters of |page= are 'CD' and last characters are digits (typically 6 digits) if cdpage and doi:match (cdpage .. '%.pub%d$') then -- page number matches doi 'CDxxxxxx.pubx' where 'x' is a digit return true; end end end end --[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------ This is the main function doing the majority of the citation formatting. ]] local function citation0( config, args ) --[[ Load Input Parameters The argument_wrapper facilitates the mapping of multiple aliases to single internal variable. ]] local A = argument_wrapper ( args ); local i -- Pick out the relevant fields from the arguments. Different citation templates -- define different field names for the same underlying things. local author_etal; local a = {}; -- authors list from |lastn= / |firstn= pairs or |vauthors= local Authors; local NameListStyle; if cfg.global_cs1_config_t['NameListStyle'] then -- global setting in {{cs1 config}} overrides local |name-list-style= parameter value; nil when empty or assigned value invalid NameListStyle = is_valid_parameter_value (cfg.global_cs1_config_t['NameListStyle'], 'cs1 config: name-list-style', cfg.keywords_lists['name-list-style'], ''); -- error messaging 'param' here is a hoax else NameListStyle = is_valid_parameter_value (A['NameListStyle'], A:ORIGIN('NameListStyle'), cfg.keywords_lists['name-list-style'], ''); end if cfg.global_cs1_config_t['NameListStyle'] and utilities.is_set (A['NameListStyle']) then -- when template has |name-list-style=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end local Collaboration = A['Collaboration']; do -- to limit scope of selected local selected = select_author_editor_source (A['Vauthors'], A['Authors'], args, 'AuthorList'); if 1 == selected then a, author_etal = extract_names (args, 'AuthorList'); -- fetch author list from |authorn= / |lastn= / |firstn=, |author-linkn=, and |author-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be a, author_etal = parse_vauthors_veditors (args, A['Vauthors'], 'AuthorList'); -- fetch author list from |vauthors=, |author-linkn=, and |author-maskn= elseif 3 == selected then Authors = A['Authors']; -- use content of |people= or |credits=; |authors= is deprecated; TODO: constrain |people= and |credits= to cite av media, episode, serial? end if utilities.is_set (Collaboration) then author_etal = true; -- so that |display-authors=etal not required end end local editor_etal; local e = {}; -- editors list from |editor-lastn= / |editor-firstn= pairs or |veditors= do -- to limit scope of selected local selected = select_author_editor_source (A['Veditors'], nil, args, 'EditorList'); -- support for |editors= withdrawn if 1 == selected then e, editor_etal = extract_names (args, 'EditorList'); -- fetch editor list from |editorn= / |editor-lastn= / |editor-firstn=, |editor-linkn=, and |editor-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be e, editor_etal = parse_vauthors_veditors (args, args.veditors, 'EditorList'); -- fetch editor list from |veditors=, |editor-linkn=, and |editor-maskn= end end local Chapter = A['Chapter']; -- done here so that we have access to |contribution= from |chapter= and |script-chapter= aliases local Chapter_origin = A:ORIGIN ('Chapter'); local ScriptChapter = A['ScriptChapter']; local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); local Contribution; -- because contribution is required for contributor(s) if 'contribution' == Chapter_origin then -- is there a |contribution= parameter? Contribution = Chapter; -- get the name of the contribution elseif 'script-contribution' == ScriptChapter_origin then -- no, so is there a |script-contribution= parameter? Contribution = ScriptChapter; -- get the name of the contribution end local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (A['Periodical']) then -- |contributor= and |contribution= only supported in book cites c = extract_names (args, 'ContributorList'); -- fetch contributor list from |contributorn= / |contributor-lastn=, -firstn=, -linkn=, -maskn= if 0 < #c then if not utilities.is_set (Contribution) then -- |contributor= requires |contribution= utilities.set_message ('err_contributor_missing_required_param', 'contribution'); -- add missing contribution error message c = {}; -- blank the contributors' table; it is used as a flag later end if 0 == #a then -- |contributor= requires |author= utilities.set_message ('err_contributor_missing_required_param', 'author'); -- add missing author error message c = {}; -- blank the contributors' table; it is used as a flag later end end else -- if not a book cite if utilities.select_one (args, cfg.aliases['ContributorList-Last'], 'err_redundant_parameters', 1 ) then -- are there contributor name list parameters? utilities.set_message ('err_contributor_ignored'); -- add contributor ignored error message end Contribution = nil; -- unset end local Title = A['Title']; local TitleLink = A['TitleLink']; local auto_select = ''; -- default is auto local accept_link; TitleLink, accept_link = utilities.has_accept_as_written (TitleLink, true); -- test for accept-this-as-written markup if (not accept_link) and utilities.in_array (TitleLink, {'none', 'pmc', 'doi'}) then -- check for special keywords auto_select = TitleLink; -- remember selection for later TitleLink = ''; -- treat as if |title-link= would have been empty end TitleLink = link_title_ok (TitleLink, A:ORIGIN ('TitleLink'), Title, 'title'); -- check for wiki-markup in |title-link= or wiki-markup in |title= when |title-link= is set local Section = ''; -- {{cite map}} only; preset to empty string for concatenation if not used if 'map' == config.CitationClass and 'section' == Chapter_origin then Section = A['Chapter']; -- get |section= from |chapter= alias list; |chapter= and the other aliases not supported in {{cite map}} Chapter = ''; -- unset for now; will be reset later from |map= if present end local Periodical = A['Periodical']; local Periodical_origin = A:ORIGIN('Periodical'); local ScriptPeriodical = A['ScriptPeriodical']; local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical'); local TransPeriodical = A['TransPeriodical']; local TransPeriodical_origin = A:ORIGIN ('TransPeriodical'); if (utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical))) then local param; if utilities.is_set (Periodical) then -- get a parameter name from one of these periodical related meta-parameters Periodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = Periodical_origin -- get parameter name for error messaging elseif utilities.is_set (TransPeriodical) then TransPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = TransPeriodical_origin; -- get parameter name for error messaging elseif utilities.is_set (ScriptPeriodical) then ScriptPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = ScriptPeriodical_origin; -- get parameter name for error messaging end if utilities.is_set (param) then -- if we found one utilities.set_message ('err_periodical_ignored', {param}); -- emit an error message end end if utilities.is_set (Periodical) then local i; Periodical, i = utilities.strip_apostrophe_markup (Periodical); -- strip apostrophe markup so that metadata isn't contaminated if i then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {Periodical_origin}); end end if 'mailinglist' == config.CitationClass then -- special case for {{cite mailing list}} if utilities.is_set (Periodical) and utilities.is_set (A ['MailingList']) then -- both set emit an error TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', Periodical_origin) .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'mailinglist')}); end Periodical = A ['MailingList']; -- error or no, set Periodical to |mailinglist= value because this template is {{cite mailing list}} Periodical_origin = A:ORIGIN('MailingList'); end -- web and news not tested for now because of -- Wikipedia:Administrators%27_noticeboard#Is_there_a_semi-automated_tool_that_could_fix_these_annoying_"Cite_Web"_errors? if not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) then -- 'periodical' templates require periodical parameter -- local p = {['journal'] = 'journal', ['magazine'] = 'magazine', ['news'] = 'newspaper', ['web'] = 'website'}; -- for error message local p = {['journal'] = 'journal', ['magazine'] = 'magazine'}; -- for error message if p[config.CitationClass] then utilities.set_message ('err_missing_periodical', {config.CitationClass, p[config.CitationClass]}); end end local Volume; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) then if not utilities.in_array (Periodical_origin, cfg.citation_no_volume_t) then -- {{citation}} does not render |volume= when these parameters are used Volume = A['Volume']; -- but does for all other 'periodicals' end elseif utilities.is_set (ScriptPeriodical) then if 'script-website' ~= ScriptPeriodical_origin then -- {{citation}} does not render volume for |script-website= Volume = A['Volume']; -- but does for all other 'periodicals' end else Volume = A['Volume']; -- and does for non-'periodical' cites end elseif utilities.in_array (config.CitationClass, cfg.templates_using_volume) then -- render |volume= for cs1 according to the configuration settings Volume = A['Volume']; end extra_text_in_vol_iss_check (Volume, A:ORIGIN ('Volume'), 'v'); local Issue; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) and utilities.in_array (Periodical_origin, cfg.citation_issue_t) then -- {{citation}} may render |issue= when these parameters are used Issue = A['Issue']; end elseif utilities.in_array (config.CitationClass, cfg.templates_using_issue) then -- conference & map books do not support issue; {{citation}} listed here because included in settings table if not (utilities.in_array (config.CitationClass, {'conference', 'map', 'citation'}) and not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical))) then Issue = A['Issue']; end end local ArticleNumber; if utilities.in_array (config.CitationClass, {'journal', 'conference'}) or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then ArticleNumber = A['ArticleNumber']; end extra_text_in_vol_iss_check (Issue, A:ORIGIN ('Issue'), 'i'); Issue = utilities.hyphen_to_dash (Issue); local Page; local Pages; local At; local QuotePage; local QuotePages; if not utilities.in_array (config.CitationClass, cfg.templates_not_using_page) then -- TODO: rewrite to emit ignored parameter error message? Page = A['Page']; Pages = utilities.hyphen_to_dash (A['Pages']); At = A['At']; QuotePage = A['QuotePage']; QuotePages = utilities.hyphen_to_dash (A['QuotePages']); end local NoPP = is_valid_parameter_value (A['NoPP'], A:ORIGIN('NoPP'), cfg.keywords_lists['yes_true_y'], nil); local Mode = mode_set (A['Mode'], A:ORIGIN('Mode')); -- separator character and postscript local sepc, PostScript = set_style (Mode:lower(), A['PostScript'], config.CitationClass); local Quote; Quote, QuotePage, QuotePages, PostScript = quote_make (A['Quote'], A['TransQuote'], A['ScriptQuote'], QuotePage, QuotePages, NoPP, sepc, PostScript); local Edition = A['Edition']; local PublicationPlace = place_check (A['PublicationPlace'], A:ORIGIN('PublicationPlace')); local Place = place_check (A['Place'], A:ORIGIN('Place')); local PublisherName = A['PublisherName']; local PublisherName_origin = A:ORIGIN('PublisherName'); if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then local i = 0; PublisherName, i = utilities.strip_apostrophe_markup (PublisherName); -- strip apostrophe markup so that metadata isn't contaminated; publisher is never italicized if i and (0 < i) then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {PublisherName_origin}); end end if ('document' == config.CitationClass) and not utilities.is_set (PublisherName) then utilities.set_message ('err_missing_publisher', {config.CitationClass, 'publisher'}); end local Newsgroup = A['Newsgroup']; -- TODO: strip apostrophe markup? local Newsgroup_origin = A:ORIGIN('Newsgroup'); if 'newsgroup' == config.CitationClass then if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then -- general use parameter |publisher= not allowed in cite newsgroup utilities.set_message ('err_parameter_ignored', {PublisherName_origin}); end PublisherName = nil; -- ensure that this parameter is unset for the time being; will be used again after COinS end if 'book' == config.CitationClass or 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then local accept; PublisherName, accept = utilities.has_accept_as_written (PublisherName); -- check for and remove accept-as-written markup from |publisher= wrapped if not accept then -- when no accept-as-written markup check_publisher_name (PublisherName); -- emit maint message when |publisher= might be prefixed with publisher's location end end local URL = A['URL']; -- TODO: better way to do this for URL, ChapterURL, and MapURL? local UrlAccess = is_valid_parameter_value (A['UrlAccess'], A:ORIGIN('UrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (URL) and utilities.is_set (UrlAccess) then UrlAccess = nil; utilities.set_message ('err_param_access_requires_param', 'url'); end local ChapterURL = A['ChapterURL']; local ChapterUrlAccess = is_valid_parameter_value (A['ChapterUrlAccess'], A:ORIGIN('ChapterUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (ChapterURL) and utilities.is_set (ChapterUrlAccess) then ChapterUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {A:ORIGIN('ChapterUrlAccess'):gsub ('%-access', '')}); end local MapUrlAccess = is_valid_parameter_value (A['MapUrlAccess'], A:ORIGIN('MapUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (A['MapURL']) and utilities.is_set (MapUrlAccess) then MapUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {'map-url'}); end local this_page = mw.title.getCurrentTitle(); -- also used for COinS and for language local no_tracking_cats = is_valid_parameter_value (A['NoTracking'], A:ORIGIN('NoTracking'), cfg.keywords_lists['yes_true_y'], nil); -- check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories if not utilities.is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page if cfg.uncategorized_namespaces[this_page.namespace] then -- is this page's namespace id one of the uncategorized namespace ids? no_tracking_cats = "true"; -- set no_tracking_cats end for _, v in ipairs (cfg.uncategorized_subpages) do -- cycle through page name patterns if this_page.text:match (v) then -- test page name against each pattern no_tracking_cats = "true"; -- set no_tracking_cats break; -- bail out if one is found end end end -- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it) utilities.select_one (args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'err_redundant_parameters'); -- this is a dummy call simply to get the error message and category local coins_pages; Page, Pages, At, coins_pages = insource_loc_get (Page, A:ORIGIN('Page'), Pages, A:ORIGIN('Pages'), At); if utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- both |publication-place= and |place= (|location=) allowed if different utilities.add_prop_cat ('location-test'); -- add property cat to evaluate how often PublicationPlace and Place are used together if PublicationPlace == Place then Place = ''; -- unset; don't need both if they are the same end elseif not utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- when only |place= (|location=) is set ... PublicationPlace = Place; -- promote |place= (|location=) to |publication-place end if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same local URL_origin = A:ORIGIN('URL'); -- get name of parameter that holds URL local ChapterURL_origin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL -- local ScriptChapter = A['ScriptChapter']; -- local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); local Format = A['Format']; local ChapterFormat = A['ChapterFormat']; local TransChapter = A['TransChapter']; local TransChapter_origin = A:ORIGIN ('TransChapter'); local TransTitle = A['TransTitle']; local ScriptTitle = A['ScriptTitle']; --[[ Parameter remapping for cite encyclopedia: When the citation has these parameters: |encyclopedia= and |title= then map |title= to |article= and |encyclopedia= to |title= for rendering |encyclopedia= and |article= then map |encyclopedia= to |title= for rendering |trans-title= maps to |trans-chapter= when |title= is re-mapped |url= maps to |chapter-url= when |title= is remapped All other combinations of |encyclopedia=, |title=, and |article= are not modified ]] local Encyclopedia = A['Encyclopedia']; -- used as a flag by this module and by ~/COinS local ScriptEncyclopedia = A['ScriptEncyclopedia']; local TransEncyclopedia = A['TransEncyclopedia']; if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then -- emit error message when Encyclopedia set but template is other than {{cite encyclopedia}} or {{citation}} if 'encyclopaedia' ~= config.CitationClass and 'citation' ~= config.CitationClass then if utilities.is_set (Encyclopedia) then utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('Encyclopedia')}); else utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('ScriptEncyclopedia')}); end Encyclopedia = nil; -- unset these because not supported by this template ScriptEncyclopedia = nil; TransEncyclopedia = nil; end elseif utilities.is_set (TransEncyclopedia) then utilities.set_message ('err_trans_missing_title', {'encyclopedia'}); end if ('encyclopaedia' == config.CitationClass) or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Periodical) and utilities.is_set (Encyclopedia) then -- when both parameters set emit an error message; {{citation}} only; Periodical not allowed in {{cite encyclopedia}} utilities.set_message ('err_periodical_ignored', {Periodical_origin}); end if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then Periodical = Encyclopedia; -- error or no, set Periodical to Encyclopedia for rendering; {{citation}} could (not legitimately) have both; use Encyclopedia Periodical_origin = A:ORIGIN ('Encyclopedia'); ScriptPeriodical = ScriptEncyclopedia; ScriptPeriodical_origin = A:ORIGIN ('ScriptEncyclopedia'); if utilities.is_set (Title) or utilities.is_set (ScriptTitle) then if not utilities.is_set (Chapter) then Chapter = Title; -- |encyclopedia= and |title= are set so map |title= params to |article= params for rendering ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle') TransChapter = TransTitle; ChapterURL = URL; ChapterURL_origin = URL_origin; ChapterUrlAccess = UrlAccess; ChapterFormat = Format; if not utilities.is_set (ChapterURL) and utilities.is_set (TitleLink) then Chapter = utilities.make_wikilink (TitleLink, Chapter); end Title = Periodical; -- now map |encyclopedia= params to |title= params for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; URL = ''; Format = ''; TitleLink = ''; end elseif utilities.is_set (Chapter) or utilities.is_set (ScriptChapter) then -- |title= not set Title = Periodical; -- |encyclopedia= set and |article= set so map |encyclopedia= to |title= for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; end end end -- special case for cite techreport. local ID = A['ID']; if (config.CitationClass == "techreport") then -- special case for cite techreport if utilities.is_set (A['Number']) then -- cite techreport uses 'number', which other citations alias to 'issue' if not utilities.is_set (ID) then -- can we use ID for the "number"? ID = A['Number']; -- yes, use it else -- ID has a value so emit error message utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'id') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'number')}); end end end -- Account for the oddity that is {{cite conference}}, before generation of COinS data. local ChapterLink -- = A['ChapterLink']; -- deprecated as a parameter but still used internally by cite episode local Conference = A['Conference']; local BookTitle = A['BookTitle']; local TransTitle_origin = A:ORIGIN ('TransTitle'); if 'conference' == config.CitationClass then if utilities.is_set (BookTitle) then Chapter = Title; Chapter_origin = 'title'; -- ChapterLink = TitleLink; -- |chapter-link= is deprecated ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; URL_origin = ''; ChapterFormat = Format; TransChapter = TransTitle; TransChapter_origin = TransTitle_origin; Title = BookTitle; Format = ''; -- TitleLink = ''; TransTitle = ''; URL = ''; end elseif 'speech' ~= config.CitationClass then Conference = ''; -- not cite conference or cite speech so make sure this is empty string end local cs2_lower = function (text) -- if mode is cs2, use lower case if (sepc ~= '.') then return text:lower(); end return text; end local use_lowercase = ( sepc == ',' ); -- controls capitalization of certain static text -- cite map oddities local Cartography = ""; local Scale = ""; local Sheet = A['Sheet'] or ''; local Sheets = A['Sheets'] or ''; if config.CitationClass == "map" then if utilities.is_set (Chapter) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'map') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', Chapter_origin)}); -- add error message end Chapter = A['Map']; Chapter_origin = A:ORIGIN('Map'); ChapterURL = A['MapURL']; ChapterURL_origin = A:ORIGIN('MapURL'); TransChapter = A['TransMap']; ScriptChapter = A['ScriptMap'] ScriptChapter_origin = A:ORIGIN('ScriptMap') ChapterUrlAccess = MapUrlAccess; ChapterFormat = A['MapFormat']; Cartography = A['Cartography']; if utilities.is_set ( Cartography ) then Cartography = sepc .. " " .. wrap_msg ('cartography', Cartography, use_lowercase); end Scale = A['Scale']; if utilities.is_set ( Scale ) then Scale = sepc .. " " .. Scale; end end -- Account for the oddities that are {{cite episode}} and {{cite serial}}, before generation of COinS data. local Series = A['Series']; if 'episode' == config.CitationClass or 'serial' == config.CitationClass then local SeriesLink = A['SeriesLink']; SeriesLink = link_title_ok (SeriesLink, A:ORIGIN ('SeriesLink'), Series, 'series'); -- check for wiki-markup in |series-link= or wiki-markup in |series= when |series-link= is set local Network = A['Network']; local Station = A['Station']; local s, n = {}, {}; -- do common parameters first if utilities.is_set (Network) then table.insert(n, Network); end if utilities.is_set (Station) then table.insert(n, Station); end ID = table.concat(n, sepc .. ' '); if 'episode' == config.CitationClass then -- handle the oddities that are strictly {{cite episode}} local Season = A['Season']; local SeriesNumber = A['SeriesNumber']; if utilities.is_set (Season) and utilities.is_set (SeriesNumber) then -- these are mutually exclusive so if both are set TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'season') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'seriesno')}); -- add error message SeriesNumber = ''; -- unset; prefer |season= over |seriesno= end -- assemble a table of parts concatenated later into Series if utilities.is_set (Season) then table.insert(s, wrap_msg ('season', Season, use_lowercase)); end if utilities.is_set (SeriesNumber) then table.insert(s, wrap_msg ('seriesnum', SeriesNumber, use_lowercase)); end if utilities.is_set (Issue) then table.insert(s, wrap_msg ('episode', Issue, use_lowercase)); end Issue = ''; -- unset because this is not a unique parameter Chapter = Title; -- promote title parameters to chapter ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle'); ChapterLink = TitleLink; -- alias |episode-link= TransChapter = TransTitle; ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; ChapterFormat = Format; Title = Series; -- promote series to title TitleLink = SeriesLink; Series = table.concat(s, sepc .. ' '); -- this is concatenation of season, seriesno, episode number if utilities.is_set (ChapterLink) and not utilities.is_set (ChapterURL) then -- link but not URL Chapter = utilities.make_wikilink (ChapterLink, Chapter); elseif utilities.is_set (ChapterLink) and utilities.is_set (ChapterURL) then -- if both are set, URL links episode; Series = utilities.make_wikilink (ChapterLink, Series); end URL = ''; -- unset TransTitle = ''; ScriptTitle = ''; Format = ''; else -- now oddities that are cite serial Issue = ''; -- unset because this parameter no longer supported by the citation/core version of cite serial Chapter = A['Episode']; -- TODO: make |episode= available to cite episode someday? if utilities.is_set (Series) and utilities.is_set (SeriesLink) then Series = utilities.make_wikilink (SeriesLink, Series); end Series = utilities.wrap_style ('italic-title', Series); -- series is italicized end end -- end of {{cite episode}} stuff -- handle type parameter for those CS1 citations that have default values local TitleType = A['TitleType']; local Degree = A['Degree']; if utilities.in_array (config.CitationClass, {'AV-media-notes', 'document', 'interview', 'mailinglist', 'map', 'podcast', 'pressrelease', 'report', 'speech', 'techreport', 'thesis'}) then TitleType = set_titletype (config.CitationClass, TitleType); if utilities.is_set (Degree) and "Thesis" == TitleType then -- special case for cite thesis TitleType = Degree .. ' ' .. cfg.title_types ['thesis']:lower(); end end if utilities.is_set (TitleType) then -- if type parameter is specified TitleType = utilities.substitute ( cfg.messages['type'], TitleType); -- display it in parentheses -- TODO: Hack on TitleType to fix bunched parentheses problem end -- legacy: promote PublicationDate to Date if neither Date nor Year are set. local Date = A['Date']; local Date_origin; -- to hold the name of parameter promoted to Date; required for date error messaging local PublicationDate = A['PublicationDate']; local Year = A['Year']; if utilities.is_set (Year) then validation.year_check (Year); -- returns nothing; emits maint message when |year= doesn't hold a 'year' value end if not utilities.is_set (Date) then Date = Year; -- promote Year to Date Year = nil; -- make nil so Year as empty string isn't used for CITEREF if not utilities.is_set (Date) and utilities.is_set (PublicationDate) then -- use PublicationDate when |date= and |year= are not set Date = PublicationDate; -- promote PublicationDate to Date PublicationDate = ''; -- unset, no longer needed Date_origin = A:ORIGIN('PublicationDate'); -- save the name of the promoted parameter else Date_origin = A:ORIGIN('Year'); -- save the name of the promoted parameter end else Date_origin = A:ORIGIN('Date'); -- not a promotion; name required for error messaging end if PublicationDate == Date then PublicationDate = ''; end -- if PublicationDate is same as Date, don't display in rendered citation --[[ Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates. This must be done before we do COinS because here is where we get the date used in the metadata. Date validation supporting code is in Module:Citation/CS1/Date_validation ]] local DF = is_valid_parameter_value (A['DF'], A:ORIGIN('DF'), cfg.keywords_lists['df'], ''); if not utilities.is_set (DF) then DF = cfg.global_df; -- local |df= if present overrides global df set by {{use xxx date}} template end local ArchiveURL; local ArchiveDate; local ArchiveFormat = A['ArchiveFormat']; local archive_url_timestamp; -- timestamp from wayback machine url ArchiveURL, ArchiveDate, archive_url_timestamp = archive_url_check (A['ArchiveURL'], A['ArchiveDate']) ArchiveFormat = style_format (ArchiveFormat, ArchiveURL, 'archive-format', 'archive-url'); ArchiveURL, ArchiveDate = is_unique_archive_url (ArchiveURL, URL, ChapterURL, A:ORIGIN('ArchiveURL'), ArchiveDate); -- add error message when URL or ChapterURL == ArchiveURL local AccessDate = A['AccessDate']; local COinS_date = {}; -- holds date info extracted from |date= for the COinS metadata by Module:Date verification local DoiBroken = A['DoiBroken']; local Embargo = A['Embargo']; local anchor_year; -- used in the CITEREF identifier do -- create defined block to contain local variables error_message, date_parameters_list, mismatch local error_message = ''; -- AirDate has been promoted to Date so not necessary to check it local date_parameters_list = { ['access-date'] = {val = AccessDate, name = A:ORIGIN ('AccessDate')}, ['archive-date'] = {val = ArchiveDate, name = A:ORIGIN ('ArchiveDate')}, ['date'] = {val = Date, name = Date_origin}, ['doi-broken-date'] = {val = DoiBroken, name = A:ORIGIN ('DoiBroken')}, ['pmc-embargo-date'] = {val = Embargo, name = A:ORIGIN ('Embargo')}, ['publication-date'] = {val = PublicationDate, name = A:ORIGIN ('PublicationDate')}, ['year'] = {val = Year, name = A:ORIGIN ('Year')}, }; local error_list = {}; anchor_year, Embargo = validation.dates(date_parameters_list, COinS_date, error_list); if utilities.is_set (Year) and utilities.is_set (Date) then -- both |date= and |year= not normally needed; validation.year_date_check (Year, A:ORIGIN ('Year'), Date, A:ORIGIN ('Date'), error_list); end if 0 == #error_list then -- error free dates only; 0 when error_list is empty local modified = false; -- flag if utilities.is_set (DF) then -- if we need to reformat dates modified = validation.reformat_dates (date_parameters_list, DF); -- reformat to DF format, use long month names if appropriate end if true == validation.date_hyphen_to_dash (date_parameters_list) then -- convert hyphens to dashes where appropriate modified = true; utilities.set_message ('maint_date_format'); -- hyphens were converted so add maint category end -- for those wikis that can and want to have English date names translated to the local language; not supported at en.wiki if cfg.date_name_auto_xlate_enable and validation.date_name_xlate (date_parameters_list, cfg.date_digit_auto_xlate_enable ) then utilities.set_message ('maint_date_auto_xlated'); -- add maint cat modified = true; end if modified then -- if the date_parameters_list values were modified AccessDate = date_parameters_list['access-date'].val; -- overwrite date holding parameters with modified values ArchiveDate = date_parameters_list['archive-date'].val; Date = date_parameters_list['date'].val; DoiBroken = date_parameters_list['doi-broken-date'].val; PublicationDate = date_parameters_list['publication-date'].val; end if archive_url_timestamp and utilities.is_set (ArchiveDate) then validation.archive_date_check (ArchiveDate, archive_url_timestamp, DF); -- does YYYYMMDD in archive_url_timestamp match date in ArchiveDate end else utilities.set_message ('err_bad_date', {utilities.make_sep_list (#error_list, error_list)}); -- add this error message end end -- end of do if utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) or -- {{cite book}}, {{cite encyclopedia}}; TODO: {{cite conference}} and others? ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) or -- {{citation}} as an encylopedia citation ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then -- {{citation}} as a book citation if utilities.is_set (PublicationPlace) then if not utilities.is_set (PublisherName) then local date = COinS_date.rftdate and tonumber (COinS_date.rftdate:match ('%d%d%d%d')); -- get year portion of COinS date (because in Arabic numerals); convert string to number if date and (1850 <= date) then -- location has no publisher; if date is 1850 or later utilities.set_message ('maint_location_no_publisher'); -- add maint cat end else -- PublisherName has a value if cfg.keywords_xlate['none'] == PublisherName then -- if that value is 'none' (only for book and encyclopedia citations) PublisherName = ''; -- unset end end end end local ID_list = {}; -- sequence table of rendered identifiers local ID_list_coins = {}; -- table of identifiers and their values from args; key is same as cfg.id_handlers's key local Class = A['Class']; -- arxiv class identifier local ID_support = { {A['ASINTLD'], 'ASIN', 'err_asintld_missing_asin', A:ORIGIN ('ASINTLD')}, {DoiBroken, 'DOI', 'err_doibroken_missing_doi', A:ORIGIN ('DoiBroken')}, {Embargo, 'PMC', 'err_embargo_missing_pmc', A:ORIGIN ('Embargo')}, } ID_list, ID_list_coins = identifiers.identifier_lists_get (args, { DoiBroken = DoiBroken, -- for |doi= ASINTLD = A['ASINTLD'], -- for |asin= Embargo = Embargo, -- for |pmc= Class = Class, -- for |arxiv= CitationClass = config.CitationClass, -- for |arxiv= Year=anchor_year, -- for |isbn= }, ID_support); if 'citation' == config.CitationClass then -- catch ve/citoid malformed book cites in {{citation}} templates for _, id in ipairs (ID_list) do -- search through the ID_list sequence looking for an ISBN identifier string if id:find ('ISBN', 3, true) then -- plain find, start at index 3 ([[ISBN) if utilities.is_set (Periodical) then -- when a |work= alias is set utilities.set_message ('maint_work_isbn'); -- add maint cat end end end end -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, {{cite ssrn}}, before generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv=, |citeseerx=, |medrxiv=, |ssrn= required for their templates if not (args[cfg.id_handlers[config.CitationClass:upper()].parameters[1]] or -- can't use ID_list_coins k/v table here because invalid parameters omitted args[cfg.id_handlers[config.CitationClass:upper()].parameters[2]]) then -- which causes unexpected parameter missing error message utilities.set_message ('err_' .. config.CitationClass .. '_missing'); -- add error message end Periodical = ({['arxiv'] = 'arXiv', ['biorxiv'] = 'bioRxiv', ['citeseerx'] = 'CiteSeerX', ['medrxiv'] = 'medRxiv', ['ssrn'] = 'Social Science Research Network'})[config.CitationClass]; end -- Link the title of the work if no |url= was provided, but we have a |pmc= or a |doi= with |doi-access=free if config.CitationClass == "journal" and not utilities.is_set (URL) and not utilities.is_set (TitleLink) and not utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) then -- TODO: remove 'none' once existing citations have been switched to 'off', so 'none' can be used as token for "no title" instead if 'none' ~= cfg.keywords_xlate[auto_select] then -- if auto-linking not disabled if identifiers.auto_link_urls[auto_select] then -- manual selection URL = identifiers.auto_link_urls[auto_select]; -- set URL to be the same as identifier's external link URL_origin = cfg.id_handlers[auto_select:upper()].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['pmc'] then -- auto-select PMC URL = identifiers.auto_link_urls['pmc']; -- set URL to be the same as the PMC external link if not embargoed URL_origin = cfg.id_handlers['PMC'].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['doi'] then -- auto-select DOI URL = identifiers.auto_link_urls['doi']; URL_origin = cfg.id_handlers['DOI'].parameters[1]; end end if utilities.is_set (URL) then -- set when using an identifier-created URL if utilities.is_set (AccessDate) then -- |access-date= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_accessdate_missing_url'); -- add an error message AccessDate = ''; -- unset end if utilities.is_set (ArchiveURL) then -- |archive-url= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_archive_missing_url'); -- add an error message ArchiveURL = ''; -- unset end end end -- At this point fields may be nil if they weren't specified in the template use. We can use that fact. -- Test if citation has no title if not utilities.is_set (Title) and not utilities.is_set (TransTitle) and not utilities.is_set (ScriptTitle) then -- has special case for cite episode utilities.set_message ('err_citation_missing_title', {'episode' == config.CitationClass and 'series' or 'title'}); end if utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) and utilities.in_array (config.CitationClass, {'journal', 'citation'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and ('journal' == Periodical_origin or 'script-journal' == ScriptPeriodical_origin) then -- special case for journal cites Title = ''; -- set title to empty string utilities.set_message ('maint_untitled'); -- add maint cat end if 'journal' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then if is_page_art_num (((utilities.is_set (Page) and Page) or (utilities.is_set (Pages) and Pages)) or nil, ID_list_coins['DOI']) then -- does |page(s)= look like it holds an article number utilities.set_message ('maint_page_art_num'); -- add maint cat end end -- COinS metadata (see <http://ocoins.info/>) for automated parsing of citation information. -- handle the oddity that is cite encyclopedia and {{citation |encyclopedia=something}}. Here we presume that -- when Periodical, Title, and Chapter are all set, then Periodical is the book (encyclopedia) title, Title -- is the article title, and Chapter is a section within the article. So, we remap local coins_chapter = Chapter; -- default assuming that remapping not required local coins_title = Title; -- et tu if 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Chapter) and utilities.is_set (Title) and utilities.is_set (Periodical) then -- if all are used then coins_chapter = Title; -- remap coins_title = Periodical; end end local coins_author = a; -- default for coins rft.au if 0 < #c then -- but if contributor list coins_author = c; -- use that instead end -- this is the function call to COinS() local OCinSoutput = metadata.COinS({ ['Periodical'] = utilities.strip_apostrophe_markup (Periodical), -- no markup in the metadata ['Encyclopedia'] = Encyclopedia, -- just a flag; content ignored by ~/COinS ['Chapter'] = metadata.make_coins_title (coins_chapter, ScriptChapter), -- Chapter and ScriptChapter stripped of bold / italic / accept-as-written markup ['Degree'] = Degree; -- cite thesis only ['Title'] = metadata.make_coins_title (coins_title, ScriptTitle), -- Title and ScriptTitle stripped of bold / italic / accept-as-written markup ['PublicationPlace'] = PublicationPlace, ['Date'] = COinS_date.rftdate, -- COinS_date.* has correctly formatted date values if Date is valid; ['Season'] = COinS_date.rftssn, ['Quarter'] = COinS_date.rftquarter, ['Chron'] = COinS_date.rftchron, ['Series'] = Series, ['Volume'] = Volume, ['Issue'] = Issue, ['ArticleNumber'] = ArticleNumber, ['Pages'] = coins_pages or metadata.get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At, QuotePage, QuotePages}, 7)), -- pages stripped of external links ['Edition'] = Edition, ['PublisherName'] = PublisherName or Newsgroup, -- any apostrophe markup already removed from PublisherName ['URL'] = first_set ({ChapterURL, URL}, 2), ['Authors'] = coins_author, ['ID_list'] = ID_list_coins, ['RawPage'] = this_page.prefixedText, }, config.CitationClass); -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, and {{cite ssrn}} AFTER generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- we have set rft.jtitle in COinS to arXiv, bioRxiv, CiteSeerX, medRxiv, or ssrn now unset so it isn't displayed Periodical = ''; -- periodical not allowed in these templates; if article has been published, use cite journal end -- special case for cite newsgroup. Do this after COinS because we are modifying Publishername to include some static text if 'newsgroup' == config.CitationClass and utilities.is_set (Newsgroup) then PublisherName = utilities.substitute (cfg.messages['newsgroup'], external_link( 'news:' .. Newsgroup, Newsgroup, Newsgroup_origin, nil )); end local Editors; local EditorCount; -- used only for choosing {ed.) or (eds.) annotation at end of editor name-list local Contributors; -- assembled contributors name list local contributor_etal; local Translators; -- assembled translators name list local translator_etal; local t = {}; -- translators list from |translator-lastn= / translator-firstn= pairs t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= local Interviewers; local interviewers_list = {}; interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters local interviewer_etal; -- Now perform various field substitutions. -- We also add leading spaces and surrounding markup and punctuation to the -- various parts of the citation, but only when they are non-nil. do local last_first_list; local control = { format = NameListStyle, -- empty string, '&', 'amp', 'and', or 'vanc' maximum = nil, -- as if display-authors or display-editors not set mode = Mode }; do -- do editor name list first because the now unsupported coauthors used to modify control table local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayEditors'], A['DisplayEditors'], A:ORIGIN ('DisplayEditors'), #e); control.maximum, editor_etal = get_display_names (display_names, #e, 'editors', editor_etal, param); Editors, EditorCount = list_people (control, e, editor_etal); if 1 == EditorCount and (true == editor_etal or 1 < #e) then -- only one editor displayed but includes etal then EditorCount = 2; -- spoof to display (eds.) annotation end end do -- now do interviewers local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayInterviewers'], A['DisplayInterviewers'], A:ORIGIN ('DisplayInterviewers'), #interviewers_list); control.maximum, interviewer_etal = get_display_names (display_names, #interviewers_list, 'interviewers', interviewer_etal, param); Interviewers = list_people (control, interviewers_list, interviewer_etal); end do -- now do translators local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayTranslators'], A['DisplayTranslators'], A:ORIGIN ('DisplayTranslators'), #t); control.maximum, translator_etal = get_display_names (display_names, #t, 'translators', translator_etal, param); Translators = list_people (control, t, translator_etal); end do -- now do contributors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayContributors'], A['DisplayContributors'], A:ORIGIN ('DisplayContributors'), #c); control.maximum, contributor_etal = get_display_names (display_names, #c, 'contributors', contributor_etal, param); Contributors = list_people (control, c, contributor_etal); end do -- now do authors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayAuthors'], A['DisplayAuthors'], A:ORIGIN ('DisplayAuthors'), #a, author_etal); control.maximum, author_etal = get_display_names (display_names, #a, 'authors', author_etal, param); last_first_list = list_people (control, a, author_etal); if utilities.is_set (Authors) then Authors, author_etal = name_has_etal (Authors, author_etal, false, 'authors'); -- find and remove variations on et al. if author_etal then Authors = Authors .. ' ' .. cfg.messages['et al']; -- add et al. to authors parameter end else Authors = last_first_list; -- either an author name list or an empty string end end -- end of do if utilities.is_set (Authors) and utilities.is_set (Collaboration) then Authors = Authors .. ' (' .. Collaboration .. ')'; -- add collaboration after et al. end end local ConferenceFormat = A['ConferenceFormat']; local ConferenceURL = A['ConferenceURL']; ConferenceFormat = style_format (ConferenceFormat, ConferenceURL, 'conference-format', 'conference-url'); Format = style_format (Format, URL, 'format', 'url'); -- special case for chapter format so no error message or cat when chapter not supported if not (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia))) then ChapterFormat = style_format (ChapterFormat, ChapterURL, 'chapter-format', 'chapter-url'); end if not utilities.is_set (URL) then if utilities.in_array (config.CitationClass, {"web", "podcast", "mailinglist"}) or -- |url= required for {{cite web}}, {{cite podcast}}, and {{cite mailing list}} ('citation' == config.CitationClass and ('website' == Periodical_origin or 'script-website' == ScriptPeriodical_origin)) then -- and required for {{citation}} with |website= or |script-website= if not url_was_archive_today then -- is <URL> empty/missing because it was a deprecated archive.today url utilities.set_message ('err_cite_web_url'); -- no; emit an error message for an empty/ missing |url= end end -- do we have |accessdate= without either |url= or |chapter-url=? if utilities.is_set (AccessDate) and not utilities.is_set (ChapterURL) then -- ChapterURL may be set when URL is not set; utilities.set_message ('err_accessdate_missing_url'); AccessDate = ''; end end local UrlStatus = is_valid_parameter_value (A['UrlStatus'], A:ORIGIN('UrlStatus'), cfg.keywords_lists['url-status'], ''); local OriginalURL local OriginalURL_origin local OriginalFormat local OriginalAccess; UrlStatus = UrlStatus:lower(); -- used later when assembling archived text if utilities.is_set ( ArchiveURL ) then if utilities.is_set (ChapterURL) then -- if chapter-url= is set apply archive url to it OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text OriginalURL_origin = ChapterURL_origin; -- name of |chapter-url= parameter for error messages OriginalFormat = ChapterFormat; -- and original |chapter-format= if 'live' ~= UrlStatus then ChapterURL = ArchiveURL -- swap-in the archive's URL ChapterURL_origin = A:ORIGIN('ArchiveURL') -- name of |archive-url= parameter for error messages ChapterFormat = ArchiveFormat or ''; -- swap in archive's format ChapterUrlAccess = nil; -- restricted access levels do not make sense for archived URLs end elseif utilities.is_set (URL) then OriginalURL = URL; -- save copy of original source URL OriginalURL_origin = URL_origin; -- name of URL parameter for error messages OriginalFormat = Format; -- and original |format= OriginalAccess = UrlAccess; if 'live' ~= UrlStatus then -- if URL set then |archive-url= applies to it URL = ArchiveURL -- swap-in the archive's URL URL_origin = A:ORIGIN('ArchiveURL') -- name of archive URL parameter for error messages Format = ArchiveFormat or ''; -- swap in archive's format UrlAccess = nil; -- restricted access levels do not make sense for archived URLs end end elseif utilities.is_set (UrlStatus) then -- if |url-status= is set when |archive-url= is not set utilities.set_message ('maint_url_status'); -- add maint cat end if utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or -- if any of the 'periodical' cites except encyclopedia ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) then local chap_param; if utilities.is_set (Chapter) then -- get a parameter name from one of these chapter related meta-parameters chap_param = A:ORIGIN ('Chapter') elseif utilities.is_set (TransChapter) then chap_param = A:ORIGIN ('TransChapter') elseif utilities.is_set (ChapterURL) then chap_param = A:ORIGIN ('ChapterURL') elseif utilities.is_set (ScriptChapter) then chap_param = ScriptChapter_origin; else utilities.is_set (ChapterFormat) chap_param = A:ORIGIN ('ChapterFormat') end if utilities.is_set (chap_param) then -- if we found one utilities.set_message ('err_chapter_ignored', {chap_param}); -- add error message Chapter = ''; -- and set them to empty string to be safe with concatenation TransChapter = ''; ChapterURL = ''; ScriptChapter = ''; ChapterFormat = ''; end else -- otherwise, format chapter / article title local no_quotes = false; -- default assume that we will be quoting the chapter parameter value if utilities.is_set (Contribution) and 0 < #c then -- if this is a contribution with contributor(s) if utilities.in_array (Contribution:lower(), cfg.keywords_lists.contribution) then -- and a generic contribution title no_quotes = true; -- then render it unquoted end end Chapter = format_chapter_title (ScriptChapter, ScriptChapter_origin, Chapter, Chapter_origin, TransChapter, TransChapter_origin, ChapterURL, ChapterURL_origin, no_quotes, ChapterUrlAccess); -- Contribution is also in Chapter if utilities.is_set (Chapter) then Chapter = Chapter .. ChapterFormat ; if 'map' == config.CitationClass and utilities.is_set (TitleType) then Chapter = Chapter .. ' ' .. TitleType; -- map annotation here; not after title end Chapter = Chapter .. sepc .. ' '; elseif utilities.is_set (ChapterFormat) then -- |chapter= not set but |chapter-format= is so ... Chapter = ChapterFormat .. sepc .. ' '; -- ... ChapterFormat has error message, we want to see it end end -- Format main title local plain_title = false; local accept_title; Title, accept_title = utilities.has_accept_as_written (Title, true); -- remove accept-this-as-written markup when it wraps all of <Title> if accept_title and ('' == Title) then -- only support forced empty for now "(())" Title = cfg.messages['notitle']; -- replace by predefined "No title" message -- TODO: utilities.set_message ( 'err_redundant_parameters', ...); -- issue proper error message instead of muting ScriptTitle = ''; -- just mute for now TransTitle = ''; -- just mute for now plain_title = true; -- suppress text decoration for descriptive title utilities.set_message ('maint_untitled'); -- add maint cat end if not accept_title then -- <Title> not wrapped in accept-as-written markup if '...' == Title:sub (-3) then -- if ellipsis is the last three characters of |title= Title = Title:gsub ('(%.%.%.)%.+$', '%1'); -- limit the number of dots to three elseif not mw.ustring.find (Title, '%.%s*%a%.$') and -- end of title is not a 'dot-(optional space-)letter-dot' initialism ... not mw.ustring.find (Title, '%s+%a%.$') then -- ...and not a 'space-letter-dot' initial (''Allium canadense'' L.) Title = mw.ustring.gsub(Title, '%' .. sepc .. '$', ''); -- remove any trailing separator character; sepc and ms.ustring() here for languages that use multibyte separator characters end if utilities.is_set (ArchiveURL) and is_archived_copy (Title) then utilities.set_message ('maint_archived_copy'); -- add maintenance category before we modify the content of Title end if is_generic ('generic_titles', Title) then utilities.set_message ('err_generic_title'); -- set an error message end end if (not plain_title) and (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'document', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) or ('map' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)))) then -- special case for cite map when the map is in a periodical treat as an article Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from module provided quote marks Title = utilities.wrap_style ('quoted-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); elseif plain_title or ('report' == config.CitationClass) then -- no styling for cite report and descriptive titles (otherwise same as above) Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); -- for cite report, use this form for trans-title else Title = utilities.wrap_style ('italic-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-italic-title', TransTitle); end if utilities.is_set (TransTitle) then if utilities.is_set (Title) then TransTitle = " " .. TransTitle; else utilities.set_message ('err_trans_missing_title', {'title'}); end end if utilities.is_set (Title) then -- TODO: is this the right place to be making Wikisource URLs? if utilities.is_set (TitleLink) and utilities.is_set (URL) then utilities.set_message ('err_wikilink_in_url'); -- set an error message because we can't have both TitleLink = ''; -- unset end if not utilities.is_set (TitleLink) and utilities.is_set (URL) then Title = external_link (URL, Title, URL_origin, UrlAccess) .. TransTitle .. Format; URL = ''; -- unset these because no longer needed Format = ""; elseif utilities.is_set (TitleLink) and not utilities.is_set (URL) then local ws_url; ws_url = wikisource_url_make (TitleLink); -- ignore ws_label return; not used here if ws_url then Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title-link'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], TitleLink, Title}); Title = Title .. TransTitle; else Title = utilities.make_wikilink (TitleLink, Title) .. TransTitle; end else local ws_url, ws_label, L; -- Title has italic or quote markup by the time we get here which causes is_wikilink() to return 0 (not a wikilink) ws_url, ws_label, L = wikisource_url_make (Title:gsub('^[\'"]*(.-)[\'"]*$', '%1')); -- make ws URL from |title= interwiki link (strip italic or quote markup); link portion L becomes tooltip label if ws_url then Title = Title:gsub ('%b[]', ws_label); -- replace interwiki link with ws_label to retain markup Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, Title}); Title = Title .. TransTitle; else Title = Title .. TransTitle; end end else Title = TransTitle; end if utilities.is_set (Place) then Place = " " .. wrap_msg ('written', Place, use_lowercase) .. sepc .. " "; end local ConferenceURL_origin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL if utilities.is_set (Conference) then if utilities.is_set (ConferenceURL) then Conference = external_link( ConferenceURL, Conference, ConferenceURL_origin, nil ); end Conference = sepc .. " " .. Conference .. ConferenceFormat; elseif utilities.is_set (ConferenceURL) then Conference = sepc .. " " .. external_link( ConferenceURL, nil, ConferenceURL_origin, nil ); end local Position = ''; if not utilities.is_set (Position) then local Minutes = A['Minutes']; local Time = A['Time']; if utilities.is_set (Minutes) then if utilities.is_set (Time) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'minutes') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'time')}); end Position = utilities.substitute (cfg.messages.minutes, Minutes); else if utilities.is_set (Time) then local TimeCaption = A['TimeCaption'] if not utilities.is_set (TimeCaption) then TimeCaption = cs2_lower(cfg.messages['event']); end Position = " " .. TimeCaption .. " " .. Time; end end else Position = " " .. Position; At = ''; end Page, Pages, Sheet, Sheets = format_pages_sheets (Page, Pages, Sheet, Sheets, config.CitationClass, Periodical_origin, sepc, NoPP, use_lowercase); At = utilities.is_set (At) and (sepc .. " " .. At) or ""; Position = utilities.is_set (Position) and (sepc .. " " .. Position) or ""; if config.CitationClass == 'map' then local Sections = A['Sections']; -- Section (singular) is an alias of Chapter so set earlier local Inset = A['Inset']; if utilities.is_set ( Inset ) then Inset = sepc .. " " .. wrap_msg ('inset', Inset, use_lowercase); end if utilities.is_set ( Sections ) then Section = sepc .. " " .. wrap_msg ('sections', Sections, use_lowercase); elseif utilities.is_set ( Section ) then Section = sepc .. " " .. wrap_msg ('section', Section, use_lowercase); end At = At .. Inset .. Section; end local Others = A['Others']; if utilities.is_set (Others) and 0 == #a and 0 == #e then -- add maint cat when |others= has value and used without |author=, |editor= if config.CitationClass == "AV-media-notes" or config.CitationClass == "audio-visual" then -- special maint for AV/M which has a lot of 'false' positives right now utilities.set_message ('maint_others_avm') else utilities.set_message ('maint_others'); end end Others = utilities.is_set (Others) and (sepc .. " " .. Others) or ""; if utilities.is_set (Translators) then Others = safe_join ({sepc .. ' ', wrap_msg ('translated', Translators, use_lowercase), Others}, sepc); end if utilities.is_set (Interviewers) then Others = safe_join ({sepc .. ' ', wrap_msg ('interview', Interviewers, use_lowercase), Others}, sepc); end local TitleNote = A['TitleNote']; TitleNote = utilities.is_set (TitleNote) and (sepc .. " " .. TitleNote) or ""; if utilities.is_set (Edition) then if Edition:match ('%f[%a][Ee]d%n?%.?$') or Edition:match ('%f[%a][Ee]dition$') then -- Ed, ed, Ed., ed., Edn, edn, Edn., edn. utilities.set_message ('err_extra_text_edition'); -- add error message end Edition = " " .. wrap_msg ('edition', Edition); else Edition = ''; end Series = utilities.is_set (Series) and wrap_msg ('series', {sepc, Series}) or ""; -- not the same as SeriesNum local Agency = A['Agency'] or ''; -- |agency= is supported by {{cite magazine}}, {{cite news}}, {{cite press release}}, {{cite web}}, and certain {{citation}} templates if utilities.is_set (Agency) then -- this testing done here because {{citation}} supports 'news' citations if utilities.in_array (config.CitationClass, {'magazine', 'news', 'pressrelease', 'web'}) or ('citation' == config.CitationClass and utilities.in_array (Periodical_origin, {"magazine", "newspaper", "work"})) then Agency = wrap_msg ('agency', {sepc, Agency}); -- format for rendering else Agency = ''; -- unset; not supported utilities.set_message ('err_parameter_ignored', {'agency'}); -- add error message end end Volume = format_volume_issue (Volume, Issue, ArticleNumber, config.CitationClass, Periodical_origin, sepc, use_lowercase); if utilities.is_set (AccessDate) then local retrv_text = " " .. cfg.messages['retrieved']; AccessDate = nowrap_date (AccessDate); -- wrap in nowrap span if date in appropriate format retrv_text = cs2_lower(retrv_text); -- if mode is cs2, lower case AccessDate = utilities.substitute (retrv_text, AccessDate); -- add retrieved text AccessDate = utilities.substitute (cfg.presentation['accessdate'], {sepc, AccessDate}); -- allow editors to hide accessdates end if utilities.is_set (ID) then ID = sepc .. " " .. ID; end local Docket = A['Docket']; if "thesis" == config.CitationClass and utilities.is_set (Docket) then ID = sepc .. " Docket " .. Docket .. ID; end if "report" == config.CitationClass and utilities.is_set (Docket) then -- for cite report when |docket= is set ID = sepc .. ' ' .. Docket; -- overwrite ID even if |id= is set end if utilities.is_set (URL) then URL = " " .. external_link( URL, nil, URL_origin, UrlAccess ); end -- We check length of PostScript here because it will have been nuked by -- the quote parameters. We'd otherwise emit a message even if there wasn't -- a displayed postscript. -- TODO: Should the max size (1) be configurable? -- TODO: Should we check a specific pattern? if utilities.is_set(PostScript) and mw.ustring.len(PostScript) > 1 then utilities.set_message ('maint_postscript') end local Archived; if utilities.is_set (ArchiveURL) then if not utilities.is_set (ArchiveDate) then -- ArchiveURL set but ArchiveDate not set utilities.set_message ('err_archive_missing_date'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end else if utilities.is_set (ArchiveDate) then -- ArchiveURL not set but ArchiveDate is set utilities.set_message ('err_archive_date_missing_url'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end end if utilities.is_set (ArchiveURL) then local arch_text; if "live" == UrlStatus then if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cfg.messages['archived-live'], { external_link( ArchiveURL, cs2_lower(cfg.messages['archived']), A:ORIGIN('ArchiveURL'), nil) .. ArchiveFormat, ArchiveDate } ); else Archived = ''; end if not utilities.is_set (OriginalURL) then utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (OriginalURL) then -- UrlStatus is empty, 'dead', 'unfit', 'usurped', 'bot: unknown' if utilities.in_array (UrlStatus, {'unfit', 'usurped', 'bot: unknown'}) then Archived = sepc .. ' ' .. utilities.substitute ( cs2_lower(cfg.messages['archived-unfit']), ArchiveDate); if 'bot: unknown' == UrlStatus then utilities.set_message ('maint_bot_unknown'); -- and add a category if not already added else utilities.add_prop_cat ('unfit'); -- and add a category if not already added end else -- UrlStatus is empty, 'dead' if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cs2_lower(cfg.messages['archived-dead']), { external_link( OriginalURL, cfg.messages['original'], OriginalURL_origin, OriginalAccess ) .. OriginalFormat, ArchiveDate } ); else Archived = ''; -- unset for concatenation end end else -- OriginalUrl not set utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (ArchiveFormat) then Archived = ArchiveFormat; -- if set and ArchiveURL not set ArchiveFormat has error message else Archived = ''; end local TranscriptURL = A['TranscriptURL'] local TranscriptFormat = A['TranscriptFormat']; TranscriptFormat = style_format (TranscriptFormat, TranscriptURL, 'transcript-format', 'transcripturl'); local Transcript = A['Transcript']; local TranscriptURL_origin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL if utilities.is_set (Transcript) then if utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, Transcript, TranscriptURL_origin, nil ); end Transcript = sepc .. ' ' .. Transcript .. TranscriptFormat; elseif utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, nil, TranscriptURL_origin, nil ); end local Publisher; if utilities.is_set (PublicationDate) then PublicationDate = wrap_msg ('published', PublicationDate); end if utilities.is_set (PublisherName) then if utilities.is_set (PublicationPlace) then Publisher = sepc .. " " .. PublicationPlace .. ": " .. PublisherName .. PublicationDate; else Publisher = sepc .. " " .. PublisherName .. PublicationDate; end elseif utilities.is_set (PublicationPlace) then Publisher= sepc .. " " .. PublicationPlace .. PublicationDate; else Publisher = PublicationDate; end -- Several of the above rely upon detecting this as nil, so do it last. if (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical)) then if utilities.is_set (Title) or utilities.is_set (TitleNote) then Periodical = sepc .. " " .. format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); else Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); end end local Language = A['Language']; if utilities.is_set (Language) then Language = language_parameter (Language); -- format, categories, name from ISO639-1, etc. else Language=''; -- language not specified so make sure this is an empty string; --[[ TODO: need to extract the wrap_msg from language_parameter so that we can solve parentheses bunching problem with Format/Language/TitleType ]] end --[[ Handle the oddity that is cite speech. This code overrides whatever may be the value assigned to TitleNote (through |department=) and forces it to be " (Speech)" so that the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided). ]] if "speech" == config.CitationClass then -- cite speech only TitleNote = TitleType; -- move TitleType to TitleNote so that it renders ahead of |event= TitleType = ''; -- and unset if utilities.is_set (Periodical) then -- if Periodical, perhaps because of an included |website= or |journal= parameter if utilities.is_set (Conference) then -- and if |event= is set Conference = Conference .. sepc .. " "; -- then add appropriate punctuation to the end of the Conference variable before rendering end end end -- Piece all bits together at last. Here, all should be non-nil. -- We build things this way because it is more efficient in LUA -- not to keep reassigning to the same string variable over and over. local tcommon; local tcommon2; -- used for book cite when |contributor= is set local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; -- Volume = safe_join ({Volume, pgtext}, sepc); if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (Periodical) then -- special cases for book cites if utilities.is_set (Contributors) then -- when we are citing foreword, preface, introduction, etc. tcommon = safe_join ({Title, TitleNote}, sepc); -- author and other stuff will come after this and before tcommon2 tcommon2 = safe_join ({TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); else tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); end elseif 'map' == config.CitationClass then -- special cases for cite map if utilities.is_set (Chapter) then -- map in a book; TitleType is part of Chapter tcommon = safe_join ({Title, Edition, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); elseif utilities.is_set (Periodical) then -- map in a periodical tcommon = safe_join ({Title, TitleType, Periodical, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); else -- a sheet or stand-alone map tcommon = safe_join ({Title, TitleType, Edition, Scale, Series, Language, Cartography, Others, Publisher}, sepc); end elseif 'episode' == config.CitationClass then -- special case for cite episode tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Edition, Publisher}, sepc); else -- all other CS1 templates tcommon = safe_join ({Title, TitleNote, Conference, Periodical, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc); end if #ID_list > 0 then ID_list = safe_join( { sepc .. " ", table.concat( ID_list, sepc .. " " ), ID }, sepc ); else ID_list = ID; end local Via = A['Via']; Via = utilities.is_set (Via) and wrap_msg ('via', Via) or ''; local idcommon; if 'audio-visual' == config.CitationClass or 'episode' == config.CitationClass then -- special case for cite AV media & cite episode position transcript idcommon = safe_join( { ID_list, URL, Archived, Transcript, AccessDate, Via, Quote }, sepc ); else idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, Quote }, sepc ); end local text; -- local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; local OrigDate = A['OrigDate']; OrigDate = utilities.is_set (OrigDate) and wrap_msg ('origdate', OrigDate) or ''; if utilities.is_set (Date) then if utilities.is_set (Authors) or utilities.is_set (Editors) then -- date follows authors or editors when authors not set Date = " (" .. Date .. ")" .. OrigDate .. sepc .. " "; -- in parentheses else -- neither of authors and editors set if (string.sub(tcommon, -1, -1) == sepc) then -- if the last character of tcommon is sepc Date = " " .. Date .. OrigDate; -- Date does not begin with sepc else Date = sepc .. " " .. Date .. OrigDate; -- Date begins with sepc end end end if utilities.is_set (Authors) then if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Authors termination Authors = terminate_name_list (Authors, sepc); -- when no date, terminate with 0 or 1 sepc and a space end if utilities.is_set (Editors) then local in_text = ''; local post_text = ''; if utilities.is_set (Chapter) and 0 == #c then in_text = cfg.messages['in'] .. ' '; in_text = cs2_lower(in_text); -- lowercase for cs2 end if EditorCount <= 1 then post_text = ' (' .. cfg.messages['editor'] .. ')'; -- be consistent with no-author, no-date case else post_text = ' (' .. cfg.messages['editors'] .. ')'; end Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space end if utilities.is_set (Contributors) then -- book cite and we're citing the intro, preface, etc. local by_text = sepc .. ' ' .. cfg.messages['by'] .. ' '; by_text = cs2_lower(by_text); -- lowercase for cs2 Authors = by_text .. Authors; -- author follows title so tweak it here if utilities.is_set (Editors) and utilities.is_set (Date) then -- when Editors make sure that Authors gets terminated Authors = terminate_name_list (Authors, sepc); -- terminate with 0 or 1 sepc and a space end if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Contributors termination Contributors = terminate_name_list (Contributors, sepc); -- terminate with 0 or 1 sepc and a space end text = safe_join( {Contributors, Date, Chapter, tcommon, Authors, Place, Editors, tcommon2, pgtext, idcommon }, sepc ); -- text = safe_join( {Contributors, Date, Chapter, tcommon, Authors, Place, Editors, tcommon2, idcommon }, sepc ); else text = safe_join( {Authors, Date, Chapter, Place, Editors, tcommon, pgtext, idcommon }, sepc ); -- text = safe_join( {Authors, Date, Chapter, Place, Editors, tcommon, idcommon }, sepc ); end elseif utilities.is_set (Editors) then if utilities.is_set (Date) then if EditorCount <= 1 then Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editor']; else Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editors']; end else if EditorCount <= 1 then Editors = Editors .. " (" .. cfg.messages['editor'] .. ")" .. sepc .. " " else Editors = Editors .. " (" .. cfg.messages['editors'] .. ")" .. sepc .. " " end end text = safe_join( {Editors, Date, Chapter, Place, tcommon, pgtext, idcommon}, sepc ); -- text = safe_join( {Editors, Date, Chapter, Place, tcommon, idcommon}, sepc ); else if utilities.in_array (config.CitationClass, {"journal", "citation"}) and utilities.is_set (Periodical) then text = safe_join( {Chapter, Place, tcommon, pgtext, Date, idcommon}, sepc ); -- text = safe_join( {Chapter, Place, tcommon, Date, idcommon}, sepc ); else text = safe_join( {Chapter, Place, tcommon, Date, pgtext, idcommon}, sepc ); -- text = safe_join( {Chapter, Place, tcommon, Date, idcommon}, sepc ); end end if utilities.is_set (PostScript) and PostScript ~= sepc then text = safe_join( {text, sepc}, sepc ); -- Deals with italics, spaces, etc. if '.' == sepc then -- remove final seperator if present text = text:gsub ('%' .. sepc .. '$', ''); -- dot must be escaped here else text = mw.ustring.gsub (text, sepc .. '$', ''); -- using ustring for non-dot sepc (likely a non-Latin character) end end text = safe_join( {text, PostScript}, sepc ); -- Now enclose the whole thing in a <cite> element local options_t = {}; options_t.class = cite_class_attribute_make (config.CitationClass, Mode); local Ref = is_valid_parameter_value (A['Ref'], A:ORIGIN('Ref'), cfg.keywords_lists['ref'], nil, true); -- nil when |ref=harv; A['Ref'] else if 'none' ~= cfg.keywords_xlate[(Ref and Ref:lower()) or ''] then local namelist_t = {}; -- holds selected contributor, author, editor name list local year = first_set ({Year, anchor_year}, 2); -- Year first for legacy citations and for YMD dates that require disambiguation if #c > 0 then -- if there is a contributor list namelist_t = c; -- select it elseif #a > 0 then -- or an author list namelist_t = a; elseif #e > 0 then -- or an editor list namelist_t = e; end local citeref_id; if #namelist_t > 0 then -- if there are names in namelist_t citeref_id = make_citeref_id (namelist_t, year); -- go make the CITEREF anchor if mw.uri.anchorEncode (citeref_id) == ((Ref and mw.uri.anchorEncode (Ref)) or '') then -- Ref may already be encoded (by {{sfnref}}) so citeref_id must be encoded before comparison utilities.set_message ('maint_ref_duplicates_default'); end else citeref_id = ''; -- unset end options_t.id = Ref or citeref_id; end if string.len (text:gsub('%b<>', '')) <= 2 then -- remove html and html-like tags; then get length of what remains; z.error_cats_t = {}; -- blank the categories list z.error_msgs_t = {}; -- blank the error messages list OCinSoutput = nil; -- blank the metadata string text = ''; -- blank the the citation utilities.set_message ('err_empty_citation'); -- set empty citation message and category end local render_t = {}; -- here we collect the final bits for concatenation into the rendered citation if is_preview_mode and (0 ~= #z.error_msgs_t or 0 ~= #z.maint_cats_t) then -- when in preview mode if not utilities.is_set (options_t.id) then -- and when this template has not created an anchor ID math.randomseed (tonumber (mw.getLanguage ('en'):formatDate ('U')) * 10000 + os.clock() * 10000); options_t.id = 'CITEREF_temp_preview_id_' .. math.random (100000, 999999); -- create temporary anchor ID for preview mode end end if utilities.is_set (options_t.id) then -- here we wrap the rendered citation in <cite ...>...</cite> tags options_t.id = mw.uri.anchorEncode(options_t.id); -- do this here; also used when adding preview warning messages table.insert (render_t, utilities.substitute (cfg.presentation['cite-id'], {options_t.id, mw.text.nowiki(options_t.class), text})); -- when |ref= is set or when there is a namelist else table.insert (render_t, utilities.substitute (cfg.presentation['cite'], {mw.text.nowiki(options_t.class), text})); -- when |ref=none or when namelist_t empty and |ref= is missing or is empty end if OCinSoutput then -- blanked when citation is 'empty' so don't bother to add boilerplate metadata span table.insert (render_t, utilities.substitute (cfg.presentation['ocins'], OCinSoutput)); -- format and append metadata to the citation end local template_name = cfg.citation_class_map_t[config.CitationClass]; local template_link = '[[Template:' .. template_name .. '|' .. template_name .. ']]'; local msg_prefix = '<code class="cs1-code">{{' .. template_link .. '}}</code>: '; if 0 ~= #z.error_msgs_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_e, {template_link, options_t.id})); table.insert (render_t, ' '); -- insert a space between citation and its error messages table.sort (z.error_msgs_t); -- sort the error messages list; sorting includes wrapping <span> and <code> tags; hidden-error sorts ahead of visible-error local hidden = true; -- presume that the only error messages emited by this template are hidden for _, v in ipairs (z.error_msgs_t) do -- spin through the list of error messages if v:find ('cs1-visible-error', 1, true) then -- look for the visible error class name hidden = false; -- found one; so don't hide the error message prefix break; -- and done because no need to look further end end z.error_msgs_t[1] = table.concat ({utilities.error_comment (msg_prefix, hidden), z.error_msgs_t[1]}); -- add error message prefix to first error message to prevent extraneous punctuation table.insert (render_t, table.concat (z.error_msgs_t, '; ')); -- make a big string of error messages and add it to the rendering end if 0 ~= #z.maint_cats_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_m, {template_link, options_t.id})); table.sort (z.maint_cats_t); -- sort the maintenance messages list local maint_msgs_t = {}; -- here we collect all of the maint messages if 0 == #z.error_msgs_t then -- if no error messages table.insert (maint_msgs_t, msg_prefix); -- insert message prefix in maint message livery end for _, v in ipairs( z.maint_cats_t ) do -- append maintenance categories table.insert (maint_msgs_t, -- assemble new maint message and add it to the maint_msgs_t table table.concat ({v, ' (', utilities.substitute (cfg.messages[':cat wikilink'], v), ')'}) ); end table.insert (render_t, utilities.substitute (cfg.presentation['hidden-maint'], table.concat (maint_msgs_t, ' '))); -- wrap the group of maint messages with proper presentation and save end if not no_tracking_cats then local sort_key; local cat_wikilink = 'cat wikilink'; if cfg.enable_sort_keys then -- when namespace sort keys enabled local namespace_number = mw.title.getCurrentTitle().namespace; -- get namespace number for this wikitext sort_key = (0 ~= namespace_number and (cfg.name_space_sort_keys[namespace_number] or cfg.name_space_sort_keys.other)) or nil; -- get sort key character; nil for mainspace cat_wikilink = (not sort_key and 'cat wikilink') or 'cat wikilink sk'; -- make <cfg.messages> key end for _, v in ipairs (z.error_cats_t) do -- append error categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end if cfg.id_limits_data_load_fail then -- boolean true when load failed utilities.set_message ('maint_id_limit_load_fail'); -- done here because this maint cat emits no message end for _, v in ipairs (z.maint_cats_t) do -- append maintenance categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end for _, v in ipairs (z.prop_cats_t) do -- append properties categories table.insert (render_t, utilities.substitute (cfg.messages['cat wikilink'], v)); -- no sort keys end end return table.concat (render_t); -- make a big string and done end --[[--------------------------< V A L I D A T E >-------------------------------------------------------------- Looks for a parameter's name in one of several whitelists. Parameters in the whitelist can have three values: true - active, supported parameters false - deprecated, supported parameters nil - unsupported parameters ]] local function validate (name, cite_class, empty) local name = tostring (name); local enum_name; -- parameter name with enumerator (if any) replaced with '#' local state; local function state_test (state, name) -- local function to do testing of state values if true == state then return true; end -- valid actively supported parameter if false == state then if empty then return nil; end -- empty deprecated parameters are treated as unknowns deprecated_parameter (name); -- parameter is deprecated but still supported return true; end if 'tracked' == state then local base_name = name:gsub ('%d', ''); -- strip enumerators from parameter names that have them to get the base name utilities.add_prop_cat ('tracked-param', {base_name}, base_name); -- add a properties category; <base_name> modifies <key> return true; end return nil; end if name:find ('#') then -- # is a cs1|2 reserved character so parameters with # not permitted return nil; end -- replace enumerator digit(s) with # (|last25= becomes |last#=) (mw.ustring because non-Western 'local' digits) enum_name = mw.ustring.gsub (name, '%d+$', '#'); -- where enumerator is last charaters in parameter name (these to protect |s2cid=) enum_name = mw.ustring.gsub (enum_name, '%d+([%-l])', '#%1'); -- where enumerator is in the middle of the parameter name; |author#link= is the oddity if 'document' == cite_class then -- special case for {{cite document}} state = whitelist.document_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end return false; end if utilities.in_array (cite_class, whitelist.preprint_template_list_t) then -- limited parameter sets allowed for these templates state = whitelist.limited_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end state = whitelist.preprint_arguments_t[cite_class][name]; -- look in the parameter-list for the template identified by cite_class if true == state_test (state, name) then return true; end return false; -- not supported because not found or name is set to nil end -- end limited parameter-set templates if utilities.in_array (cite_class, whitelist.unique_param_template_list_t) then -- template-specific parameters for templates that accept parameters from the basic argument list state = whitelist.unique_arguments_t[cite_class][name]; -- look in the template-specific parameter-lists for the template identified by cite_class if true == state_test (state, name) then return true; end end -- if here, fall into general validation state = whitelist.common_parameters_t[enum_name]; -- all other templates; all normal parameters allowed; this list holds enumerated and nonenumerated parameters if true == state_test (state, name) then return true; end return false; -- not supported because not found or name is set to nil end --[=[-------------------------< I N T E R _ W I K I _ C H E C K >---------------------------------------------- check <value> for inter-language interwiki-link markup. <prefix> must be a MediaWiki-recognized language code. when these values have the form (without leading colon): [[<prefix>:link|label]] return label as plain-text [[<prefix>:link]] return <prefix>:link as plain-text return value as is else ]=] local function inter_wiki_check (parameter, value) local prefix = value:match ('%[%[(%a+):'); -- get an interwiki prefix if one exists local _; if prefix and cfg.inter_wiki_map[prefix:lower()] then -- if prefix is in the map, needs preceding colon so utilities.set_message ('err_bad_paramlink', parameter); -- emit an error message _, value, _ = utilities.is_wikilink (value); -- extract label portion from wikilink end return value; end --[[--------------------------< M I S S I N G _ P I P E _ C H E C K >------------------------------------------ Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal sign, compare the alphanumeric string to the list of cs1|2 parameters. If found, then the string is possibly a parameter that is missing its pipe. There are two tests made: {{cite ... |title=Title access-date=2016-03-17}} -- the first parameter has a value and whitespace separates that value from the missing pipe parameter name {{cite ... |title=access-date=2016-03-17}} -- the first parameter has no value (whitespace after the first = is trimmed by MediaWiki) cs1|2 shares some parameter names with XML/HTML attributes: class=, title=, etc. To prevent false positives XML/HTML tags are removed before the search. If a missing pipe is detected, this function adds the missing pipe maintenance category. ]] local function missing_pipe_check (parameter, value) local capture; value = value:gsub ('%b<>', ''); -- remove XML/HTML tags because attributes: class=, title=, etc. capture = value:match ('%s+(%a[%w%-]+)%s*=') or value:match ('^(%a[%w%-]+)%s*='); -- find and categorize parameters with possible missing pipes if capture and validate (capture) then -- if the capture is a valid parameter name utilities.set_message ('err_missing_pipe', parameter); end end --[[--------------------------< H A S _ E X T R A N E O U S _ P U N C T >-------------------------------------- look for extraneous terminal punctuation in most parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_punc (param, value) if 'number' == type (param) then return; end param = param:gsub ('%d+', '#'); -- enumerated name-list mask params allow terminal punct; normalize if cfg.punct_skip[param] then return; -- parameter name found in the skip table so done end if value:match ('[,;:]$') then utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end if value:match ('^=') then -- sometimes an extraneous '=' character appears ... utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end end --[[--------------------------< H A S _ T W L _ U R L >-------------------------------------------------------- look for The Wikipedia Library urls in url-holding parameters. TWL urls are accessible only for readers who are active extended confirmed Wikipedia editors. This function sets an error message when such urls are discovered and when appropriate, sets the |<param>-url-access=subscription. returns nothing. looks for: '.wikipedialibrary.idm.oclc.org' ]] local function has_twl_url (url_params_t, cite_args_t) local url_error_t = {}; -- sequence of url-holding parameters that have a TWL url for param, value in pairs (url_params_t) do if value:find ('%.wikipedialibrary%.idm%.oclc%.org') then -- has the TWL base url? table.insert (url_error_t, param); -- add parameter name to the error list end end if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); -- sor for error messaging for i, param in ipairs (url_error_t) do if cfg.url_access_map_t[param] then -- if <param> has a matching -access parameter cite_args_t[cfg.url_access_map_t[param]] = cfg.keywords_xlate.subscription; -- set |<param>-url-access=subscription end url_error_t[i] = utilities.wrap_style ('parameter', param); -- make the parameter pretty for error message end utilities.set_message ('err_param_has_twl_url', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< H A S _ E X T R A N E O U S _ U R L >------------------------------------------ look for extraneous url parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_url (non_url_param_t) local url_error_t = {}; check_for_url (non_url_param_t, url_error_t); -- extraneous url check if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); utilities.set_message ('err_param_has_ext_link', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< _ C I T A T I O N >------------------------------------------------------------ Module entry point frame – from template call (citation()); may be nil when called from another module args_t – table of all cs1|2 parameters in the template (the parent frame) config_t – table of template-supplied parameter (the #invoke frame) ]] local function _citation (frame, args_t, config_t) -- save a copy in case we need to display an error message in preview mode if not frame then frame = mw.getCurrentFrame(); -- if called from another module, get a frame for frame-provided functions end -- i18n: set the name that your wiki uses to identify sandbox subpages from sandbox template invoke (or can be set here) local sandbox = ((config_t.SandboxPath and '' ~= config_t.SandboxPath) and config_t.SandboxPath) or '/sandbox'; -- sandbox path from {{#invoke:Citation/CS1/sandbox|citation|SandboxPath=/...}} is_sandbox = nil ~= string.find (frame:getTitle(), sandbox, 1, true); -- is this invoke the sandbox module? sandbox = is_sandbox and sandbox or ''; -- use i18n sandbox to load sandbox modules when this module is the sandox; live modules else cfg = mw.loadData ('Module:Citation/CS1/Configuration' .. sandbox); -- load sandbox versions of support modules when {{#invoke:Citation/CS1/sandbox|...}}; live modules else whitelist = mw.loadData ('Module:Citation/CS1/Whitelist' .. sandbox); utilities = require ('Module:Citation/CS1/Utilities' .. sandbox); validation = require ('Module:Citation/CS1/Date_validation' .. sandbox); identifiers = require ('Module:Citation/CS1/Identifiers' .. sandbox); metadata = require ('Module:Citation/CS1/COinS' .. sandbox); utilities.set_selected_modules (cfg); -- so that functions in Utilities can see the selected cfg tables identifiers.set_selected_modules (cfg, utilities); -- so that functions in Identifiers can see the selected cfg tables and selected Utilities module validation.set_selected_modules (cfg, utilities); -- so that functions in Date validataion can see selected cfg tables and the selected Utilities module metadata.set_selected_modules (cfg, utilities); -- so that functions in COinS can see the selected cfg tables and selected Utilities module z = utilities.z; -- table of error and category tables in Module:Citation/CS1/Utilities local cite_args_t = {}; -- because args_t is the parent (template) frame args (which cannot be modified); params and their values will be placed here is_preview_mode = not utilities.is_set (frame:preprocess ('{{REVISIONID}}')); local suggestions = {}; -- table where we store suggestions if we need to loadData them local error_text; -- used as a flag local capture; -- the single supported capture when matching unknown parameters using patterns local empty_unknowns = {}; -- sequence table to hold empty unknown params for error message listing for k, v in pairs (args_t) do -- get parameters from the parent (template) frame v = mw.ustring.gsub (v, '^%s*(.-)%s*$', '%1'); -- trim leading/trailing whitespace; when v is only whitespace, becomes empty string if v ~= '' then if cfg.enum_needs_xlation and 'string' == type (k) then -- for wikis that set date_names['local_digits'] to non-western digits k = mw.ustring.gsub (k, '%d', cfg.date_names.local_digits); -- translate 'local' digits enumerators to Western 0-9 end if not validate( k, config_t.CitationClass ) then if type (k) ~= 'string' then -- exclude empty numbered parameters if v:match("%S+") ~= nil then error_text = utilities.set_message ('err_text_ignored', {v}); end elseif validate (k:lower(), config_t.CitationClass) then error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, k:lower()}); -- suggest the lowercase version of the parameter else if nil == suggestions.suggestions then -- if this table is nil then we need to load it suggestions = mw.loadData ('Module:Citation/CS1/Suggestions' .. sandbox); --load sandbox version of suggestion module when {{#invoke:Citation/CS1/sandbox|...}}; live module else end for pattern, param in pairs (suggestions.patterns) do -- loop through the patterns to see if we can suggest a proper parameter capture = k:match (pattern); -- the whole match if no capture in pattern else the capture if a match if capture then -- if the pattern matches param = utilities.substitute (param, capture); -- add the capture to the suggested parameter (typically the enumerator) if validate (param, config_t.CitationClass) then -- validate the suggestion to make sure that the suggestion is supported by this template (necessary for limited parameter lists) error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, param}); -- set the suggestion error message else error_text = utilities.set_message ('err_parameter_ignored', {k}); -- suggested param not supported by this template v = ''; -- unset end end end if not utilities.is_set (error_text) then -- couldn't match with a pattern, is there an explicit suggestion? if (suggestions.suggestions[ k:lower() ] ~= nil) and validate (suggestions.suggestions[ k:lower() ], config_t.CitationClass) then utilities.set_message ('err_parameter_ignored_suggest', {k, suggestions.suggestions[ k:lower() ]}); else utilities.set_message ('err_parameter_ignored', {k}); v = ''; -- unset value assigned to unrecognized parameters (this for the limited parameter lists) end end end end cite_args_t[k] = v; -- save this parameter and its value elseif not utilities.is_set (v) then -- for empty parameters if not validate (k, config_t.CitationClass, true) then -- is this empty parameter a valid parameter k = ('' == k) and cfg.err_msg_supl.empty_str or k; -- when k is empty string (or was space(s) trimmed to empty string), replace with descriptive text table.insert (empty_unknowns, utilities.wrap_style ('parameter', k)); -- format for error message and add to the list end end end if 0 ~= #empty_unknowns then -- create empty unknown error message utilities.set_message ('err_param_unknown_empty', { 1 == #empty_unknowns and '' or 's', utilities.make_sep_list (#empty_unknowns, empty_unknowns) }); end local non_url_param_t = {}; -- table of parameters and values that are not url-holding parameters local url_param_t = {}; -- table of url-holding paramters and their values for k, v in pairs (cite_args_t) do if 'string' == type (k) then -- don't evaluate positional parameters has_invisible_chars (k, v); -- look for invisible characters end has_extraneous_punc (k, v); -- look for extraneous terminal punctuation in parameter values missing_pipe_check (k, v); -- do we think that there is a parameter that is missing a pipe? cite_args_t[k] = inter_wiki_check (k, v); -- when language interwiki-linked parameter missing leading colon replace with wiki-link label if 'string' == type (k) then -- when parameter k is not positional if not cfg.url_skip[k] then -- and not in url skip table non_url_param_t[k] = v; -- make a parameter/value list for extraneous url check else -- and is in url skip table (a url-holding parameter) url_param_t[k] = v; -- make a parameter/value list to check for values that are The Wikipedia Library url end end end if cfg.suppress_archive_today_urls then has_archive_today_url (cite_args_t); -- look for and suppress archive.today urls and dependent parameters for all templates end has_extraneous_url (non_url_param_t); -- look for url in parameter values where a url does not belong has_twl_url (url_param_t, cite_args_t); -- look for url-holding parameters that hold a The Wikipedia Library url return table.concat ({ frame:extensionTag ('templatestyles', '', {src='Module:Citation/CS1' .. sandbox .. '/styles.css'}), citation0 (config_t, cite_args_t) }); end --[[--------------------------< C I T A T I O N >-------------------------------------------------------------- Template entry point ]] local function citation (frame) local config_t = {}; -- table to store parameters from the module {{#invoke:}} local args_t = frame:getParent().args; -- get template's preset parameters for k, v in pairs (frame.args) do -- get parameters from the {{#invoke}} frame config_t[k] = v; -- args_t[k] = v; -- crude debug support that allows us to render a citation from module {{#invoke:}}; skips parameter validation; TODO: keep? end return _citation (frame, args_t, config_t) end --[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------ ]] return { citation = citation, -- template entry point _citation = _citation, -- module entry point } o0mp7ygqu5bibs2dabkkkkneiickrfx 736734 736721 2026-10-07T14:53:35Z King ChristLike 13051 7 revisions imported from [[:en:Module:Citation/CS1]] 736704 Scribunto text/plain require ('strict'); --[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- each of these counts against the Lua upvalue limit ]] local validation; -- functions in Module:Citation/CS1/Date_validation local utilities; -- functions in Module:Citation/CS1/Utilities local z = {}; -- table of tables in Module:Citation/CS1/Utilities local identifiers; -- functions and tables in Module:Citation/CS1/Identifiers local metadata; -- functions in Module:Citation/CS1/COinS local cfg = {}; -- table of configuration tables that are defined in Module:Citation/CS1/Configuration local whitelist = {}; -- table of tables listing valid template parameter names; defined in Module:Citation/CS1/Whitelist --[[------------------< P A G E S C O P E V A R I A B L E S >--------------- declare variables here that have page-wide scope that are not brought in from other modules; that are created here and used here ]] local added_deprecated_cat; -- boolean flag so that the category is added only once local added_vanc_errs; -- boolean flag so we only emit one Vancouver error / category local added_generic_name_errs; -- boolean flag so we only emit one generic name error / category and stop testing names once an error is encountered local added_numeric_name_errs; -- boolean flag so we only emit one numeric name error / category and stop testing names once an error is encountered local added_numeric_name_maint; -- boolean flag so we only emit one numeric name maint category and stop testing names once a category has been emitted local is_preview_mode; -- true when article is in preview mode; false when using 'Preview page with this template' (previewing the module) local is_sandbox; -- true when using sandbox modules to render citation local url_was_archive_today; -- boolean flag set to true when has_archive_today_url() has unset |url= because it held a deprecated archive.today url --[[--------------------------< F I R S T _ S E T >------------------------------------------------------------ Locates and returns the first set value in a table of values where the order established in the table, left-to-right (or top-to-bottom), is the order in which the values are evaluated. Returns nil if none are set. This version replaces the original 'for _, val in pairs do' and a similar version that used ipairs. With the pairs version the order of evaluation could not be guaranteed. With the ipairs version, a nil value would terminate the for-loop before it reached the actual end of the list. ]] local function first_set (list, count) local i = 1; while i <= count do -- loop through all items in list if utilities.is_set( list[i] ) then return list[i]; -- return the first set list member end i = i + 1; -- point to next end end --[[--------------------------< A D D _ V A N C _ E R R O R >---------------------------------------------------- Adds a single Vancouver system error message to the template's output regardless of how many error actually exist. To prevent duplication, added_vanc_errs is nil until an error message is emitted. added_vanc_errs is a Boolean declared in page scope variables above ]] local function add_vanc_error (source, position) if added_vanc_errs then return end added_vanc_errs = true; -- note that we've added this category utilities.set_message ('err_vancouver', {source, position}); end --[[--------------------------< I S _ S C H E M E >------------------------------------------------------------ does this thing that purports to be a URI scheme seem to be a valid scheme? The scheme is checked to see if it is in agreement with http://tools.ietf.org/html/std66#section-3.1 which says: Scheme names consist of a sequence of characters beginning with a letter and followed by any combination of letters, digits, plus ("+"), period ("."), or hyphen ("-"). returns true if it does, else false ]] local function is_scheme (scheme) return scheme and scheme:match ('^%a[%a%d%+%.%-]*:'); -- true if scheme is set and matches the pattern end --[=[-------------------------< I S _ D O M A I N _ N A M E >-------------------------------------------------- Does this thing that purports to be a domain name seem to be a valid domain name? Syntax defined here: http://tools.ietf.org/html/rfc1034#section-3.5 BNF defined here: https://tools.ietf.org/html/rfc4234 Single character names are generally reserved; see https://tools.ietf.org/html/draft-ietf-dnsind-iana-dns-01#page-15; see also [[Single-letter second-level domain]] list of TLDs: https://www.iana.org/domains/root/db RFC 952 (modified by RFC 1123) requires the first and last character of a hostname to be a letter or a digit (see http://tools.ietf.org/html/rfc952 §GRAMMATICAL HOST TABLE SPECIFICATION §§B. Lexical grammar <name>; see http://tools.ietf.org/html/rfc1123#section-2). Between the first and last characters the name may use letters, digits, and the hyphen. Also allowed are IPv4 addresses. IPv6 not supported domain is expected to be stripped of any path so that the last character in the last character of the TLD. tld is two or more alpha characters. Any preceding '//' (from splitting a URL with a scheme) will be stripped here. Perhaps not necessary but retained in case it is necessary for IPv4 dot decimal. There are several tests: the first character of the whole domain name including subdomains must be a letter or a digit internationalized domain name (ASCII characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the TLD) see https://tools.ietf.org/html/rfc3490 single-letter/digit second-level domains in the .org, .cash, and .today TLDs q, x, and z SL domains in the .com TLD i and q SL domains in the .net TLD single-letter SL domains in the ccTLDs (where the ccTLD is two letters) two-character SL domains in gTLDs (where the gTLD is two or more letters) three-plus-character SL domains in gTLDs (where the gTLD is two or more letters) IPv4 dot-decimal address format; TLD not allowed returns true if domain appears to be a proper name and TLD or IPv4 address, else false ]=] local function is_domain_name (domain) if not domain then return false; -- if not set, abandon end domain = domain:gsub ('^//', ''); -- strip '//' from domain name if present; done here so we only have to do it once local sl_domain = domain:match ('[^%.]+') or domain; -- test the second level domain name if not (sl_domain:match ('^%w') and sl_domain:match ('%w$') and -- first and last characters must be letter or digit sl_domain:match ('^[%w%-]+$')) then -- all other characters must be letters, digits, or hyphen-minus return false; end if domain:match ('^%a+:') then -- hack to detect things that look like s:Page:Title where Page: is namespace at Wikisource return false; end local patterns = { -- patterns that look like URLs '%f[%w][%w][%w%-]+[%w]%.%a%a+$', -- three or more character hostname.hostname or hostname.tld '%f[%w][%w][%w%-]+[%w]%.xn%-%-[%w]+$', -- internationalized domain name with ACE prefix '%f[%a][qxz]%.com$', -- assigned one character .com hostname (x.com times out 2015-12-10) '%f[%a][iq]%.net$', -- assigned one character .net hostname (q.net registered but not active 2015-12-10) '%f[%w][%w]%.%a%a$', -- one character hostname and ccTLD (2 chars) '%f[%w][%w][%w]%.%a%a+$', -- two character hostname and TLD '^%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?', -- IPv4 address '[%a%d]+%:?' -- IPv6 address } for _, pattern in ipairs (patterns) do -- loop through the patterns list if domain:match (pattern) then return true; -- if a match then we think that this thing that purports to be a URL is a URL end end for _, d in ipairs (cfg.single_letter_2nd_lvl_domains_t) do -- look for single letter second level domain names for these top level domains if domain:match ('%f[%w][%w]%.' .. d) then return true end end return false; -- no matches, we don't know what this thing is end --[[--------------------------< I S _ U R L >------------------------------------------------------------------ returns true if the scheme and domain parts of a URL appear to be a valid URL; else false. This function is the last step in the validation process. This function is separate because there are cases that are not covered by split_url(), for example is_parameter_ext_wikilink() which is looking for bracketted external wikilinks. ]] local function is_url (scheme, domain) if utilities.is_set (scheme) then -- if scheme is set check it and domain return is_scheme (scheme) and is_domain_name (domain); else return is_domain_name (domain); -- scheme not set when URL is protocol-relative end end --[[--------------------------< S P L I T _ U R L >------------------------------------------------------------ Split a URL into a scheme, authority indicator, and domain. First remove Fully Qualified Domain Name terminator (a dot following TLD) (if any) and any path(/), query(?) or fragment(#). If protocol-relative URL, return nil scheme and domain else return nil for both scheme and domain. When not protocol-relative, get scheme, authority indicator, and domain. If there is an authority indicator (one or more '/' characters immediately following the scheme's colon), make sure that there are only 2. Any URL that does not have news: scheme must have authority indicator (//). TODO: are there other common schemes like news: that don't use authority indicator? Strip off any port and path; ]] local function split_url (url_str) local scheme, authority, domain; url_str = url_str:gsub ('([%a%d])%.?[/%?#].*$', '%1'); -- strip FQDN terminator and path(/), query(?), fragment (#) (the capture prevents false replacement of '//') if url_str:match ('^//%S*') then -- if there is what appears to be a protocol-relative URL domain = url_str:match ('^//(%S*)') elseif url_str:match ('%S-:/*%S+') then -- if there is what appears to be a scheme, optional authority indicator, and domain name scheme, authority, domain = url_str:match ('(%S-:)(/*)(%S+)'); -- extract the scheme, authority indicator, and domain portions if utilities.is_set (authority) then authority = authority:gsub ('//', '', 1); -- replace place 1 pair of '/' with nothing; if utilities.is_set(authority) then -- if anything left (1 or 3+ '/' where authority should be) then return scheme; -- return scheme only making domain nil which will cause an error message end else if not scheme:match ('^news:') then -- except for news:..., MediaWiki won't link URLs that do not have authority indicator; TODO: a better way to do this test? return scheme; -- return scheme only making domain nil which will cause an error message end end domain = domain:gsub ('(%a):%d+', '%1'); -- strip port number if present end return scheme, domain; end --[[--------------------------< L I N K _ P A R A M _ O K >--------------------------------------------------- checks the content of |title-link=, |series-link=, |author-link=, etc. for properly formatted content: no wikilinks, no URLs Link parameters are to hold the title of a Wikipedia article, so none of the WP:TITLESPECIALCHARACTERS are allowed: # < > [ ] | { } _ except the underscore which is used as a space in wiki URLs and # which is used for section links returns false when the value contains any of these characters. When there are no illegal characters, this function returns TRUE if value DOES NOT appear to be a valid URL (the |<param>-link= parameter is ok); else false when value appears to be a valid URL (the |<param>-link= parameter is NOT ok). ]] local function link_param_ok (value) local scheme, domain; if value:find ('[<>%[%]|{}]') then -- if any prohibited characters return false; end scheme, domain = split_url (value); -- get scheme or nil and domain or nil from URL; return not is_url (scheme, domain); -- return true if value DOES NOT appear to be a valid URL end --[[--------------------------< L I N K _ T I T L E _ O K >--------------------------------------------------- Use link_param_ok() to validate |<param>-link= value and its matching |<title>= value. |<title>= may be wiki-linked but not when |<param>-link= has a value. This function emits an error message when that condition exists check <link> for inter-language interwiki-link prefix. prefix must be a MediaWiki-recognized language code and must begin with a colon. ]] local function link_title_ok (link, lorig, title, torig) local orig; if utilities.is_set (link) then -- don't bother if <param>-link doesn't have a value if not link_param_ok (link) then -- check |<param>-link= markup orig = lorig; -- identify the failing link parameter elseif title:find ('%[%[') then -- check |title= for wikilink markup orig = torig; -- identify the failing |title= parameter elseif link:match ('^%a+:') then -- if the link is what looks like an interwiki local prefix = link:match ('^(%a+):'):lower(); -- get the interwiki prefix if cfg.inter_wiki_map[prefix] then -- if prefix is in the map, must have preceding colon orig = lorig; -- flag as error end end end if utilities.is_set (orig) then link = ''; -- unset utilities.set_message ('err_bad_paramlink', orig); -- URL or wikilink in |title= with |title-link=; end return link; -- link if ok, empty string else end --[[--------------------------< C H E C K _ U R L >------------------------------------------------------------ Determines whether a URL string appears to be valid. First we test for space characters. If any are found, return false. Then split the URL into scheme and domain portions, or for protocol-relative (//example.com) URLs, just the domain. Use is_url() to validate the two portions of the URL. If both are valid, or for protocol-relative if domain is valid, return true, else false. Because it is different from a standard URL, and because this module used external_link() to make external links that work for standard and news: links, we validate newsgroup names here. The specification for a newsgroup name is at https://tools.ietf.org/html/rfc5536#section-3.1.4 ]] local function check_url( url_str ) if nil == url_str:match ("^%S+$") then -- if there are any spaces in |url=value it can't be a proper URL return false; end local scheme, domain; scheme, domain = split_url (url_str); -- get scheme or nil and domain or nil from URL; if 'news:' == scheme then -- special case for newsgroups return domain:match('^[%a%d%+%-_]+%.[%a%d%+%-_%.]*[%a%d%+%-_]$'); end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[=[-------------------------< I S _ P A R A M E T E R _ E X T _ W I K I L I N K >---------------------------- Return true if a parameter value has a string that begins and ends with square brackets [ and ] and the first non-space characters following the opening bracket appear to be a URL. The test will also find external wikilinks that use protocol-relative URLs. Also finds bare URLs. The frontier pattern prevents a match on interwiki-links which are similar to scheme:path URLs. The tests that find bracketed URLs are required because the parameters that call this test (currently |title=, |chapter=, |work=, and |publisher=) may have wikilinks and there are articles or redirects like '//Hus' so, while uncommon, |title=[[//Hus]] is possible as might be [[en://Hus]]. ]=] local function is_parameter_ext_wikilink (value) local scheme, domain; if value:match ('%f[%[]%[%a%S*:%S+.*%]') then -- if ext. wikilink with scheme and domain: [xxxx://yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(%a%S*:%S+).*%]')); elseif value:match ('%f[%[]%[//%S+.*%]') then -- if protocol-relative ext. wikilink: [//yyyyy.zzz] scheme, domain = split_url (value:match ('%f[%[]%[(//%S+).*%]')); elseif value:match ('%a%S*:%S+') then -- if bare URL with scheme; may have leading or trailing plain text scheme, domain = split_url (value:match ('(%a%S*:%S+)')); elseif value:match ('^//%S+') or value:match ('%s//%S+') then -- if protocol-relative bare URL: //yyyyy.zzz; authority indicator (//) must be be preceded nothing or by whitespace scheme, domain = split_url (value:match ('(//%S+)')); -- what is left should be the domain else return false; -- didn't find anything that is obviously a URL end return is_url (scheme, domain); -- return true if value appears to be a valid URL end --[[--------------------------< I S _ A R C H I V E _ T O D A Y _ U R L >-------------------------------------- archive.today (and .ph, .is, .md, .li, .fo, .vn) are deprecated. See Wikipedia:Requests_for_comment/Archive.is_RFC_5 (Special:Permalink/1339352976) <val> is a string that may or may not be a url ]] local function is_archive_today_url (val) if is_parameter_ext_wikilink (val) then -- is <val> a url? local tld = val:match ('archive%.(%l+)/'); -- get the tld; real archive.today urls have a '/' after the tld return tld and cfg.archive_today_tlds_t[tld]; -- return true if <tld> is one of the archive.today tlds; nil else end end --[[--------------------------< H A S _ A R C H I V E _ T O D A Y _ U R L >------------------------------------ blank any parameter that holds one of the archive.today tlds (.today, .ph, .is, .md, .li, .fo, .vn) and also blank parameters that are dependent on the offending parameter. input <cite_args_t> is a table of all of this template's parameters This function modifies <cite_args_t> when |url= or its alias |URL= hold an archive.today url, this function sets the flag <url_was_archive_today> which is used later to suppress the missing url error message from {{citation}} when it has |website=<summat> or from the templates {{cite web}}, {{cite podcast}}, {{cite mailing list}} which all require a url. returns nothing ]] local function has_archive_today_url (cite_args_t) local unset_params_t = {}; -- to hold a sequence of parameters to unset from cite_args_t for p, v in pairs (cite_args_t) do -- look at each parameter in the template if is_archive_today_url (v:lower()) then -- if it has a parameter with an archive.today url table.insert (unset_params_t, p); -- add the url-holding parameter name to our list of parameters to unset (may or may not be a legitimate url parameter) if 'url' == p:lower() then -- if this parameter is |url= or |URL= url_was_archive_today = true; -- set a flag so that cite web / podcast / mailinglist don't emit a missing url error message end if p:match ('archive%-?url') and ('usurped' == cite_args_t['url-status'] or 'unfit' == cite_args_t['url-status']) then -- if |archive-url=archive.today and |url-status=unfit/usurped url_was_archive_today = true; -- set a flag so that cite web / podcast / mailinglist don't emit a missing url error message table.insert (unset_params_t, 'url'); -- add the url parameter name to our list of parameters to unset (may or may not be a legitimate url parameter) table.insert (unset_params_t, 'URL'); -- this one because both are possible end if cfg.dependencies_t[p] then -- if this url-holding parameter (<p>) has dependencies for _, dependent in ipairs (cfg.dependencies_t[p]) do -- loop through the url-holding parameter's dependency sequence table.insert (unset_params_t, dependent); -- add dependent parameter to the list to be unset end end end end if 0 < #unset_params_t then -- when there are parameters to unset if not is_preview_mode then -- when in preview mode do not suppress any parameters for _, unset_param in ipairs (unset_params_t) do -- loop through the sequence cite_args_t[unset_param] = nil; -- and unset the url-holding parameter and its dependent parameters to avoid parameter-requires-other-parameter errors end end utilities.set_message ('maint_deprecated_archive'); -- add a maintenance message end end --[[-------------------------< C H E C K _ F O R _ U R L >----------------------------------------------------- loop through a list of parameters and their values. Look at the value and if it has an external link, emit an error message. ]] local function check_for_url (parameter_list, error_list) for k, v in pairs (parameter_list) do -- for each parameter in the list if is_parameter_ext_wikilink (v) then -- look at the value; if there is a URL add an error message table.insert (error_list, utilities.wrap_style ('parameter', k)); end end end --[[--------------------------< S A F E _ F O R _ U R L >------------------------------------------------------ Escape sequences for content that will be used for URL descriptions ]] local function safe_for_url( str ) if str:match( "%[%[.-%]%]" ) ~= nil then utilities.set_message ('err_wikilink_in_url', {}); end return str:gsub( '[%[%]\n]', { ['['] = '&#91;', [']'] = '&#93;', ['\n'] = ' ' } ); end --[[--------------------------< E X T E R N A L _ L I N K >---------------------------------------------------- Format an external link with error checking ]] local function external_link (URL, label, source, access) local domain; local path; local base_url; if not utilities.is_set (label) then label = URL; if utilities.is_set (source) then utilities.set_message ('err_bare_url_missing_title', {utilities.wrap_style ('parameter', source)}); else error (cfg.messages["bare_url_no_origin"]); -- programmer error; valid parameter name does not have matching meta-parameter end end if not check_url (URL) then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); end domain, path = URL:match ('^([/%.%-%+:%a%d]+)([/%?#].*)$'); -- split the URL into scheme plus domain and path if path then -- if there is a path portion path = path:gsub ('[%[%]]', {['['] = '%5b', [']'] = '%5d'}); -- replace '[' and ']' with their percent-encoded values URL = table.concat ({domain, path}); -- and reassemble end base_url = table.concat ({ "[", URL, " ", safe_for_url (label), "]" }); -- assemble a wiki-markup URL if utilities.is_set (access) then -- access level (subscription, registration, limited) base_url = utilities.substitute (cfg.presentation['ext-link-access-signal'], {cfg.presentation[access].class, cfg.presentation[access].title, base_url}); -- add the appropriate icon end return base_url; end --[[--------------------------< D E P R E C A T E D _ P A R A M E T E R >-------------------------------------- Categorize and emit an error message when the citation contains one or more deprecated parameters. The function includes the offending parameter name to the error message. Only one error message is emitted regardless of the number of deprecated parameters in the citation. added_deprecated_cat is a Boolean declared in page scope variables above ]] local function deprecated_parameter(name) if not added_deprecated_cat then added_deprecated_cat = true; -- note that we've added this category utilities.set_message ('err_deprecated_params', {name}); -- add error message end end --[=[-------------------------< K E R N _ Q U O T E S >-------------------------------------------------------- Apply kerning to open the space between the quote mark provided by the module and a leading or trailing quote mark contained in a |title= or |chapter= parameter's value. This function will positive kern either single or double quotes: "'Unkerned title with leading and trailing single quote marks'" " 'Kerned title with leading and trailing single quote marks' " (in real life the kerning isn't as wide as this example) Double single quotes (italic or bold wiki-markup) are not kerned. Replaces Unicode quote marks in plain text or in the label portion of a [[L|D]] style wikilink with typewriter quote marks regardless of the need for kerning. Unicode quote marks are not replaced in simple [[D]] wikilinks. Call this function for chapter titles, for website titles, etc.; not for book titles. ]=] local function kern_quotes (str) local wl_type, label, link; wl_type, label, link = utilities.is_wikilink (str); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] if 1 == wl_type then -- [[D]] simple wikilink with or without quote marks if mw.ustring.match (str, '%[%[[\"“”\'‘’].+[\"“”\'‘’]%]%]') then -- leading and trailing quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); str = utilities.substitute (cfg.presentation['kern-right'], str); elseif mw.ustring.match (str, '%[%[[\"“”\'‘’].+%]%]') then -- leading quote marks str = utilities.substitute (cfg.presentation['kern-left'], str); elseif mw.ustring.match (str, '%[%[.+[\"“”\'‘’]%]%]') then -- trailing quote marks str = utilities.substitute (cfg.presentation['kern-right'], str); end else -- plain text or [[L|D]]; text in label variable label = mw.ustring.gsub (label, '[“”]', '\"'); -- replace “” (U+201C & U+201D) with " (typewriter double quote mark) label = mw.ustring.gsub (label, '[‘’]', '\''); -- replace ‘’ (U+2018 & U+2019) with ' (typewriter single quote mark) local cap = mw.ustring.match (label, "^([\"\'][^\'].+)"); -- match leading double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-left'], cap); end cap = mw.ustring.match (label, "^(.+[^\'][\"\'])$") -- match trailing double or single quote but not doubled single quotes (italic markup) if utilities.is_set (cap) then label = utilities.substitute (cfg.presentation['kern-right'], cap); end if 2 == wl_type then str = utilities.make_wikilink (link, label); -- reassemble the wikilink else str = label; end end return str; end --[[--------------------------< F O R M A T _ S C R I P T _ V A L U E >---------------------------------------- |script-title= holds title parameters that are not written in Latin-based scripts: Chinese, Japanese, Arabic, Hebrew, etc. These scripts should not be italicized and may be written right-to-left. The value supplied by |script-title= is concatenated onto Title after Title has been wrapped in italic markup. Regardless of language, all values provided by |script-title= are wrapped in <bdi>...</bdi> tags to isolate RTL languages from the English left to right. |script-title= provides a unique feature. The value in |script-title= may be prefixed with a two-character ISO 639-1 language code and a colon: |script-title=ja:*** *** (where * represents a Japanese character) Spaces between the two-character code and the colon and the colon and the first script character are allowed: |script-title=ja : *** *** |script-title=ja: *** *** |script-title=ja :*** *** Spaces preceding the prefix are allowed: |script-title = ja:*** *** The prefix is checked for validity. If it is a valid ISO 639-1 language code, the lang attribute (lang="ja") is added to the <bdi> tag so that browsers can know the language the tag contains. This may help the browser render the script more correctly. If the prefix is invalid, the lang attribute is not added. At this time there is no error message for this condition. Supports |script-title=, |script-chapter=, |script-<periodical>= ]] local function format_script_value (script_value, script_param) local lang=''; -- initialize to empty string local name; if script_value:match('^%l%l%l?%s*:') then -- if first 3 or 4 non-space characters are script language prefix lang = script_value:match('^(%l%l%l?)%s*:%s*%S.*'); -- get the language prefix or nil if there is no script if not utilities.is_set (lang) then utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing title part']}); -- prefix without 'title'; add error message return ''; -- script_value was just the prefix so return empty string end -- if we get this far we have prefix and script name = cfg.lang_tag_remap[lang] or mw.language.fetchLanguageName( lang, cfg.this_wiki_code ); -- get language name so that we can use it to categorize if utilities.is_set (name) then -- is prefix a proper ISO 639-1 language code? script_value = script_value:gsub ('^%l+%s*:%s*', ''); -- strip prefix from script -- is prefix one of these language codes? if utilities.in_array (lang, cfg.script_lang_codes) then utilities.add_prop_cat ('script', {name, lang}) else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['unknown language code']}); -- unknown script-language; add error message end lang = ' lang="' .. lang .. '" '; -- convert prefix into a lang attribute else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['invalid language code']}); -- invalid language code; add error message lang = ''; -- invalid so set lang to empty string end else utilities.set_message ('err_script_parameter', {script_param, cfg.err_msg_supl['missing prefix']}); -- no language code prefix; add error message end script_value = utilities.substitute (cfg.presentation['bdi'], {lang, script_value}); -- isolate in case script is RTL return script_value; end --[[--------------------------< S C R I P T _ C O N C A T E N A T E >------------------------------------------ Initially for |title= and |script-title=, this function concatenates those two parameter values after the script value has been wrapped in <bdi> tags. ]] local function script_concatenate (title, script, script_param) if utilities.is_set (script) then script = format_script_value (script, script_param); -- <bdi> tags, lang attribute, categorization, etc.; returns empty string on error if utilities.is_set (script) then title = title .. ' ' .. script; -- concatenate title and script title end end return title; end --[[--------------------------< W R A P _ M S G >-------------------------------------------------------------- Applies additional message text to various parameter values. Supplied string is wrapped using a message_list configuration taking one argument. Supports lower case text for {{citation}} templates. Additional text taken from citation_config.messages - the reason this function is similar to but separate from wrap_style(). ]] local function wrap_msg (key, str, lower) if not utilities.is_set ( str ) then return ""; end if true == lower then local msg; msg = cfg.messages[key]:lower(); -- set the message to lower case before return utilities.substitute ( msg, str ); -- including template text else return utilities.substitute ( cfg.messages[key], str ); end end --[[----------------< W I K I S O U R C E _ U R L _ M A K E >------------------- Makes a Wikisource URL from Wikisource interwiki-link. Returns the URL and appropriate label; nil else. str is the value assigned to |chapter= (or aliases) or |title= or |title-link= ]] local function wikisource_url_make (str) local wl_type, D, L; local ws_url, ws_label; local wikisource_prefix = table.concat ({'https://', cfg.this_wiki_code, '.wikisource.org/wiki/'}); wl_type, D, L = utilities.is_wikilink (str); -- wl_type is 0 (not a wikilink), 1 (simple wikilink), 2 (complex wikilink) if 0 == wl_type then -- not a wikilink; might be from |title-link= str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 1 == wl_type then -- simple wikilink: [[Wikisource:ws article]] str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title }); ws_label = str; -- label for the URL end elseif 2 == wl_type then -- non-so-simple wikilink: [[Wikisource:ws article|displayed text]] ([[L|D]]) str = L:match ('^[Ww]ikisource:(.+)') or L:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace if utilities.is_set (str) then ws_label = D; -- get ws article name from display portion of interwiki link ws_url = table.concat ({ -- build a Wikisource URL wikisource_prefix, -- prefix str, -- article title without namespace from link portion of wikilink }); end end if ws_url then ws_url = mw.uri.encode (ws_url, 'WIKI'); -- make a usable URL ws_url = ws_url:gsub ('%%23', '#'); -- undo percent-encoding of fragment marker end return ws_url, ws_label, L or D; -- return proper URL or nil and a label or nil end --[[----------------< F O R M A T _ P E R I O D I C A L >----------------------- Format the three periodical parameters: |script-<periodical>=, |<periodical>=, and |trans-<periodical>= into a single Periodical meta-parameter. ]] local function format_periodical (script_periodical, script_periodical_source, periodical, trans_periodical) if not utilities.is_set (periodical) then periodical = ''; -- to be safe for concatenation else periodical = utilities.wrap_style ('italic-title', periodical); -- style end periodical = script_concatenate (periodical, script_periodical, script_periodical_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (trans_periodical) then trans_periodical = utilities.wrap_style ('trans-italic-title', trans_periodical); if utilities.is_set (periodical) then periodical = periodical .. ' ' .. trans_periodical; else -- here when trans-periodical without periodical or script-periodical periodical = trans_periodical; utilities.set_message ('err_trans_missing_title', {'periodical'}); end end return periodical; end --[[------------------< F O R M A T _ C H A P T E R _ T I T L E >--------------- Format the four chapter parameters: |script-chapter=, |chapter=, |trans-chapter=, and |chapter-url= into a single chapter meta- parameter (chapter_url_source used for error messages). ]] local function format_chapter_title (script_chapter, script_chapter_source, chapter, trans_chapter, trans_chapter_source, chapter_url, chapter_url_source, no_quotes, access) local ws_url, ws_label, L = wikisource_url_make (chapter); -- make a wikisource URL and label from a wikisource interwiki link if ws_url then ws_label = ws_label:gsub ('_', ' '); -- replace underscore separators with space characters chapter = ws_label; end if not utilities.is_set (chapter) then chapter = ''; -- to be safe for concatenation else if false == no_quotes then chapter = kern_quotes (chapter); -- if necessary, separate chapter title's leading and trailing quote marks from module provided quote marks chapter = utilities.wrap_style ('quoted-title', chapter); end end chapter = script_concatenate (chapter, script_chapter, script_chapter_source); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped if utilities.is_set (chapter_url) then chapter = external_link (chapter_url, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate elseif ws_url then chapter = external_link (ws_url, chapter .. '&nbsp;', 'ws link in chapter'); -- adds bare_url_missing_title error if appropriate; space char to move icon away from chap text; TODO: better way to do this? chapter = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, chapter}); end if utilities.is_set (trans_chapter) then trans_chapter = utilities.wrap_style ('trans-quoted-title', trans_chapter); if utilities.is_set (chapter) then chapter = chapter .. ' ' .. trans_chapter; else -- here when trans_chapter without chapter or script-chapter chapter = trans_chapter; utilities.set_message ('err_trans_missing_title', {trans_chapter_source:match ('trans%-?(.+)')}); -- when no chapter, get matching name from trans-<param> end end return chapter; end --[[----------------< H A S _ I N V I S I B L E _ C H A R S >------------------- This function searches a parameter's value for non-printable or invisible characters. The search stops at the first match. This function will detect the visible replacement character when it is part of the Wikisource. Detects but ignores nowiki and math stripmarkers. Also detects other named stripmarkers (gallery, math, pre, ref) and identifies them with a slightly different error message. See also coins_cleanup(). Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker that was detected along with its position (or, for multi-byte characters, the position of its first byte) in the parameter value. ]] local function has_invisible_chars (param, v) local position; -- position of invisible char or starting position of stripmarker local capture; -- used by stripmarker detection to hold name of the stripmarker local stripmarker; -- boolean set true when a stripmarker is found capture = string.match (v, '[%w%p ]*'); -- test for values that are simple ASCII text and bypass other tests if true if capture == v then -- if same there are no Unicode characters return; end for _, invisible_char in ipairs (cfg.invisible_chars) do local char_name = invisible_char[1]; -- the character or group name local pattern = invisible_char[2]; -- the pattern used to find it position, _, capture = mw.ustring.find (v, pattern); -- see if the parameter value contains characters that match the pattern if position and (cfg.invisible_defs.zwj == capture) then -- if we found a zero-width joiner character if mw.ustring.find (v, cfg.indic_script) then -- it's ok if one of the Indic scripts position = nil; -- unset position elseif cfg.emoji_t[mw.ustring.codepoint (v, position+1)] then -- is zwj followed by a character listed in emoji{}? position = nil; -- unset position end end if position then if 'nowiki' == capture or 'math' == capture or -- nowiki and math stripmarkers (not an error condition) ('templatestyles' == capture and utilities.in_array (param, {'id', 'quote'})) then -- templatestyles stripmarker allowed in these parameters stripmarker = true; -- set a flag elseif true == stripmarker and cfg.invisible_defs.del == capture then -- because stripmakers begin and end with the delete char, assume that we've found one end of a stripmarker position = nil; -- unset; for now, ignore linter warning else local err_msg; if capture and not (cfg.invisible_defs.del == capture or cfg.invisible_defs.zwj == capture) then err_msg = utilities.substitute (cfg.messages.invisible_1, {capture, char_name}); -- <capture> here is stripmarker name else err_msg = utilities.substitute (cfg.messages.invisible_2, char_name); end utilities.set_message ('err_invisible_char', {err_msg, utilities.wrap_style ('parameter', param), position}); -- add error message return; -- and done with this parameter end end end end --[[-------------------< A R G U M E N T _ W R A P P E R >---------------------- Argument wrapper. This function provides support for argument mapping defined in the configuration file so that multiple names can be transparently aliased to single internal variable. ]] local function argument_wrapper ( args ) local origin = {}; return setmetatable({ ORIGIN = function ( self, k ) local dummy = self[k]; -- force the variable to be loaded; for now, ignore linter warning return origin[k]; end }, { __index = function ( tbl, k ) if origin[k] ~= nil then return nil; end local v; local list = cfg.aliases[k]; if type( list ) == 'table' then v, origin[k] = utilities.select_one ( args, list, 'err_redundant_parameters' ); if origin[k] == nil then origin[k] = ''; -- Empty string, not nil end elseif list ~= nil then v, origin[k] = args[list], list; else -- maybe let through instead of raising an error? -- v, origin[k] = args[k], k; error( cfg.messages['unknown_argument_map'] .. ': ' .. k); end -- Empty strings, not nil; if v == nil then v = ''; origin[k] = ''; end -- tbl = rawset( tbl, k, v ); rawset( tbl, k, v ); return v; end, }); end --[[--------------------------< N O W R A P _ D A T E >------------------------- When date is YYYY-MM-DD format wrap in nowrap span: <span ...>YYYY-MM-DD</span>. When date is DD MMMM YYYY or is MMMM DD, YYYY then wrap in nowrap span: <span ...>DD MMMM</span> YYYY or <span ...>MMMM DD,</span> YYYY DOES NOT yet support MMMM YYYY or any of the date ranges. ]] local function nowrap_date (date) local cap; local cap2; if date:match("^%d%d%d%d%-%d%d%-%d%d$") then date = utilities.substitute (cfg.presentation['nowrap1'], date); elseif date:match("^%a+%s*%d%d?,%s+%d%d%d%d$") or date:match ("^%d%d?%s*%a+%s+%d%d%d%d$") then cap, cap2 = string.match (date, "^(.*)%s+(%d%d%d%d)$"); date = utilities.substitute (cfg.presentation['nowrap2'], {cap, cap2}); end return date; end --[[--------------------------< S E T _ T I T L E T Y P E >--------------------- This function sets default title types (equivalent to the citation including |type=<default value>) for those templates that have defaults. Also handles the special case where it is desirable to omit the title type from the rendered citation (|type=none). ]] local function set_titletype (cite_class, title_type) if utilities.is_set (title_type) then if 'none' == cfg.keywords_xlate[title_type] then title_type = ''; -- if |type=none then type parameter not displayed end return title_type; -- if |type= has been set to any other value use that value end return cfg.title_types [cite_class] or ''; -- set template's default title type; else empty string for concatenation end --[[--------------------------< S A F E _ J O I N >----------------------------- Joins a sequence of strings together while checking for duplicate separation characters. ]] local function safe_join( tbl, duplicate_char ) local f = {}; -- create a function table appropriate to type of 'duplicate character' if 1 == #duplicate_char then -- for single byte ASCII characters use the string library functions f.gsub = string.gsub f.match = string.match f.sub = string.sub else -- for multi-byte characters use the ustring library functions f.gsub = mw.ustring.gsub f.match = mw.ustring.match f.sub = mw.ustring.sub end local str = ''; -- the output string for _, value in ipairs( tbl ) do if value == nil then value = ''; end if str == '' then -- if output string is empty str = value; -- assign value to it (first time through the loop) elseif value ~= '' then local comp; -- what does 'comp' mean? if value:sub(1, 1) == '<' then -- special case of values enclosed in spans and other markup. comp = value:gsub( "%b<>", "" ); -- remove HTML markup (<span>string</span> -> string) else comp = value; end -- typically duplicate_char is sepc if f.sub(comp, 1, 1) == duplicate_char then -- is first character same as duplicate_char? why test first character? -- Because individual string segments often (always?) begin with terminal punct for the -- preceding segment: 'First element' .. 'sepc next element' .. etc.? local trim = false; local end_chr = f.sub(str, -1, -1); -- get the last character of the output string -- str = str .. "<HERE(enchr=" .. end_chr .. ")" -- debug stuff? if end_chr == duplicate_char then -- if same as separator str = f.sub(str, 1, -2); -- remove it elseif end_chr == "'" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "''" then -- if last three chars of str are sepc'' str = f.sub(str, 1, -4) .. "''"; -- remove them and add back '' elseif f.sub(str, -5, -1) == duplicate_char .. "]]''" then -- if last five chars of str are sepc]]'' trim = true; -- why? why do this and next differently from previous? elseif f.sub(str, -4, -1) == duplicate_char .. "]''" then -- if last four chars of str are sepc]'' trim = true; -- same question end elseif end_chr == "]" then -- if it might be wiki-markup if f.sub(str, -3, -1) == duplicate_char .. "]]" then -- if last three chars of str are sepc]] wikilink trim = true; elseif f.sub(str, -3, -1) == duplicate_char .. '"]' then -- if last three chars of str are sepc"] quoted external link trim = true; elseif f.sub(str, -2, -1) == duplicate_char .. "]" then -- if last two chars of str are sepc] external link trim = true; elseif f.sub(str, -4, -1) == duplicate_char .. "'']" then -- normal case when |url=something & |title=Title. trim = true; end elseif end_chr == " " then -- if last char of output string is a space if f.sub(str, -2, -1) == duplicate_char .. " " then -- if last two chars of str are <sepc><space> str = f.sub(str, 1, -3); -- remove them both end end if trim then if value ~= comp then -- value does not equal comp when value contains HTML markup local dup2 = duplicate_char; if f.match(dup2, "%A" ) then dup2 = "%" .. dup2; end -- if duplicate_char not a letter then escape it value = f.gsub(value, "(%b<>)" .. dup2, "%1", 1 ) -- remove duplicate_char if it follows HTML markup else value = f.sub(value, 2, -1 ); -- remove duplicate_char when it is first character end end end str = str .. value; -- add it to the output string end end return str; end --[[--------------------------< I S _ S U F F I X >----------------------------- returns true if suffix is properly formed Jr, Sr, or ordinal in the range 1–9. Puncutation not allowed. ]] local function is_suffix (suffix) if utilities.in_array (suffix, {'Jr', 'Sr', 'Jnr', 'Snr', '1st', '2nd', '3rd'}) or suffix:match ('^%dth$') then return true; end return false; end --[[--------------------< I S _ G O O D _ V A N C _ N A M E >------------------- For Vancouver style, author/editor names are supposed to be rendered in Latin (read ASCII) characters. When a name uses characters that contain diacritical marks, those characters are to be converted to the corresponding Latin character. When a name is written using a non-Latin alphabet or logogram, that name is to be transliterated into Latin characters. The module doesn't do this so editors may/must. This test allows |first= and |last= names to contain any of the letters defined in the four Unicode Latin character sets [http://www.unicode.org/charts/PDF/U0000.pdf C0 Controls and Basic Latin] 0041–005A, 0061–007A [http://www.unicode.org/charts/PDF/U0080.pdf C1 Controls and Latin-1 Supplement] 00C0–00D6, 00D8–00F6, 00F8–00FF [http://www.unicode.org/charts/PDF/U0100.pdf Latin Extended-A] 0100–017F [http://www.unicode.org/charts/PDF/U0180.pdf Latin Extended-B] 0180–01BF, 01C4–024F |lastn= also allowed to contain hyphens, spaces, and apostrophes. (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) |firstn= also allowed to contain hyphens, spaces, apostrophes, and periods This original test: if nil == mw.ustring.find (last, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%'%.]+[2-6%a]*$") then was written outside of the code editor and pasted here because the code editor gets confused between character insertion point and cursor position. The test has been rewritten to use decimal character escape sequence for the individual bytes of the Unicode characters so that it is not necessary to use an external editor to maintain this code. \195\128-\195\150 – À-Ö (U+00C0–U+00D6 – C0 controls) \195\152-\195\182 – Ø-ö (U+00D8-U+00F6 – C0 controls) \195\184-\198\191 – ø-ƿ (U+00F8-U+01BF – C0 controls, Latin extended A & B) \199\132-\201\143 – DŽ-ɏ (U+01C4-U+024F – Latin extended B) ]] local function is_good_vanc_name (last, first, suffix, position) if not suffix then if first:find ('[,%s]') then -- when there is a space or comma, might be first name/initials + generational suffix first = first:match ('(.-)[,%s]+'); -- get name/initials suffix = first:match ('[,%s]+(.+)$'); -- get generational suffix end end if utilities.is_set (suffix) then if not is_suffix (suffix) then add_vanc_error (cfg.err_msg_supl.suffix, position); return false; -- not a name with an appropriate suffix end end if nil == mw.ustring.find (last, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%'%.]*$") then add_vanc_error (cfg.err_msg_supl['non-Latin char'], position); return false; -- not a string of Latin characters; Vancouver requires Romanization end; return true; end --[[--------------------------< R E D U C E _ T O _ I N I T I A L S >------------------------------------------ Attempts to convert names to initials in support of |name-list-style=vanc. Names in |firstn= may be separated by spaces or hyphens, or for initials, a period. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35062/. Vancouver style requires family rank designations (Jr, II, III, etc.) to be rendered as Jr, 2nd, 3rd, etc. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35085/. This code only accepts and understands generational suffix in the Vancouver format because Roman numerals look like, and can be mistaken for, initials. This function uses ustring functions because firstname initials may be any of the Unicode Latin characters accepted by is_good_vanc_name (). ]] local function reduce_to_initials (first, position) if first:find (',', 1, true) then return first; -- commas not allowed; abandon end local name, suffix = mw.ustring.match (first, "^(%u+) ([%dJS][%drndth]+)$"); if not name then -- if not initials and a suffix name = mw.ustring.match (first, "^(%u+)$"); -- is it just initials? end if name then -- if first is initials with or without suffix if 3 > mw.ustring.len (name) then -- if one or two initials if suffix then -- if there is a suffix if is_suffix (suffix) then -- is it legitimate? return first; -- one or two initials and a valid suffix so nothing to do else add_vanc_error (cfg.err_msg_supl.suffix, position); -- one or two initials with invalid suffix so error message return first; -- and return first unmolested end else return first; -- one or two initials without suffix; nothing to do end end end -- if here then name has 3 or more uppercase letters so treat them as a word local initials_t = {}; -- table to hold initials local i = 1; -- counter for number of initials local names_t = mw.text.split (first, '[%s%-]+'); -- split into a sequence of names and possible suffix while names_t[i] do -- loop through the sequence if 1 < i and names_t[i]:match ('[%dJS][%drndth]+%.?$') then -- if not the first name, and looks like a suffix (may have trailing dot) names_t[i] = names_t[i]:gsub ('%.', ''); -- remove terminal dot if present if is_suffix (names_t[i]) then -- if a legitimate suffix table.insert (initials_t, ' ' .. names_t[i]); -- add a separator space, insert at end of initials sequence break; -- and done because suffix must fall at the end of a name end -- no error message if not a suffix; possibly because of Romanization end if 3 > i then table.insert (initials_t, mw.ustring.sub (names_t[i], 1, 1)); -- insert the initial at end of initials sequence end i = i + 1; -- bump the counter end return table.concat (initials_t); -- Vancouver format does not include spaces. end --[[--------------------------< I N T E R W I K I _ P R E F I X E N _ G E T >---------------------------------- extract interwiki prefixen from <value>. Returns two one or two values: false – no prefixen nil – prefix exists but not recognized project prefix, language prefix – when value has either of: :<project>:<language>:<article> :<language>:<project>:<article> project prefix, nil – when <value> has only a known single-letter prefix nil, language prefix – when <value> has only a known language prefix accepts single-letter project prefixen: 'd' (wikidata), 's' (wikisource), and 'w' (wikipedia) prefixes; at this writing, the other single-letter prefixen (b (wikibook), c (commons), m (meta), n (wikinews), q (wikiquote), and v (wikiversity)) are not supported. ]] local function interwiki_prefixen_get (value, is_link) if not value:find (':%l+:') then -- if no prefix return false; -- abandon; boolean here to distinguish from nil fail returns later end local prefix_patterns_linked_t = { -- sequence of valid interwiki and inter project prefixen '^%[%[:([dsw]):(%l%l+):', -- wikilinked; project and language prefixes '^%[%[:(%l%l+):([dsw]):', -- wikilinked; language and project prefixes '^%[%[:([dsw]):', -- wikilinked; project prefix '^%[%[:(%l%l+):', -- wikilinked; language prefix } local prefix_patterns_unlinked_t = { -- sequence of valid interwiki and inter project prefixen '^:([dsw]):(%l%l+):', -- project and language prefixes '^:(%l%l+):([dsw]):', -- language and project prefixes '^:([dsw]):', -- project prefix '^:(%l%l+):', -- language prefix } local cap1, cap2; for _, pattern in ipairs ((is_link and prefix_patterns_linked_t) or prefix_patterns_unlinked_t) do cap1, cap2 = value:match (pattern); if cap1 then break; -- found a match so stop looking end end if cap1 and cap2 then -- when both then :project:language: or :language:project: (both forms allowed) if 1 == #cap1 then -- length == 1 then :project:language: if cfg.inter_wiki_map[cap2] then -- is language prefix in the interwiki map? return cap1, cap2; -- return interwiki project and interwiki language end else -- here when :language:project: if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return cap2, cap1; -- return interwiki project and interwiki language end end return nil; -- unknown interwiki language elseif not (cap1 or cap2) then -- both are nil? return nil; -- we got something that looks like a project prefix but isn't; return fail elseif 1 == #cap1 then -- here when one capture return cap1, nil; -- length is 1 so return project, nil language else -- here when one capture and its length it more than 1 if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map? return nil, cap1; -- return nil project, language end end end --[[--------------------------< L I S T _ P E O P L E >-------------------------- Formats a list of people (authors, contributors, editors, interviewers, translators) names in the list will be linked when |<name>-link= has a value |<name>-mask- does NOT have a value; masked names are presumed to have been rendered previously so should have been linked there when |<name>-mask=0, the associated name is not rendered ]] local function list_people (control, people, etal) local sep; local namesep; local format = control.format; local maximum = control.maximum; local name_list = {}; if 'vanc' == format then -- Vancouver-like name styling? sep = cfg.presentation['sep_nl_vanc']; -- name-list separator between names is a comma namesep = cfg.presentation['sep_name_vanc']; -- last/first separator is a space else sep = cfg.presentation['sep_nl']; -- name-list separator between names is a semicolon namesep = cfg.presentation['sep_name']; -- last/first separator is <comma><space> end if sep:sub (-1, -1) ~= " " then sep = sep .. " " end if utilities.is_set (maximum) and maximum < 1 then return "", 0; end -- returned 0 is for EditorCount; not used for other names for i, person in ipairs (people) do if utilities.is_set (person.last) then local mask = person.mask; local one; local sep_one = sep; if utilities.is_set (maximum) and i > maximum then etal = true; break; end if mask then local n = tonumber (mask); -- convert to a number if it can be converted; nil else if n then one = 0 ~= n and string.rep("&mdash;", n) or nil; -- make a string of (n > 0) mdashes, nil else, to replace name person.link = nil; -- don't create link to name if name is replaces with mdash string or has been set nil else one = mask; -- replace name with mask text (must include name-list separator) sep_one = " "; -- modify name-list separator end else one = person.last; -- get surname local first = person.first -- get given name if utilities.is_set (first) then if ("vanc" == format) then -- if Vancouver format one = one:gsub ('%.', ''); -- remove periods from surnames (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) if not person.corporate and is_good_vanc_name (one, first, nil, i) then -- and name is all Latin characters; corporate authors not tested first = reduce_to_initials (first, i); -- attempt to convert first name(s) to initials end end one = one .. namesep .. first; end end if utilities.is_set (person.link) then one = utilities.make_wikilink (person.link, one); -- link author/editor end if one then -- if <one> has a value (name, mdash replacement, or mask text replacement) local proj, tag = interwiki_prefixen_get (one, true); -- get the interwiki prefixen if present if 'w' == proj and ('Wikipedia' == mw.site.namespaces.Project['name']) then proj = nil; -- for stuff like :w:de:<article>, :w is unnecessary TODO: maint cat? end if proj then local proj_name = ({['d'] = cfg.messages.wikidata, ['s'] = cfg.messages.wikisource, ['w'] = cfg.messages.wikipedia})[proj]; -- :w (wikipedia) for linking from a non-wikipedia project if proj_name then one = one .. utilities.wrap_style ('interproj', proj_name); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interproj-linked-name', proj); -- categorize it; <proj> is sort key tag = nil; -- unset; don't do both project and language end end if tag == cfg.this_wiki_code then tag = nil; -- stuff like :en:<article> at en.wiki is pointless TODO: maint cat? end if tag then local lang = cfg.lang_tag_remap[tag] or cfg.mw_languages_by_tag_t[tag]; if lang then -- error messaging done in extract_names() where we know parameter names one = one .. utilities.wrap_style ('interwiki', lang); -- add resized leading space, brackets, static text, language name utilities.add_prop_cat ('interwiki-linked-name', tag); -- categorize it; <tag> is sort key end end table.insert (name_list, one); -- add it to the list of names table.insert (name_list, sep_one); -- add the proper name-list separator end end end local count = #name_list / 2; -- (number of names + number of separators) divided by 2 if 0 < count then if 1 < count and not etal then if 'amp' == format then name_list[#name_list-2] = " & "; -- replace last separator with ampersand text elseif 'and' == format then if 2 == count then name_list[#name_list-2] = cfg.presentation.sep_nl_and; -- replace last separator with 'and' text else name_list[#name_list-2] = cfg.presentation.sep_nl_end; -- replace last separator with '(sep) and' text end end end name_list[#name_list] = nil; -- erase the last separator end local result = table.concat (name_list); -- construct list if etal and utilities.is_set (result) then -- etal may be set by |display-authors=etal but we might not have a last-first list result = result .. sep .. cfg.messages['et al']; -- we've got a last-first list and etal so add et al. end return result, count; -- return name-list string and count of number of names (count used for editor names only) end --[[--------------------< M A K E _ C I T E R E F _ I D >----------------------- Generates a CITEREF anchor ID if we have at least one name or a date. Otherwise returns an empty string. namelist is one of the contributor-, author-, or editor-name lists chosen in that order. year is Year or anchor_year. ]] local function make_citeref_id (namelist, year) local names={}; -- a table for the one to four names and year for i,v in ipairs (namelist) do -- loop through the list and take up to the first four last names names[i] = v.last if i == 4 then break end -- if four then done end table.insert (names, year); -- add the year at the end local id = table.concat(names); -- concatenate names and year for CITEREF id if utilities.is_set (id) then -- if concatenation is not an empty string return "CITEREF" .. id; -- add the CITEREF portion else return ''; -- return an empty string; no reason to include CITEREF id in this citation end end --[[--------------------------< C I T E _ C L A S S _A T T R I B U T E _M A K E >------------------------------ construct <cite> tag class attribute for this citation. <cite_class> – config.CitationClass from calling template <mode> – value from |mode= parameter ]] local function cite_class_attribute_make (cite_class, mode) local class_t = {}; table.insert (class_t, 'citation'); -- required for blue highlight if 'citation' ~= cite_class then table.insert (class_t, cite_class); -- identify this template for user css table.insert (class_t, utilities.is_set (mode) and mode or 'cs1'); -- identify the citation style for user css or javascript else table.insert (class_t, utilities.is_set (mode) and mode or 'cs2'); -- identify the citation style for user css or javascript end for _, prop_key in ipairs (z.prop_keys_t) do table.insert (class_t, prop_key); -- identify various properties for user css or javascript end return table.concat (class_t, ' '); -- make a big string and done end --[[---------------------< N A M E _ H A S _ E T A L >-------------------------- Evaluates the content of name parameters (author, editor, etc.) for variations on the theme of et al. If found, the et al. is removed, a flag is set to true and the function returns the modified name and the flag. This function never sets the flag to false but returns its previous state because it may have been set by previous passes through this function or by the associated |display-<names>=etal parameter ]] local function name_has_etal (name, etal, nocat, param) if utilities.is_set (name) then -- name can be nil in which case just return local patterns = cfg.et_al_patterns; -- get patterns from configuration for _, pattern in ipairs (patterns) do -- loop through all of the patterns if name:match (pattern) then -- if this 'et al' pattern is found in name name = name:gsub (pattern, ''); -- remove the offending text etal = true; -- set flag (may have been set previously here or by |display-<names>=etal) if not nocat then -- no categorization for |vauthors= utilities.set_message ('err_etal', {param}); -- and set an error if not added end end end end return name, etal; end --[[---------------------< N A M E _ I S _ N U M E R I C >---------------------- Add an error message and category when <name> parameter value does not contain letters. Add a maintenance category when <name> parameter value has numeric characters mixed with characters that are not numeric characters; could be letters and/or punctuation characters. This function will only emit one error and one maint message for the current template. Does not emit both error and maint messages/categories for the same parameter value. returns nothing ]] local function name_is_numeric (name, name_alias, list_name) local patterns = { '^%D+%d', -- <name> must have digits preceded by other characters '^%D*%d+%D+', -- <name> must have digits followed by other characters } if not added_numeric_name_errs and mw.ustring.match (name, '^[%A]+$') then -- if we have not already set an error message and <name> does not have any alpha characters utilities.set_message ('err_numeric_names', name_alias); -- add an error message added_numeric_name_errs = true; -- set the flag so we emit only one error message return; -- when here no point in further testing; abandon end if not added_numeric_name_maint then -- if we have already set a maint message for _, pattern in ipairs (patterns) do -- spin through list of patterns if mw.ustring.match (name, pattern) then -- digits preceded or followed by anything but digits; %D+ includes punctuation utilities.set_message ('maint_numeric_names', cfg.special_case_translation [list_name]); -- add a maint cat for this template added_numeric_name_maint = true; -- set the flag so we emit only one maint message return; -- when here no point in further testing; abandon end end end end --[[-----------------< N A M E _ H A S _ M U L T _ N A M E S >------------------ Evaluates the content of last/surname (authors etc.) parameters for multiple names. Multiple names are indicated if there is more than one comma or any "unescaped" semicolons. Escaped semicolons are ones used as part of selected HTML entities. If the condition is met, the function adds the multiple name maintenance category. Same test for first except that commas should not appear in given names (MOS:JR says that the generational suffix does not take a separator character). Titles, degrees, postnominals, affiliations, all normally comma separated don't belong in a citation. <name> – name parameter value <list_name> – AuthorList, EditorList, etc <limit> – number of allowed commas; 1 (default) for surnames; 0 for given names returns nothing ]] local function name_has_mult_names (name, list_name, limit) local _, commas, semicolons, nbsps; limit = limit and limit or 1; if utilities.is_set (name) then _, commas = name:gsub (',', ''); -- count the number of commas _, semicolons = name:gsub (';', ''); -- count the number of semicolons -- nbsps probably should be its own separate count rather than merged in -- some way with semicolons because Lua patterns do not support the -- grouping operator that regex does, which means there is no way to add -- more entities to escape except by adding more counts with the new -- entities _, nbsps = name:gsub ('&nbsp;',''); -- count nbsps -- There is exactly 1 semicolon per &nbsp; entity, so subtract nbsps -- from semicolons to 'escape' them. If additional entities are added, -- they also can be subtracted. if limit < commas or 0 < (semicolons - nbsps) then utilities.set_message ('maint_mult_names', cfg.special_case_translation [list_name]); -- add a maint message end end end --[=[-------------------------< I S _ G E N E R I C >---------------------------------------------------------- Compares values assigned to various parameters according to the string provided as <item> in the function call. <item> can have on of two values: 'generic_names' – for name-holding parameters: |last=, |first=, |editor-last=, etc 'generic_titles' – for |title= There are two types of generic tests. The 'accept' tests look for a pattern that should not be rejected by the 'reject' test. For example, |author=[[John Smith (author)|Smith, John]] would be rejected by the 'author' reject test. But piped wikilinks with 'author' disambiguation should not be rejected so the 'accept' test prevents that from happening. Accept tests are always performed before reject tests. Each of the 'accept' and 'reject' sequence tables hold tables for en.wiki (['en']) and local.wiki (['local']) that each can hold a test sequence table The sequence table holds, at index [1], a test pattern, and, at index [2], a boolean control value. The control value tells string.find() or mw.ustring.find() to do plain-text search (true) or a pattern search (false). The intent of all this complexity is to make these searches as fast as possible so that we don't run out of processing time on very large articles. Returns true when a reject test finds the pattern or string false when an accept test finds the pattern or string nil else ]=] local function is_generic (item, value) local str_lower = { -- use string.lower() for en.wiki (['en']) and use mw.ustring.lower() or local.wiki (['local']) ['en'] = string.lower, ['local'] = mw.ustring.lower, } local str_find = { -- use string.find() for en.wiki (['en']) and use mw.ustring.find() or local.wiki (['local']) ['en'] = string.find, ['local'] = mw.ustring.find, } local function test (val, test_t, wiki) -- local function to do the testing; <wiki> selects lower() and find() functions val = test_t[2] and str_lower[wiki](value) or val; -- when <test_t[2]> set to 'true', plaintext search using lowercase value return str_find[wiki] (val, test_t[1], 1, test_t[2]); -- return nil when not found or matched end local test_types_t = {'accept', 'reject'}; -- test accept patterns first, then reject patterns local wikis_t = {'en', 'local'}; -- do tests for each of these keys; en.wiki first, local.wiki second for _, test_type in ipairs (test_types_t) do -- for each test type for _, generic_value in pairs (cfg.special_case_translation[item][test_type]) do -- spin through the list of generic value fragments to accept or reject for _, wiki in ipairs (wikis_t) do if generic_value[wiki] then if test (value, generic_value[wiki], wiki) then -- go do the test return ('reject' == test_type); -- param value rejected, return true; false else end end end end end end --[[--------------------------< N A M E _ I S _ G E N E R I C >------------------------------------------------ calls is_generic() to determine if <name> is a 'generic name' listed in cfg.generic_names; <name_alias> is the parameter name used in error messaging ]] local function name_is_generic (name, name_alias) if not added_generic_name_errs and is_generic ('generic_names', name) then utilities.set_message ('err_generic_name', name_alias); -- set an error message added_generic_name_errs = true; end end --[[--------------------------< N A M E _ C H E C K S >-------------------------------------------------------- This function calls various name checking functions used to validate the content of the various name-holding parameters. ]] local function name_checks (last, first, list_name, last_alias, first_alias) local accept_name; if utilities.is_set (last) then last, accept_name = utilities.has_accept_as_written (last); -- remove accept-this-as-written markup when it wraps all of <last> if not accept_name then -- <last> not wrapped in accept-as-written markup name_has_mult_names (last, list_name); -- check for multiple names in the parameter name_is_numeric (last, last_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (last, last_alias); -- check for names found in the generic names list end end if utilities.is_set (first) then first, accept_name = utilities.has_accept_as_written (first); -- remove accept-this-as-written markup when it wraps all of <first> if not accept_name then -- <first> not wrapped in accept-as-written markup name_has_mult_names (first, list_name, 0); -- check for multiple names in the parameter; 0 is number of allowed commas in a given name name_is_numeric (first, first_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters name_is_generic (first, first_alias); -- check for names found in the generic names list end local wl_type, D = utilities.is_wikilink (first); if 0 ~= wl_type then first = D; utilities.set_message ('err_bad_paramlink', first_alias); end end return last, first; -- done end --[[----------------------< E X T R A C T _ N A M E S >------------------------- Gets name list from the input arguments Searches through args in sequential order to find |lastn= and |firstn= parameters (or their aliases), and their matching link and mask parameters. Stops searching when both |lastn= and |firstn= are not found in args after two sequential attempts: found |last1=, |last2=, and |last3= but doesn't find |last4= and |last5= then the search is done. This function emits an error message when there is a |firstn= without a matching |lastn=. When there are 'holes' in the list of last names, |last1= and |last3= are present but |last2= is missing, an error message is emitted. |lastn= is not required to have a matching |firstn=. When an author or editor parameter contains some form of 'et al.', the 'et al.' is stripped from the parameter and a flag (etal) returned that will cause list_people() to add the static 'et al.' text from Module:Citation/CS1/Configuration. This keeps 'et al.' out of the template's metadata. When this occurs, an error is emitted. ]] local function extract_names(args, list_name) local names = {}; -- table of names local last; -- individual name components local first; local link; local mask; local i = 1; -- loop counter/indexer local n = 1; -- output table indexer local count = 0; -- used to count the number of times we haven't found a |last= (or alias for authors, |editor-last or alias for editors) local etal = false; -- return value set to true when we find some form of et al. in an author parameter local last_alias, first_alias, link_alias; -- selected parameter aliases used in error messaging while true do last, last_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'err_redundant_parameters', i ); -- search through args for name components beginning at 1 first, first_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'err_redundant_parameters', i ); link, link_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ); mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); if last then -- error check |lastn= alias for unknown interwiki link prefix; done here because this is where we have the parameter name local project, language = interwiki_prefixen_get (last, true); -- true because we expect interwiki links in |lastn= to be wikilinked if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', last_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? last = utilities.remove_wiki_link (last); -- remove wikilink markup; show display value only end end if link then -- error check |linkn= alias for unknown interwiki link prefix local project, language = interwiki_prefixen_get (link, false); -- false because wiki links in |author-linkn= is an error if nil == project and nil == language then -- when both are nil utilities.set_message ('err_bad_paramlink', link_alias); -- not known, emit an error message -- TODO: err_bad_interwiki? link = nil; -- unset so we don't link link_alias = nil; end end last, etal = name_has_etal (last, etal, false, last_alias); -- find and remove variations on et al. first, etal = name_has_etal (first, etal, false, first_alias); -- find and remove variations on et al. last, first = name_checks (last, first, list_name, last_alias, first_alias); -- multiple names, extraneous annotation, etc. checks if first and not last then -- if there is a firstn without a matching lastn local alias = first_alias:find ('given', 1, true) and 'given' or 'first'; -- get first or given form of the alias utilities.set_message ('err_first_missing_last', { first_alias, -- param name of alias missing its mate first_alias:gsub (alias, {['first'] = 'last', ['given'] = 'surname'}), -- make param name appropriate to the alias form }); -- add this error message elseif not first and not last then -- if both firstn and lastn aren't found, are we done? count = count + 1; -- number of times we haven't found last and first if 2 <= count then -- two missing names and we give up break; -- normal exit or there is a two-name hole in the list; can't tell which end else -- we have last with or without a first link = link_title_ok (link, link_alias, last, last_alias); -- check for improper wiki-markup if first then link = link_title_ok (link, link_alias, first, first_alias); -- check for improper wiki-markup end names[n] = {last = last, first = first, link = link, mask = mask, corporate = false}; -- add this name to our names list (corporate for |vauthors= only) n = n + 1; -- point to next location in the names table if 1 == count then -- if the previous name was missing utilities.set_message ('err_missing_name', {list_name:match ("(%w+)List"):lower(), i - 1}); -- add this error message end count = 0; -- reset the counter, we're looking for two consecutive missing names end i = i + 1; -- point to next args location end return names, etal; -- all done, return our list of names and the etal flag end --[[--------------------------< N A M E _ T A G _ G E T >------------------------------------------------------ attempt to decode |language=<lang_param> and return language name and matching tag; nil else. This function looks for: <lang_param> as a tag in cfg.lang_tag_remap{} <lang_param> as a name in cfg.lang_name_remap{} <lang_param> as a name in cfg.mw_languages_by_name_t <lang_param> as a tag in cfg.mw_languages_by_tag_t when those fail, presume that <lang_param> is an IETF-like tag that MediaWiki does not recognize. Strip all script, region, variant, whatever subtags from <lang_param> to leave just a two or three character language tag and look for the new <lang_param> in cfg.mw_languages_by_tag_t{} on success, returns name (in properly capitalized form) and matching tag (in lowercase); on failure returns nil ]] local function name_tag_get (lang_param) local lang_param_lc = mw.ustring.lower (lang_param); -- use lowercase as an index into the various tables local name; local tag; name = cfg.lang_tag_remap[lang_param_lc]; -- assume <lang_param_lc> is a tag; attempt to get remapped language name if name then -- when <name>, <lang_param> is a tag for a remapped language name if cfg.lang_name_remap[name:lower()][2] ~= lang_param_lc then utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added return name, cfg.lang_name_remap[name:lower()][2]; -- so return name and tag from lang_name_remap[name]; special case to xlate sr-ec and sr-el to sr-cyrl and sr-latn end return name, lang_param_lc; -- so return <name> from remap and <lang_param_lc> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- still assuming that <lang_param_lc> is a tag; strip script, region, variant subtags name = cfg.lang_tag_remap[tag]; -- attempt to get remapped language name with language subtag only if name then -- when <name>, <tag> is a tag for a remapped language name return name, tag; -- so return <name> from remap and <tag> end if cfg.lang_name_remap[lang_param_lc] then -- not a remapped tag, assume <lang_param_lc> is a name; attempt to get remapped language tag return cfg.lang_name_remap[lang_param_lc][1], cfg.lang_name_remap[lang_param_lc][2]; -- for this <lang_param_lc>, return a (possibly) new name and appropriate tag end name = cfg.mw_languages_by_tag_t[lang_param_lc]; -- assume that <lang_param_lc> is a tag; attempt to get its matching language name if name then return name, lang_param_lc; -- <lang_param_lc> is a tag so return it and <name> end tag = cfg.mw_languages_by_name_t[lang_param_lc]; -- assume that <lang_param_lc> is a language name; attempt to get its matching tag if tag then return cfg.mw_languages_by_tag_t[tag], tag; -- <lang_param_lc> is a name so return the name from the table and <tag> end tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- is <lang_param_lc> an IETF-like tag that MediaWiki doesn't recognize? <tag> gets the language subtag; nil else if tag then name = cfg.mw_languages_by_tag_t[tag]; -- attempt to get a language name using the shortened <tag> if name then return name, tag; -- <lang_param_lc> is an unrecognized IETF-like tag so return <name> and language subtag end end end --[[-------------------< L A N G U A G E _ P A R A M E T E R >------------------ Gets language name from a provided two- or three-character ISO 639 code. If a code is recognized by MediaWiki, use the returned name; if not, then use the value that was provided with the language parameter. When |language= contains a recognized language (either code or name), the page is assigned to the category for that code: Category:Norwegian-language sources (no). For valid three-character code languages, the page is assigned to the single category for '639-2' codes: Category:CS1 ISO 639-2 language sources. Languages that are the same as the local wiki are not categorized. MediaWiki does not recognize three-character equivalents of two-character codes: code 'ar' is recognized but code 'ara' is not. This function supports multiple languages in the form |language=nb, French, th where the language names or codes are separated from each other by commas with optional space characters. ]] local function language_parameter (lang) local tag; -- some form of IETF-like language tag; language subtag with optional region, sript, vatiant, etc subtags local lang_subtag; -- ve populates |language= with mostly unecessary region subtags that MediaWiki does not recognize; this is the base language subtag local name; -- the language name local language_list = {}; -- table of language names to be rendered local names_t = mw.text.split (lang, '%s*,%s*'); -- names should be a comma separated list for _, lang in ipairs (names_t) do -- reuse lang here because we don't yet know if lang is a language name or a language tag; for now, ignore linter warning name, tag = name_tag_get (lang); -- attempt to get name/tag pair for <lang>; <name> has proper capitalization; <tag> is lowercase if utilities.is_set (tag) then lang_subtag = tag:gsub ('^(%a%a%a?)%-.*', '%1'); -- for categorization, strip any IETF-like tags from language tag if cfg.this_wiki_code ~= lang_subtag then -- when the language is not the same as this wiki's language if 2 == lang_subtag:len() then -- and is a two-character tag utilities.add_prop_cat ('foreign-lang-source', {name, tag}, lang_subtag); -- categorize it; tag appended to allow for multiple language categorization else -- or is a recognized language (but has a three-character tag) utilities.add_prop_cat ('foreign-lang-source-2', {lang_subtag}, lang_subtag); -- categorize it differently TODO: support multiple three-character tag categories per cs1|2 template? end elseif cfg.local_lang_cat_enable then -- when the language and this wiki's language are the same and categorization is enabled utilities.add_prop_cat ('local-lang-source', {name, lang_subtag}); -- categorize it end else name = lang; -- return whatever <lang> has so that we show something utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added end table.insert (language_list, name); end name = utilities.make_sep_list (#language_list, language_list); if (1 == #language_list) and (lang_subtag == cfg.this_wiki_code) then -- when only one language, find lang name in this wiki lang name; for |language=en-us, 'English' in 'American English' return ''; -- if one language and that language is this wiki's return an empty string (no annotation) end return (" " .. wrap_msg ('language', name)); -- otherwise wrap with '(in ...)' --[[ TODO: should only return blank or name rather than full list so we can clean up the bunched parenthetical elements Language, Type, Format ]] end --[[-----------------------< S E T _ C S _ S T Y L E >-------------------------- Gets the default CS style configuration for the given mode. Returns default separator and either postscript as passed in or the default. In CS1, the default postscript and separator are '.'. In CS2, the default postscript is the empty string and the default separator is ','. ]] local function set_cs_style (postscript, mode) if utilities.is_set(postscript) then -- emit a maintenance message if user postscript is the default cs1 postscript -- we catch the opposite case for cs2 in set_style if mode == 'cs1' and postscript == cfg.presentation['ps_' .. mode] then utilities.set_message ('maint_postscript'); end else postscript = cfg.presentation['ps_' .. mode]; end return cfg.presentation['sep_' .. mode], postscript; end --[[--------------------------< S E T _ S T Y L E >----------------------------- Sets the separator and postscript styles. Checks the |mode= first and the #invoke CitationClass second. Removes the postscript if postscript == none. ]] local function set_style (mode, postscript, cite_class) local sep; if 'cs2' == mode then sep, postscript = set_cs_style (postscript, 'cs2'); elseif 'cs1' == mode then sep, postscript = set_cs_style (postscript, 'cs1'); elseif 'citation' == cite_class then sep, postscript = set_cs_style (postscript, 'cs2'); else sep, postscript = set_cs_style (postscript, 'cs1'); end if cfg.keywords_xlate[postscript:lower()] == 'none' then -- emit a maintenance message if user postscript is the default cs2 postscript -- we catch the opposite case for cs1 in set_cs_style if 'cs2' == mode or ('cs1' ~= mode and 'citation' == cite_class) then -- {{citation |title=Title |mode=cs1 |postscript=none}} should not emit maint message utilities.set_message ('maint_postscript'); end postscript = ''; end return sep, postscript end --[=[-------------------------< I S _ P D F >----------------------------------- Determines if a URL has the file extension that is one of the PDF file extensions used by [[MediaWiki:Common.css]] when applying the PDF icon to external links. returns true if file extension is one of the recognized extensions, else false ]=] local function is_pdf (url) return url:match ('%.pdf$') or url:match ('%.PDF$') or url:match ('%.pdf[%?#]') or url:match ('%.PDF[%?#]') or url:match ('%.PDF&#035') or url:match ('%.pdf&#035'); end --[[--------------------------< S T Y L E _ F O R M A T >----------------------- Applies CSS style to |format=, |chapter-format=, etc. Also emits an error message if the format parameter does not have a matching URL parameter. If the format parameter is not set and the URL contains a file extension that is recognized as a PDF document by MediaWiki's commons.css, this code will set the format parameter to (PDF) with the appropriate styling. ]] local function style_format (format, url, fmt_param, url_param) if utilities.is_set (format) then format = utilities.wrap_style ('format', format); -- add leading space, parentheses, resize if not utilities.is_set (url) then utilities.set_message ('err_format_missing_url', {fmt_param, url_param}); -- add an error message end elseif is_pdf (url) then -- format is not set so if URL is a PDF file then format = utilities.wrap_style ('format', 'PDF'); -- set format to PDF else format = ''; -- empty string for concatenation end return format; end --[[---------------------< G E T _ D I S P L A Y _ N A M E S >------------------ Returns a number that defines the number of names displayed for author and editor name lists and a Boolean flag to indicate when et al. should be appended to the name list. When the value assigned to |display-xxxxors= is a number greater than or equal to zero, return the number and the previous state of the 'etal' flag (false by default but may have been set to true if the name list contains some variant of the text 'et al.'). When the value assigned to |display-xxxxors= is the keyword 'etal', return a number that is one greater than the number of authors in the list and set the 'etal' flag true. This will cause the list_people() to display all of the names in the name list followed by 'et al.' In all other cases, returns nil and the previous state of the 'etal' flag. inputs: max: A['DisplayAuthors'] or A['DisplayEditors'], etc; a number or some flavor of etal count: #a or #e list_name: 'authors' or 'editors' etal: author_etal or editor_etal This function sets an error message when |display-xxxxors= value greater than or equal to number of names but not when <max> comes from {{cs1 config}} global settings. When using global settings, <param> is set to the keyword 'cs1 config' which is used to supress the normal error. Error is suppressed because it is to be expected that some citations in an article will have the same or fewer names that the limit specified in {{cs1 config}}. ]] local function get_display_names (max, count, etal, param) if utilities.is_set (max) then if 'etal' == cfg.keywords_xlate[max:lower():gsub("[ '%.]", '')] then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings max = count + 1; -- number of authors + 1 so display all author name plus et al. etal = true; -- overrides value set by extract_names() elseif max:match ('^%d+$') then -- if is a string of numbers max = tonumber (max); -- make it a number if (max >= count) and ('cs1 config' ~= param) then -- error when local |display-xxxxors= value greater than or equal to number of names; not an error when using global setting utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; end else -- not a valid keyword or number utilities.set_message ('err_disp_name', {param, max}); -- add error message max = nil; -- unset; as if |display-xxxxors= had not been set end end return max, etal; end --[[----------< E X T R A _ T E X T _ I N _ P A G E _ C H E C K >--------------- Adds error if |page=, |pages=, |quote-page=, |quote-pages= has what appears to be some form of p. or pp. abbreviation in the first characters of the parameter content. check page for extraneous p, p., pp, pp., pg, pg. at start of parameter value: good pattern: '^P[^%.P%l]' matches when page begins PX or P# but not Px where x and X are letters and # is a digit bad pattern: '^[Pp][PpGg]' matches when page begins pp, pP, Pp, PP, pg, pG, Pg, PG ]] local function extra_text_in_page_check (val, name) if not val:match (cfg.vol_iss_pg_patterns.good_ppattern) then for _, pattern in ipairs (cfg.vol_iss_pg_patterns.bad_ppatterns) do -- spin through the selected sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message ('err_extra_text_pages', name); -- add error message return; -- and done end end end end --[[--------------------------< E X T R A _ T E X T _ I N _ V O L _ I S S _ C H E C K >------------------------ Adds error if |volume= or |issue= has what appears to be some form of redundant 'type' indicator. Applies to both; this function looks for issue text in both |issue= and |volume= and looks for volume-like text in |voluem= and |issue=. For |volume=: 'V.', or 'Vol.' (with or without the dot) abbreviations or 'Volume' in the first characters of the parameter content (all case insensitive). 'V' and 'v' (without the dot) are presumed to be roman numerals so are allowed. For |issue=: 'No.', 'I.', 'Iss.' (with or without the dot) abbreviations, or 'Issue' in the first characters of the parameter content (all case insensitive); numero styling: 'n°' with degree sign U+00B0, and № precomposed numero sign U+2116. Single character values ('v', 'i', 'n') allowed when not followed by separator character ('.', ':', '=', or whitespace character) – param values are trimmed of whitespace by MediaWiki before delivered to the module. <val> is |volume= or |issue= parameter value <name> is |volume= or |issue= parameter name for error message <selector> is 'v' for |volume=, 'i' for |issue= sets error message on failure; returns nothing ]] local function extra_text_in_vol_iss_check (val, name, selector) if not utilities.is_set (val) then return; end local handler = 'v' == selector and 'err_extra_text_volume' or 'err_extra_text_issue'; local accept_val; -- for now, ignore linter warning val, accept_val = utilities.has_accept_as_written (val); --if accept_val then -- if uncomment this, |volume=((vol. 1)) suppresses error -- return; --end --val = mw.text.unstripNoWiki (val); -- if uncomment this, |volume=<nowiki>vol. 1</nowiki> shows error val = val:lower(); -- force parameter value to lower case for _, pattern in ipairs (cfg.vol_iss_pg_patterns.vi_patterns_t) do -- spin through the sequence table of patterns if val:match (pattern) then -- when a match, error so utilities.set_message (handler, name); -- add error message return; -- and done end end end --[=[-------------------------< G E T _ V _ N A M E _ T A B L E >---------------------------------------------- split apart a |vauthors= or |veditors= parameter. This function allows for corporate names, wrapped in doubled parentheses to also have commas; in the old version of the code, the doubled parentheses were included in the rendered citation and in the metadata. Individual author names may be wikilinked |vauthors=Jones AB, [[E. B. White|White EB]], ((Black, Brown, and Co.)) ]=] local function get_v_name_table (vparam, output_table, output_link_table) local _, accept = utilities.has_accept_as_written (vparam); if accept then utilities.add_prop_cat ('vanc-accept'); -- add properties category end local name_table = mw.text.split(vparam, "%s*,%s*"); -- names are separated by commas local wl_type, label, link; -- wl_type not used here; just a placeholder local i = 1; while name_table[i] do if name_table[i]:match ('^%(%(.*[^%)][^%)]$') then -- first segment of corporate with one or more commas; this segment has the opening doubled parentheses local name = name_table[i]; i = i + 1; -- bump indexer to next segment while name_table[i] do name = name .. ', ' .. name_table[i]; -- concatenate with previous segments if name_table[i]:match ('^.*%)%)$') then -- if this table member has the closing doubled parentheses break; -- and done reassembling so end i = i + 1; -- bump indexer end table.insert (output_table, name); -- and add corporate name to the output table table.insert (output_link_table, ''); -- no wikilink else wl_type, label, link = utilities.is_wikilink (name_table[i]); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] table.insert (output_table, label); -- add this name if 1 == wl_type then table.insert (output_link_table, label); -- simple wikilink [[D]] else table.insert (output_link_table, link); -- no wikilink or [[L|D]]; add this link if there is one, else empty string end end i = i + 1; end return output_table; end --[[--------------------------< P A R S E _ V A U T H O R S _ V E D I T O R S >-------------------------------- This function extracts author / editor names from |vauthors= or |veditors= and finds matching |xxxxor-maskn= and |xxxxor-linkn= in args. It then returns a table of assembled names just as extract_names() does. Author / editor names in |vauthors= or |veditors= must be in Vancouver system style. Corporate or institutional names may sometimes be required and because such names will often fail the is_good_vanc_name() and other format compliance tests, are wrapped in doubled parentheses ((corporate name)) to suppress the format tests. Supports generational suffixes Jr, 2nd, 3rd, 4th–6th. This function sets the Vancouver error when a required comma is missing and when there is a space between an author's initials. ]] local function parse_vauthors_veditors (args, vparam, list_name) local names = {}; -- table of names assembled from |vauthors=, |author-maskn=, |author-linkn= local v_name_table = {}; local v_link_table = {}; -- when name is wikilinked, targets go in this table local etal = false; -- return value set to true when we find some form of et al. vauthors parameter local last, first, link, mask, suffix; local corporate = false; vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period) v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); -- names are separated by commas for i, v_name in ipairs(v_name_table) do first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor local accept_name; v_name, accept_name = utilities.has_accept_as_written (v_name); -- remove accept-this-as-written markup when it wraps all of <v_name> if accept_name then last = v_name; corporate = true; -- flag used in list_people() elseif string.find(v_name, "%s") then if v_name:find('[;%.]') then -- look for commonly occurring punctuation characters; add_vanc_error (cfg.err_msg_supl.punctuation, i); end local lastfirst_t = mw.text.split(v_name, "%s+"); first = table.remove (lastfirst_t); -- removes and returns value of last element in table which should be initials or generational suffix if not mw.ustring.match (first, '^%u+$') then -- mw.ustring here so that later we will catch non-Latin characters suffix = first; -- not initials so assume that whatever we got is a generational suffix first = table.remove (lastfirst_t); -- get what should be the initials from the table end last = table.concat (lastfirst_t, ' '); -- returns a string that is the concatenation of all other names that are not initials and generational suffix if not utilities.is_set (last) then first = ''; -- unset last = v_name; -- last empty because something wrong with first add_vanc_error (cfg.err_msg_supl.name, i); end if mw.ustring.match (last, '%a+%s+%u+%s+%a+') then add_vanc_error (cfg.err_msg_supl['missing comma'], i); -- matches last II last; the case when a comma is missing end if mw.ustring.match (v_name, ' %u %u$') then -- this test is in the wrong place TODO: move or replace with a more appropriate test add_vanc_error (cfg.err_msg_supl.initials, i); -- matches a space between two initials end else last = v_name; -- last name or single corporate name? Doesn't support multiword corporate names? do we need this? end if utilities.is_set (first) then if not mw.ustring.match (first, "^%u?%u$") then -- first shall contain one or two upper-case letters, nothing else add_vanc_error (cfg.err_msg_supl.initials, i); -- too many initials; mixed case initials (which may be ok Romanization); hyphenated initials end is_good_vanc_name (last, first, suffix, i); -- check first and last before restoring the suffix which may have a non-Latin digit if utilities.is_set (suffix) then first = first .. ' ' .. suffix; -- if there was a suffix concatenate with the initials suffix = ''; -- unset so we don't add this suffix to all subsequent names end else if not corporate then is_good_vanc_name (last, '', nil, i); end end link = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i ) or v_link_table[i]; mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i ); names[i] = {last = last, first = first, link = link, mask = mask, corporate = corporate}; -- add this assembled name to our names list end return names, etal; -- all done, return our list of names end --[[--------------------------< S E L E C T _ A U T H O R _ E D I T O R _ S O U R C E >------------------------ Select one of |authors=, |authorn= / |lastn / firstn=, or |vauthors= as the source of the author name list or select one of |editorn= / editor-lastn= / |editor-firstn= or |veditors= as the source of the editor name list. Only one of these appropriate three will be used. The hierarchy is: |authorn= (and aliases) highest and |authors= lowest; |editorn= (and aliases) highest and |veditors= lowest (support for |editors= withdrawn) When looking for |authorn= / |editorn= parameters, test |xxxxor1= and |xxxxor2= (and all of their aliases); stops after the second test which mimicks the test used in extract_names() when looking for a hole in the author name list. There may be a better way to do this, I just haven't discovered what that way is. Emits an error message when more than one xxxxor name source is provided. In this function, vxxxxors = vauthors or veditors; xxxxors = authors as appropriate. ]] local function select_author_editor_source (vxxxxors, xxxxors, args, list_name) local lastfirst = false; if utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 1 ) or -- do this twice in case we have a |first1= without a |last1=; this ... utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 1 ) or -- ... also catches the case where |first= is used with |vauthors= utilities.select_one ( args, cfg.aliases[list_name .. '-Last'], 'none', 2 ) or utilities.select_one ( args, cfg.aliases[list_name .. '-First'], 'none', 2 ) then lastfirst = true; end if (utilities.is_set (vxxxxors) and true == lastfirst) or -- these are the three error conditions (utilities.is_set (vxxxxors) and utilities.is_set (xxxxors)) or (true == lastfirst and utilities.is_set (xxxxors)) then utilities.set_message ('err_redundant_parameters', utilities.substitute (cfg.special_case_translation.name_list_params, ('AuthorList' == list_name) and cfg.special_case_translation.author or cfg.special_case_translation.editor)); -- add error message end if true == lastfirst then return 1 end; -- return a number indicating which author name source to use if utilities.is_set (vxxxxors) then return 2 end; if utilities.is_set (xxxxors) then return 3 end; return 1; -- no authors so return 1; this allows missing author name test to run in case there is a first without last end --[[--------------------------< I S _ V A L I D _ P A R A M E T E R _ V A L U E >------------------------------ This function is used to validate a parameter's assigned value for those parameters that have only a limited number of allowable values (yes, y, true, live, dead, etc.). When the parameter value has not been assigned a value (missing or empty in the source template) the function returns the value specified by ret_val. If the parameter value is one of the list of allowed values returns the translated value; else, emits an error message and returns the value specified by ret_val. TODO: explain <invert> ]] local function is_valid_parameter_value (value, name, possible, ret_val, invert) if not utilities.is_set (value) then return ret_val; -- an empty parameter is ok end if (not invert and utilities.in_array (value, possible)) then -- normal; <value> is in <possible> table return cfg.keywords_xlate[value]; -- return translation of parameter keyword elseif invert and not utilities.in_array (value, possible) then -- invert; <value> is not in <possible> table return value; -- return <value> as it is else utilities.set_message ('err_invalid_param_val', {name, value}); -- not an allowed value so add error message return ret_val; end end --[[--------------------------< T E R M I N A T E _ N A M E _ L I S T >---------------------------------------- This function terminates a name list (author, contributor, editor) with a separator character (sepc) and a space when the last character is not a sepc character or when the last three characters are not sepc followed by two closing square brackets (close of a wikilink). When either of these is true, the name_list is terminated with a single space character. ]] local function terminate_name_list (name_list, sepc) if (string.sub (name_list, -3, -1) == sepc .. '. ') then -- if already properly terminated return name_list; -- just return the name list elseif (string.sub (name_list, -1, -1) == sepc) or (string.sub (name_list, -3, -1) == sepc .. ']]') then -- if last name in list ends with sepc char return name_list .. " "; -- don't add another else return name_list .. sepc .. ' '; -- otherwise terminate the name list end end --[[-------------------------< F O R M A T _ V O L U M E _ I S S U E >----------------------------------------- returns the concatenation of the formatted volume and issue (or journal article number) parameters as a single string; or formatted volume or formatted issue, or an empty string if neither are set. ]] local function format_volume_issue (volume, issue, article, cite_class, origin, sepc, lower) if not utilities.is_set (volume) and not utilities.is_set (issue) and not utilities.is_set (article) then return ''; end -- same condition as in format_pages_sheets() local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); local is_numeric_vol = volume and (volume:match ('^[MDCLXVI]+$') or volume:match ('^%d+$')); -- is only uppercase roman numerals or only digits? local is_long_vol = volume and (4 < mw.ustring.len(volume)); -- is |volume= value longer than 4 characters? if volume and (not is_numeric_vol and is_long_vol) then -- when not all digits or Roman numerals, is |volume= longer than 4 characters? utilities.add_prop_cat ('long-vol'); -- yes, add properties cat end if is_journal then -- journal-style formatting local vol = ''; if utilities.is_set (volume) then if is_numeric_vol then -- |volume= value all digits or all uppercase Roman numerals? vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, volume}); -- render in bold face elseif is_long_vol then -- not all digits or Roman numerals; longer than 4 characters? vol = utilities.substitute (cfg.messages['j-vol'], {sepc, utilities.hyphen_to_dash (volume)}); -- not bold else -- four or fewer characters vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, utilities.hyphen_to_dash (volume)}); -- bold end end vol = vol .. (utilities.is_set (issue) and utilities.substitute (cfg.messages['j-issue'], issue) or '') vol = vol .. (utilities.is_set (article) and utilities.substitute (cfg.messages['j-article-num'], article) or '') return vol; end if 'podcast' == cite_class and utilities.is_set (issue) then return wrap_msg ('issue', {sepc, issue}, lower); end if 'conference' == cite_class and utilities.is_set (article) then -- |article-number= supported only in journal and conference cites if utilities.is_set (volume) and utilities.is_set (article) then -- both volume and article number return wrap_msg ('vol-art', {sepc, utilities.hyphen_to_dash (volume), article}, lower); elseif utilities.is_set (article) then -- article number alone; when volume alone, handled below return wrap_msg ('art', {sepc, article}, lower); end end -- all other types of citation if utilities.is_set (volume) and utilities.is_set (issue) then return wrap_msg ('vol-no', {sepc, utilities.hyphen_to_dash (volume), issue}, lower); elseif utilities.is_set (volume) then return wrap_msg ('vol', {sepc, utilities.hyphen_to_dash (volume)}, lower); else return wrap_msg ('issue', {sepc, issue}, lower); end end --[[-------------------------< F O R M A T _ P A G E S _ S H E E T S >----------------------------------------- adds static text to one of |page(s)= or |sheet(s)= values and returns it with all of the others set to empty strings. The return order is: page, pages, sheet, sheets Singular has priority over plural when both are provided. ]] local function format_pages_sheets (page, pages, sheet, sheets, cite_class, origin, sepc, nopp, lower) if 'map' == cite_class then -- only cite map supports sheet(s) as in-source locators if utilities.is_set (sheet) then if 'journal' == origin then return '', '', wrap_msg ('j-sheet', sheet, lower), ''; else return '', '', wrap_msg ('sheet', {sepc, sheet}, lower), ''; end elseif utilities.is_set (sheets) then if 'journal' == origin then return '', '', '', wrap_msg ('j-sheets', sheets, lower); else return '', '', '', wrap_msg ('sheets', {sepc, sheets}, lower); end end end local is_journal = 'journal' == cite_class or (utilities.in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); if utilities.is_set (page) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], page), '', '', ''; elseif not nopp then return utilities.substitute (cfg.messages['p-prefix'], {sepc, page}), '', '', ''; else return utilities.substitute (cfg.messages['nopp'], {sepc, page}), '', '', ''; end elseif utilities.is_set (pages) then if is_journal then return utilities.substitute (cfg.messages['j-page(s)'], pages), '', '', ''; elseif tonumber(pages) ~= nil and not nopp then -- if pages is only digits, assume a single page number return '', utilities.substitute (cfg.messages['p-prefix'], {sepc, pages}), '', ''; elseif not nopp then return '', utilities.substitute (cfg.messages['pp-prefix'], {sepc, pages}), '', ''; else return '', utilities.substitute (cfg.messages['nopp'], {sepc, pages}), '', ''; end end return '', '', '', ''; -- return empty strings end --[[--------------------------< I N S O U R C E _ L O C _ G E T >---------------------------------------------- returns one of the in-source locators: page, pages, or at. If any of these are interwiki links to Wikisource, returns the label portion of the interwiki-link as plain text for use in COinS. This COinS thing is done because here we convert an interwiki-link to an external link and add an icon span around that; get_coins_pages() doesn't know about the span. TODO: should it? TODO: add support for sheet and sheets?; streamline; TODO: make it so that this function returns only one of the three as the single in-source (the return value assigned to a new name)? ]] local function insource_loc_get (page, page_orig, pages, pages_orig, at) local ws_url, ws_label, coins_pages, L; -- for Wikisource interwiki-links; TODO: this corrupts page metadata (span remains in place after cleanup; fix there?) if utilities.is_set (page) then if utilities.is_set (pages) or utilities.is_set (at) then pages = ''; -- unset the others at = ''; end extra_text_in_page_check (page, page_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (page); -- make ws URL from |page= interwiki link; link portion L becomes tooltip label if ws_url then page = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in page'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? page = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, page}); coins_pages = ws_label; end elseif utilities.is_set (pages) then if utilities.is_set (at) then at = ''; -- unset end extra_text_in_page_check (pages, pages_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. ws_url, ws_label, L = wikisource_url_make (pages); -- make ws URL from |pages= interwiki link; link portion L becomes tooltip label if ws_url then pages = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in pages'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? pages = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, pages}); coins_pages = ws_label; end elseif utilities.is_set (at) then ws_url, ws_label, L = wikisource_url_make (at); -- make ws URL from |at= interwiki link; link portion L becomes tooltip label if ws_url then at = external_link (ws_url, ws_label .. '&nbsp;', 'ws link in at'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? at = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, at}); coins_pages = ws_label; end end return page, pages, at, coins_pages; end --[[--------------------------< I S _ U N I Q U E _ A R C H I V E _ U R L >------------------------------------ add error message when |archive-url= value is same as |url= or chapter-url= (or alias...) value ]] local function is_unique_archive_url (archive, url, c_url, source, date) if utilities.is_set (archive) then if archive == url or archive == c_url then utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}); -- add error message return '', ''; -- unset |archive-url= and |archive-date= because same as |url= or |chapter-url= end end return archive, date; end --[=[-------------------------< A R C H I V E _ U R L _ C H E C K >-------------------------------------------- Check archive.org URLs to make sure they at least look like they are pointing at valid archives and not to the save snapshot URL or to calendar pages. When the archive URL is 'https://web.archive.org/save/' (or http://...) archive.org saves a snapshot of the target page in the URL. That is something that Wikipedia should not allow unwitting readers to do. When the archive.org URL does not have a complete timestamp, archive.org chooses a snapshot according to its own algorithm or provides a calendar 'search' result. [[WP:ELNO]] discourages links to search results. This function looks at the value assigned to |archive-url= and returns empty strings for |archive-url= and |archive-date= and an error message when: |archive-url= holds an archive.org save command URL |archive-url= is an archive.org URL that does not have a complete timestamp (YYYYMMDDhhmmss 14 digits) in the correct place otherwise returns |archive-url= and |archive-date= There are two mostly compatible archive.org URLs: //web.archive.org/<timestamp>... -- the old form //web.archive.org/web/<timestamp>... -- the new form The old form does not support or map to the new form when it contains a display flag. There are four identified flags ('id_', 'js_', 'cs_', 'im_') but since archive.org ignores others following the same form (two letters and an underscore) we don't check for these specific flags but we do check the form. This function supports a preview mode. When the article is rendered in preview mode, this function may return a modified archive URL: for save command errors, return undated wildcard (/*/) for timestamp errors when the timestamp has a wildcard, return the URL unmodified for timestamp errors when the timestamp does not have a wildcard, return with timestamp limited to six digits plus wildcard (/yyyymm*/) A secondary function is to return an archive-url timestamp from those archive urls that have them. The timestamp is used by validation.archive_date_check() to see if the value in |archive-date= matches the timestamp in the archive url. ]=] local function archive_url_check (url, date) local err_msg; -- start with the error message empty local path, timestamp, flag; -- portions of the archive.org URL local function is_ts_date_valid (ts, origin_date) -- local function to validate archive url taimestamp date; time ignored local y, m, d = ts:match ('(%d%d%d%d)(%d%d)(%d%d)'); -- split into parts if y and validation.is_valid_date (y, m, d) and (tonumber (y) >= 1996) then return true, tonumber (y) >= origin_date; -- <origin_date> is 1996 for archive.org end end if (not url:match('//web%.archive%.org/')) and (not url:match('//liveweb%.archive%.org/')) then -- also deprecated liveweb Wayback machine URL return url, date; -- not an archive.org archive, return ArchiveURL and ArchiveDate end if url:match('//web%.archive%.org/save/') then -- if a save command URL, we don't want to allow saving of the target page err_msg = cfg.err_msg_supl.save; url = url:gsub ('(//web%.archive%.org)/save/', '%1/*/', 1); -- for preview mode: modify ArchiveURL elseif url:match('//liveweb%.archive%.org/') then err_msg = cfg.err_msg_supl.liveweb; else path, timestamp, flag = url:match('//web%.archive%.org/([^%d]*)(%d+)([^/]*)/'); -- split out some of the URL parts for evaluation if not path then -- malformed in some way; pattern did not match err_msg = cfg.err_msg_supl.timestamp; elseif 14 ~= timestamp:len() then -- path and flag optional, must have 14-digit timestamp here err_msg = cfg.err_msg_supl.timestamp; if '*' ~= flag then local replacement = timestamp:match ('^%d%d%d%d%d%d') or timestamp:match ('^%d%d%d%d'); -- get the first 6 (YYYYMM) or first 4 digits (YYYY) if replacement then -- nil if there aren't at least 4 digits (year) replacement = replacement .. string.rep ('0', 14 - replacement:len()); -- year or yearmo (4 or 6 digits) zero-fill to make 14-digit timestamp url=url:gsub ('(//web%.archive%.org/[^%d]*)%d[^/]*', '%1' .. replacement .. '*', 1) -- for preview, modify ts to 14 digits plus splat for calendar display end end elseif not is_ts_date_valid (timestamp, 1996) then -- is ymd portion of timestamp a valid date? err_msg = cfg.err_msg_supl.timestamp; timestamp = nil; -- unset because invalid elseif utilities.is_set (path) and 'web/' ~= path then -- older archive URLs do not have the extra 'web/' path element err_msg = cfg.err_msg_supl.path; elseif utilities.is_set (flag) and not utilities.is_set (path) then -- flag not allowed with the old form URL (without the 'web/' path element) err_msg = cfg.err_msg_supl.flag; elseif utilities.is_set (flag) and not flag:match ('%a%a_') then -- flag if present must be two alpha characters and underscore (requires 'web/' path element) err_msg = cfg.err_msg_supl.flag; else return url, date, timestamp; -- return ArchiveURL, ArchiveDate, and timestamp from |archive-url= end end -- if here, something not right so utilities.set_message ('err_archive_url', {err_msg}); -- add error message and if is_preview_mode then return url, date, timestamp; -- preview mode so return ArchiveURL, ArchiveDate, and timestamp from |archive-url= else return '', ''; -- return empty strings for ArchiveURL and ArchiveDate end end --[[--------------------------< P L A C E _ C H E C K >-------------------------------------------------------- check |place=, |publication-place=, |location= to see if these params include digits. This function added because many editors misuse location to specify the in-source location (|page(s)= and |at= are supposed to do that) returns the original parameter value without modification; added maint cat when parameter value contains digits ]] local function place_check (param_val) if not utilities.is_set (param_val) then -- parameter empty or omitted return param_val; -- return that empty state end if mw.ustring.find (param_val, '%d') then -- not empty, are there digits in the parameter value utilities.set_message ('maint_location'); -- yep, add maint cat end return param_val; -- and done end --[[--------------------------< I S _ A R C H I V E D _ C O P Y >---------------------------------------------- compares |title= to 'Archived copy' (placeholder added by bots that can't find proper title); if matches, return true; nil else ]] local function is_archived_copy (title) title = mw.ustring.lower(title); -- switch title to lower case if title:find (cfg.special_case_translation.archived_copy.en) then -- if title is 'Archived copy' return true; elseif cfg.special_case_translation.archived_copy['local'] then if mw.ustring.find (title, cfg.special_case_translation.archived_copy['local']) then -- mw.ustring() because might not be Latin script return true; end end end --[[--------------------------< D I S P L A Y _ N A M E S _ S E L E C T >-------------------------------------- for any of the |display-authors=, |display-editors=, etc parameters, select either the local or global setting. When both are present, look at <local_display_names> value. When the value is some sort of 'et al.'string, special handling is required. When {{cs1 config}} has |display-<namelist>= AND this template has |display-<namelist>=etal AND: the number of names specified by <number_of_names> is: greater than the number specified in the global |display-<namelist>= parameter (<global_display_names>) use global |display-<namelist>= parameter value set overridden maint category less than or equal to the number specified in the global |display-<namelist>= parameter use local |display-<namelist>= parameter value The purpose of this function is to prevent categorizing a template that has fewer names than the global setting to keep the etal annotation specified by <local_display_names>. ]] local function display_names_select (global_display_names, local_display_names, param_name, number_of_names) if global_display_names and utilities.is_set (local_display_names) then -- when both if 'etal' == local_display_names:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings number_of_names = tonumber (number_of_names); -- convert these to numbers for comparison local global_display_names_num = tonumber (global_display_names); -- <global_display_names> not set when parameter value is not digits if number_of_names > global_display_names_num then -- template has more names than global config allows to be displayed? utilities.set_message ('maint_overridden_setting'); -- set a maint message because global is overriding local |display-<namelist>=etal return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local because fewer names so let <local_display_names> control end end -- here when <global_display_names> and <local_display_names> both numbers; <global_display_names> controls utilities.set_message ('maint_overridden_setting'); -- set a maint message return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) end -- here when only one of <global_display_names> or <local_display_names> set if global_display_names then return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names()) else return local_display_names, param_name; -- return local end end --[[--------------------------< M O D E _ S E T >-------------------------------------------------------------- fetch global mode setting from {{cs1 config}} (if present) or from |mode= (if present); global setting overrides local |mode= parameter value. When both are present, emit maintenance message ]] local function mode_set (Mode, Mode_origin) local mode; if cfg.global_cs1_config_t['Mode'] then -- global setting in {{cs1 config}}; nil when empty or assigned value invalid mode = is_valid_parameter_value (cfg.global_cs1_config_t['Mode'], 'cs1 config: mode', cfg.keywords_lists['mode'], ''); -- error messaging 'param' here is a hoax else mode = is_valid_parameter_value (Mode, Mode_origin, cfg.keywords_lists['mode'], ''); end if cfg.global_cs1_config_t['Mode'] and utilities.is_set (Mode) then -- when template has |mode=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end return mode; end --[[--------------------------< Q U O T E _ M A K E >---------------------------------------------------------- create quotation from |quote=, |trans-quote=, and/or script-quote= with or without |quote-page= or |quote-pages= when any of those three quote parameters are set, this function unsets <PostScript>. When none of those parameters are set, |quote-page= and |quote-pages= are unset to nil so that they are not included in the template's metadata ]] local function quote_make (quote, trans_quote, script_quote, quote_page, quote_pages, nopp, sepc, postscript) if utilities.is_set (quote) or utilities.is_set (trans_quote) or utilities.is_set (script_quote) then if utilities.is_set (quote) then if quote:sub(1, 1) == '"' and quote:sub(-1, -1) == '"' then -- if first and last characters of quote are quote marks quote = quote:sub(2, -2); -- strip them off end end quote = kern_quotes (quote); -- kern if needed quote = utilities.wrap_style ('quoted-text', quote ); -- wrap in <q>...</q> tags if utilities.is_set (script_quote) then quote = script_concatenate (quote, script_quote, 'script-quote'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after quote is wrapped end if utilities.is_set (trans_quote) then if trans_quote:sub(1, 1) == '"' and trans_quote:sub(-1, -1) == '"' then -- if first and last characters of |trans-quote are quote marks trans_quote = trans_quote:sub(2, -2); -- strip them off end quote = quote .. " " .. utilities.wrap_style ('trans-quoted-title', trans_quote ); end if utilities.is_set (quote_page) or utilities.is_set (quote_pages) then -- add page prefix local quote_prefix = ''; if utilities.is_set (quote_page) then extra_text_in_page_check (quote_page, 'quote-page'); -- add to maint cat if |quote-page= value begins with what looks like p., pp., etc. if not nopp then quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_page}); else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_page}); end elseif utilities.is_set (quote_pages) then extra_text_in_page_check (quote_pages, 'quote-pages'); -- add to maint cat if |quote-pages= value begins with what looks like p., pp., etc. if tonumber(quote_pages) ~= nil and not nopp then -- if only digits, assume single page quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, quote_pages}); elseif not nopp then quote_prefix = utilities.substitute (cfg.messages['pp-prefix'], {sepc, quote_pages}); else quote_prefix = utilities.substitute (cfg.messages['nopp'], {sepc, quote_pages}); end end quote = quote_prefix .. ": " .. quote; else quote = sepc .. " " .. quote; end postscript = ""; -- cs1|2 does not supply terminal punctuation when |quote= is set elseif utilities.is_set (quote_page) or utilities.is_set (quote_pages) then quote_page = nil; -- unset; these require |quote=; TODO: error message? quote_pages = nil; end return quote, quote_page, quote_pages, postscript; end --[[--------------------------< C H E C K _ P U B L I S H E R _ N A M E >-------------------------------------- look for variations of '<text>: <text>' that might be '<location>: <publisher>' in |publisher= parameter value. when found, emit a maintenance message; return nil else <publisher> is the value assigned to |publisher= or |institution= ]] local function check_publisher_name (publisher) local patterns_t = { '^[%w%s]+%s*:%s*[%w%s]+$', -- plain text <location>: <publisher> '^%[+[%w%s:|]+%]+%s*:%s*[%w%s]+$', -- partially wikilinked [[<location>]]: <publisher> '^[%w%s]+%s*:%s*%[+[%w%s:|]+%]+$', -- partially wikilinked <location>: [[<publisher>]] '^%[+[%w%s:|]+%]+%s*:%s*%[+[%w%s:|]+%]+$', -- wikilinked [[<location>]]: [[<publisher>]] } for _, pattern in ipairs (patterns_t) do -- spin through the patterns_t sequence if mw.ustring.match (publisher, pattern) then -- does this pattern match? utilities.set_message ('maint_publisher_location'); -- set a maint message return; -- and done end end end --[[--------------------------< I S _ P A G E _ A R T _ N U M >------------------------------------------------ compare the trailing (rightmost) characters of the |doi= value against the whole value assigned to |page(s)=. return boolean true when: |page(s)= has exactly 8 digits and a dot between the fourth and fifth digits matches the trailing 9 characters of the |doi= value: |page=12345678 → |page=1234.5678 matches |doi=10.xxxx/yyyy1234.5678 |page(s)= is 5 or more characters and matches |doi= values's trailing characters |page(s)= begins with a lowercase 'e' and |page(s)= without the 'e' matches |doi= values's trailing characters: |page=e12345 → |page=12345 matches |doi=10.xxxx/yyyy12345 |page(s)= begins with a uppercase 'CD' followed by (typically) six digits matches |doi= values that ends with 'CDxxxxxx.pubx' (where 'x' is any single digit) return nil when |page(s)= values: are ranges separated by underscore, hyphen, emdash, endash, figure dash, or minus character are comma- or semicolon-separated lists of pages have external urls (has text 'http') are digit-only values less than 10000 do not match |doi= values's trailing characters ]] local function is_page_art_num (page, doi) if not (utilities.is_set (page) and utilities.is_set (doi)) then -- both required return; -- abandon; nothing to do end if page:match ('[,;_−–—‒%-]') then -- when |page(s)= might be a page range or a separated list of pages return; -- abandon end page = page:lower(); -- because doi names are case insensitive doi = doi:lower(); -- force these to lowercase for testing if page:match ('http') then -- when |page(s)= appears to hold a url return; -- abandon end if tonumber (page) then -- is |page(s)= digits only if 10000 > tonumber (page) then -- when |page(s)= less than 10000 return; -- abandon end if doi:match (page .. '$') then -- digits only page number match the last digits in |doi=? return true; end if 8 == page:len() then -- special case when |page(s)= is exactly 8 digits local dot_page = page:gsub ('(%d%d%d%d)(%d%d%d%d)', '%1.%2'); -- make a |page=xxxx.yyyy version commonly used in |doi= if doi:match (dot_page .. '$') then -- 8-digit dotted page number match the last characters in |doi=? return true; end end else -- here when |page(s)= is alpha-numeric if 4 < page:len() then -- when |page(s)= is five or more characters if doi:match (page .. '$') then -- alpha-numeric page match the last characters in |doi=? return true; end local epage = page:match ('^e([%w]+)$'); -- if first character of |page= is 'e', remove it if epage and doi:match (epage .. '$') then -- page number match the last characters in |doi=? return true; end local cdpage = page:match ('^cd%d+$'); -- if first characters of |page= are 'CD' and last characters are digits (typically 6 digits) if cdpage and doi:match (cdpage .. '%.pub%d$') then -- page number matches doi 'CDxxxxxx.pubx' where 'x' is a digit return true; end end end end --[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------ This is the main function doing the majority of the citation formatting. ]] local function citation0( config, args ) --[[ Load Input Parameters The argument_wrapper facilitates the mapping of multiple aliases to single internal variable. ]] local A = argument_wrapper ( args ); -- Pick out the relevant fields from the arguments. Different citation templates -- define different field names for the same underlying things. local author_etal; local a = {}; -- authors list from |lastn= / |firstn= pairs or |vauthors= local Authors; local NameListStyle; if cfg.global_cs1_config_t['NameListStyle'] then -- global setting in {{cs1 config}} overrides local |name-list-style= parameter value; nil when empty or assigned value invalid NameListStyle = is_valid_parameter_value (cfg.global_cs1_config_t['NameListStyle'], 'cs1 config: name-list-style', cfg.keywords_lists['name-list-style'], ''); -- error messaging 'param' here is a hoax else NameListStyle = is_valid_parameter_value (A['NameListStyle'], A:ORIGIN('NameListStyle'), cfg.keywords_lists['name-list-style'], ''); end if cfg.global_cs1_config_t['NameListStyle'] and utilities.is_set (A['NameListStyle']) then -- when template has |name-list-style=<something> which global setting has overridden utilities.set_message ('maint_overridden_setting'); -- set a maint message end local Collaboration = A['Collaboration']; do -- to limit scope of selected local selected = select_author_editor_source (A['Vauthors'], A['Authors'], args, 'AuthorList'); if 1 == selected then a, author_etal = extract_names (args, 'AuthorList'); -- fetch author list from |authorn= / |lastn= / |firstn=, |author-linkn=, and |author-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be a, author_etal = parse_vauthors_veditors (args, A['Vauthors'], 'AuthorList'); -- fetch author list from |vauthors=, |author-linkn=, and |author-maskn= elseif 3 == selected then Authors = A['Authors']; -- use content of |people= or |credits=; |authors= is deprecated; TODO: constrain |people= and |credits= to cite av media, episode, serial? end if utilities.is_set (Collaboration) then author_etal = true; -- so that |display-authors=etal not required end end local editor_etal; local e = {}; -- editors list from |editor-lastn= / |editor-firstn= pairs or |veditors= do -- to limit scope of selected local selected = select_author_editor_source (A['Veditors'], nil, args, 'EditorList'); -- support for |editors= withdrawn if 1 == selected then e, editor_etal = extract_names (args, 'EditorList'); -- fetch editor list from |editorn= / |editor-lastn= / |editor-firstn=, |editor-linkn=, and |editor-maskn= elseif 2 == selected then NameListStyle = 'vanc'; -- override whatever |name-list-style= might be e, editor_etal = parse_vauthors_veditors (args, args.veditors, 'EditorList'); -- fetch editor list from |veditors=, |editor-linkn=, and |editor-maskn= end end local Chapter = A['Chapter']; -- done here so that we have access to |contribution= from |chapter= and |script-chapter= aliases local Chapter_origin = A:ORIGIN ('Chapter'); local ScriptChapter = A['ScriptChapter']; local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); local Contribution; -- because contribution is required for contributor(s) if 'contribution' == Chapter_origin then -- is there a |contribution= parameter? Contribution = Chapter; -- get the name of the contribution elseif 'script-contribution' == ScriptChapter_origin then -- no, so is there a |script-contribution= parameter? Contribution = ScriptChapter; -- get the name of the contribution end local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (A['Periodical']) then -- |contributor= and |contribution= only supported in book cites c = extract_names (args, 'ContributorList'); -- fetch contributor list from |contributorn= / |contributor-lastn=, -firstn=, -linkn=, -maskn= if 0 < #c then if not utilities.is_set (Contribution) then -- |contributor= requires |contribution= utilities.set_message ('err_contributor_missing_required_param', 'contribution'); -- add missing contribution error message c = {}; -- blank the contributors' table; it is used as a flag later end if 0 == #a then -- |contributor= requires |author= utilities.set_message ('err_contributor_missing_required_param', 'author'); -- add missing author error message c = {}; -- blank the contributors' table; it is used as a flag later end end else -- if not a book cite if utilities.select_one (args, cfg.aliases['ContributorList-Last'], 'err_redundant_parameters', 1 ) then -- are there contributor name list parameters? utilities.set_message ('err_contributor_ignored'); -- add contributor ignored error message end Contribution = nil; -- unset end local Title = A['Title']; local TitleLink = A['TitleLink']; local auto_select = ''; -- default is auto local accept_link; TitleLink, accept_link = utilities.has_accept_as_written (TitleLink, true); -- test for accept-this-as-written markup if (not accept_link) and utilities.in_array (TitleLink, {'none', 'pmc', 'doi'}) then -- check for special keywords auto_select = TitleLink; -- remember selection for later TitleLink = ''; -- treat as if |title-link= would have been empty end TitleLink = link_title_ok (TitleLink, A:ORIGIN ('TitleLink'), Title, 'title'); -- check for wiki-markup in |title-link= or wiki-markup in |title= when |title-link= is set local Section = ''; -- {{cite map}} only; preset to empty string for concatenation if not used if 'map' == config.CitationClass and 'section' == Chapter_origin then Section = A['Chapter']; -- get |section= from |chapter= alias list; |chapter= and the other aliases not supported in {{cite map}} Chapter = ''; -- unset for now; will be reset later from |map= if present end local Periodical = A['Periodical']; local Periodical_origin = A:ORIGIN('Periodical'); local ScriptPeriodical = A['ScriptPeriodical']; local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical'); local TransPeriodical = A['TransPeriodical']; local TransPeriodical_origin = A:ORIGIN ('TransPeriodical'); if (utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical))) then local param; if utilities.is_set (Periodical) then -- get a parameter name from one of these periodical related meta-parameters Periodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = Periodical_origin -- get parameter name for error messaging elseif utilities.is_set (TransPeriodical) then TransPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = TransPeriodical_origin; -- get parameter name for error messaging elseif utilities.is_set (ScriptPeriodical) then ScriptPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters param = ScriptPeriodical_origin; -- get parameter name for error messaging end if utilities.is_set (param) then -- if we found one utilities.set_message ('err_periodical_ignored', {param}); -- emit an error message end end if utilities.is_set (Periodical) then local i; Periodical, i = utilities.strip_apostrophe_markup (Periodical); -- strip apostrophe markup so that metadata isn't contaminated if i then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {Periodical_origin}); end end if 'mailinglist' == config.CitationClass then -- special case for {{cite mailing list}} if utilities.is_set (Periodical) and utilities.is_set (A ['MailingList']) then -- both set emit an error TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', Periodical_origin) .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'mailinglist')}); end Periodical = A ['MailingList']; -- error or no, set Periodical to |mailinglist= value because this template is {{cite mailing list}} Periodical_origin = A:ORIGIN('MailingList'); end -- web and news not tested for now because of -- Wikipedia:Administrators%27_noticeboard#Is_there_a_semi-automated_tool_that_could_fix_these_annoying_"Cite_Web"_errors? if not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) then -- 'periodical' templates require periodical parameter -- local p = {['journal'] = 'journal', ['magazine'] = 'magazine', ['news'] = 'newspaper', ['web'] = 'website'}; -- for error message local p = {['journal'] = 'journal', ['magazine'] = 'magazine'}; -- for error message if p[config.CitationClass] then utilities.set_message ('err_missing_periodical', {config.CitationClass, p[config.CitationClass]}); end end local Volume; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) then if not utilities.in_array (Periodical_origin, cfg.citation_no_volume_t) then -- {{citation}} does not render |volume= when these parameters are used Volume = A['Volume']; -- but does for all other 'periodicals' end elseif utilities.is_set (ScriptPeriodical) then if 'script-website' ~= ScriptPeriodical_origin then -- {{citation}} does not render volume for |script-website= Volume = A['Volume']; -- but does for all other 'periodicals' end else Volume = A['Volume']; -- and does for non-'periodical' cites end elseif utilities.in_array (config.CitationClass, cfg.templates_using_volume) then -- render |volume= for cs1 according to the configuration settings Volume = A['Volume']; end extra_text_in_vol_iss_check (Volume, A:ORIGIN ('Volume'), 'v'); local Issue; if 'citation' == config.CitationClass then if utilities.is_set (Periodical) and utilities.in_array (Periodical_origin, cfg.citation_issue_t) then -- {{citation}} may render |issue= when these parameters are used Issue = A['Issue']; end elseif utilities.in_array (config.CitationClass, cfg.templates_using_issue) then -- conference & map books do not support issue; {{citation}} listed here because included in settings table if not (utilities.in_array (config.CitationClass, {'conference', 'map', 'citation'}) and not (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical))) then Issue = A['Issue']; end end local ArticleNumber; if utilities.in_array (config.CitationClass, {'journal', 'conference'}) or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then ArticleNumber = A['ArticleNumber']; end extra_text_in_vol_iss_check (Issue, A:ORIGIN ('Issue'), 'i'); Issue = utilities.hyphen_to_dash (Issue); local Page; local Pages; local At; local QuotePage; local QuotePages; if not utilities.in_array (config.CitationClass, cfg.templates_not_using_page) then -- TODO: rewrite to emit ignored parameter error message? Page = A['Page']; Pages = utilities.hyphen_to_dash (A['Pages']); At = A['At']; QuotePage = A['QuotePage']; QuotePages = utilities.hyphen_to_dash (A['QuotePages']); end local NoPP = is_valid_parameter_value (A['NoPP'], A:ORIGIN('NoPP'), cfg.keywords_lists['yes_true_y'], nil); local Mode = mode_set (A['Mode'], A:ORIGIN('Mode')); -- separator character and postscript local sepc, PostScript = set_style (Mode:lower(), A['PostScript'], config.CitationClass); local Quote; Quote, QuotePage, QuotePages, PostScript = quote_make (A['Quote'], A['TransQuote'], A['ScriptQuote'], QuotePage, QuotePages, NoPP, sepc, PostScript); local Edition = A['Edition']; local PublicationPlace = place_check (A['PublicationPlace'], A:ORIGIN('PublicationPlace')); local Place = place_check (A['Place'], A:ORIGIN('Place')); local PublisherName = A['PublisherName']; local PublisherName_origin = A:ORIGIN('PublisherName'); if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then local i; PublisherName, i = utilities.strip_apostrophe_markup (PublisherName); -- strip apostrophe markup so that metadata isn't contaminated; publisher is never italicized if i and (0 < i) then -- non-zero when markup was stripped so emit an error message utilities.set_message ('err_apostrophe_markup', {PublisherName_origin}); end end if ('document' == config.CitationClass) and not utilities.is_set (PublisherName) then utilities.set_message ('err_missing_publisher', {config.CitationClass, 'publisher'}); end local Newsgroup = A['Newsgroup']; -- TODO: strip apostrophe markup? local Newsgroup_origin = A:ORIGIN('Newsgroup'); if 'newsgroup' == config.CitationClass then if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then -- general use parameter |publisher= not allowed in cite newsgroup utilities.set_message ('err_parameter_ignored', {PublisherName_origin}); end PublisherName = nil; -- ensure that this parameter is unset for the time being; will be used again after COinS end if 'book' == config.CitationClass or 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then local accept; PublisherName, accept = utilities.has_accept_as_written (PublisherName); -- check for and remove accept-as-written markup from |publisher= wrapped if not accept then -- when no accept-as-written markup check_publisher_name (PublisherName); -- emit maint message when |publisher= might be prefixed with publisher's location end end local URL = A['URL']; -- TODO: better way to do this for URL, ChapterURL, and MapURL? local UrlAccess = is_valid_parameter_value (A['UrlAccess'], A:ORIGIN('UrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (URL) and utilities.is_set (UrlAccess) then UrlAccess = nil; utilities.set_message ('err_param_access_requires_param', 'url'); end local ChapterURL = A['ChapterURL']; local ChapterUrlAccess = is_valid_parameter_value (A['ChapterUrlAccess'], A:ORIGIN('ChapterUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (ChapterURL) and utilities.is_set (ChapterUrlAccess) then ChapterUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {A:ORIGIN('ChapterUrlAccess'):gsub ('%-access', '')}); end local MapUrlAccess = is_valid_parameter_value (A['MapUrlAccess'], A:ORIGIN('MapUrlAccess'), cfg.keywords_lists['url-access'], nil); if not utilities.is_set (A['MapURL']) and utilities.is_set (MapUrlAccess) then MapUrlAccess = nil; utilities.set_message ('err_param_access_requires_param', {'map-url'}); end local this_page = mw.title.getCurrentTitle(); -- also used for COinS and for language local no_tracking_cats = is_valid_parameter_value (A['NoTracking'], A:ORIGIN('NoTracking'), cfg.keywords_lists['yes_true_y'], nil); -- check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories if not utilities.is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page if cfg.uncategorized_namespaces[this_page.namespace] then -- is this page's namespace id one of the uncategorized namespace ids? no_tracking_cats = "true"; -- set no_tracking_cats end for _, v in ipairs (cfg.uncategorized_subpages) do -- cycle through page name patterns if this_page.text:match (v) then -- test page name against each pattern no_tracking_cats = "true"; -- set no_tracking_cats break; -- bail out if one is found end end end -- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it) utilities.select_one (args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'err_redundant_parameters'); -- this is a dummy call simply to get the error message and category local coins_pages; Page, Pages, At, coins_pages = insource_loc_get (Page, A:ORIGIN('Page'), Pages, A:ORIGIN('Pages'), At); if utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- both |publication-place= and |place= (|location=) allowed if different utilities.add_prop_cat ('location-test'); -- add property cat to evaluate how often PublicationPlace and Place are used together if PublicationPlace == Place then Place = ''; -- unset; don't need both if they are the same end elseif not utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- when only |place= (|location=) is set ... PublicationPlace = Place; -- promote |place= (|location=) to |publication-place end if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same local URL_origin = A:ORIGIN('URL'); -- get name of parameter that holds URL local ChapterURL_origin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL -- local ScriptChapter = A['ScriptChapter']; -- local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); local Format = A['Format']; local ChapterFormat = A['ChapterFormat']; local TransChapter = A['TransChapter']; local TransChapter_origin = A:ORIGIN ('TransChapter'); local TransTitle = A['TransTitle']; local ScriptTitle = A['ScriptTitle']; --[[ Parameter remapping for cite encyclopedia: When the citation has these parameters: |encyclopedia= and |title= then map |title= to |article= and |encyclopedia= to |title= for rendering |encyclopedia= and |article= then map |encyclopedia= to |title= for rendering |trans-title= maps to |trans-chapter= when |title= is re-mapped |url= maps to |chapter-url= when |title= is remapped All other combinations of |encyclopedia=, |title=, and |article= are not modified ]] local Encyclopedia = A['Encyclopedia']; -- used as a flag by this module and by ~/COinS local ScriptEncyclopedia = A['ScriptEncyclopedia']; local TransEncyclopedia = A['TransEncyclopedia']; if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then -- emit error message when Encyclopedia set but template is other than {{cite encyclopedia}} or {{citation}} if 'encyclopaedia' ~= config.CitationClass and 'citation' ~= config.CitationClass then if utilities.is_set (Encyclopedia) then utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('Encyclopedia')}); else utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('ScriptEncyclopedia')}); end Encyclopedia = nil; -- unset these because not supported by this template ScriptEncyclopedia = nil; TransEncyclopedia = nil; end elseif utilities.is_set (TransEncyclopedia) then utilities.set_message ('err_trans_missing_title', {'encyclopedia'}); end if ('encyclopaedia' == config.CitationClass) or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Periodical) and utilities.is_set (Encyclopedia) then -- when both parameters set emit an error message; {{citation}} only; Periodical not allowed in {{cite encyclopedia}} utilities.set_message ('err_periodical_ignored', {Periodical_origin}); end if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then Periodical = Encyclopedia; -- error or no, set Periodical to Encyclopedia for rendering; {{citation}} could (not legitimately) have both; use Encyclopedia Periodical_origin = A:ORIGIN ('Encyclopedia'); ScriptPeriodical = ScriptEncyclopedia; ScriptPeriodical_origin = A:ORIGIN ('ScriptEncyclopedia'); if utilities.is_set (Title) or utilities.is_set (ScriptTitle) then if not utilities.is_set (Chapter) then Chapter = Title; -- |encyclopedia= and |title= are set so map |title= params to |article= params for rendering ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle') TransChapter = TransTitle; ChapterURL = URL; ChapterURL_origin = URL_origin; ChapterUrlAccess = UrlAccess; ChapterFormat = Format; if not utilities.is_set (ChapterURL) and utilities.is_set (TitleLink) then Chapter = utilities.make_wikilink (TitleLink, Chapter); end Title = Periodical; -- now map |encyclopedia= params to |title= params for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; URL = ''; Format = ''; TitleLink = ''; end elseif utilities.is_set (Chapter) or utilities.is_set (ScriptChapter) then -- |title= not set Title = Periodical; -- |encyclopedia= set and |article= set so map |encyclopedia= to |title= for rendering ScriptTitle = ScriptPeriodical or ''; TransTitle = TransEncyclopedia or ''; Periodical = ''; -- redundant so unset ScriptPeriodical = ''; end end end -- special case for cite techreport. local ID = A['ID']; if (config.CitationClass == "techreport") then -- special case for cite techreport if utilities.is_set (A['Number']) then -- cite techreport uses 'number', which other citations alias to 'issue' if not utilities.is_set (ID) then -- can we use ID for the "number"? ID = A['Number']; -- yes, use it else -- ID has a value so emit error message utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'id') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'number')}); end end end -- Account for the oddity that is {{cite conference}}, before generation of COinS data. local ChapterLink -- = A['ChapterLink']; -- deprecated as a parameter but still used internally by cite episode local Conference = A['Conference']; local BookTitle = A['BookTitle']; local TransTitle_origin = A:ORIGIN ('TransTitle'); if 'conference' == config.CitationClass then if utilities.is_set (BookTitle) then Chapter = Title; Chapter_origin = 'title'; -- ChapterLink = TitleLink; -- |chapter-link= is deprecated ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; URL_origin = ''; ChapterFormat = Format; TransChapter = TransTitle; TransChapter_origin = TransTitle_origin; Title = BookTitle; Format = ''; -- TitleLink = ''; TransTitle = ''; URL = ''; end elseif 'speech' ~= config.CitationClass then Conference = ''; -- not cite conference or cite speech so make sure this is empty string end local cs2_lower = function (text) -- if mode is cs2, use lower case if (sepc ~= '.') then return text:lower(); end return text; end local use_lowercase = ( sepc == ',' ); -- controls capitalization of certain static text -- cite map oddities local Cartography = ""; local Scale = ""; local Sheet = A['Sheet'] or ''; local Sheets = A['Sheets'] or ''; if config.CitationClass == "map" then if utilities.is_set (Chapter) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'map') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', Chapter_origin)}); -- add error message end Chapter = A['Map']; Chapter_origin = A:ORIGIN('Map'); -- for now, ignore linter warning ChapterURL = A['MapURL']; ChapterURL_origin = A:ORIGIN('MapURL'); TransChapter = A['TransMap']; ScriptChapter = A['ScriptMap'] ScriptChapter_origin = A:ORIGIN('ScriptMap') ChapterUrlAccess = MapUrlAccess; ChapterFormat = A['MapFormat']; Cartography = A['Cartography']; if utilities.is_set ( Cartography ) then Cartography = sepc .. " " .. wrap_msg ('cartography', Cartography, use_lowercase); end Scale = A['Scale']; if utilities.is_set ( Scale ) then Scale = sepc .. " " .. Scale; end end -- Account for the oddities that are {{cite episode}} and {{cite serial}}, before generation of COinS data. local Series = A['Series']; if 'episode' == config.CitationClass or 'serial' == config.CitationClass then local SeriesLink = A['SeriesLink']; SeriesLink = link_title_ok (SeriesLink, A:ORIGIN ('SeriesLink'), Series, 'series'); -- check for wiki-markup in |series-link= or wiki-markup in |series= when |series-link= is set local Network = A['Network']; local Station = A['Station']; local s, n = {}, {}; -- do common parameters first if utilities.is_set (Network) then table.insert(n, Network); end if utilities.is_set (Station) then table.insert(n, Station); end ID = table.concat(n, sepc .. ' '); if 'episode' == config.CitationClass then -- handle the oddities that are strictly {{cite episode}} local Season = A['Season']; local SeriesNumber = A['SeriesNumber']; if utilities.is_set (Season) and utilities.is_set (SeriesNumber) then -- these are mutually exclusive so if both are set TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'season') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'seriesno')}); -- add error message SeriesNumber = ''; -- unset; prefer |season= over |seriesno= end -- assemble a table of parts concatenated later into Series if utilities.is_set (Season) then table.insert(s, wrap_msg ('season', Season, use_lowercase)); end if utilities.is_set (SeriesNumber) then table.insert(s, wrap_msg ('seriesnum', SeriesNumber, use_lowercase)); end if utilities.is_set (Issue) then table.insert(s, wrap_msg ('episode', Issue, use_lowercase)); end Issue = ''; -- unset because this is not a unique parameter Chapter = Title; -- promote title parameters to chapter ScriptChapter = ScriptTitle; ScriptChapter_origin = A:ORIGIN('ScriptTitle'); ChapterLink = TitleLink; -- alias |episode-link= TransChapter = TransTitle; ChapterURL = URL; ChapterUrlAccess = UrlAccess; ChapterURL_origin = URL_origin; ChapterFormat = Format; Title = Series; -- promote series to title TitleLink = SeriesLink; Series = table.concat(s, sepc .. ' '); -- this is concatenation of season, seriesno, episode number if utilities.is_set (ChapterLink) and not utilities.is_set (ChapterURL) then -- link but not URL Chapter = utilities.make_wikilink (ChapterLink, Chapter); elseif utilities.is_set (ChapterLink) and utilities.is_set (ChapterURL) then -- if both are set, URL links episode; Series = utilities.make_wikilink (ChapterLink, Series); end URL = ''; -- unset TransTitle = ''; ScriptTitle = ''; Format = ''; else -- now oddities that are cite serial Issue = ''; -- unset because this parameter no longer supported by the citation/core version of cite serial Chapter = A['Episode']; -- TODO: make |episode= available to cite episode someday? if utilities.is_set (Series) and utilities.is_set (SeriesLink) then Series = utilities.make_wikilink (SeriesLink, Series); end Series = utilities.wrap_style ('italic-title', Series); -- series is italicized end end -- end of {{cite episode}} stuff -- handle type parameter for those CS1 citations that have default values local TitleType = A['TitleType']; local Degree = A['Degree']; if utilities.in_array (config.CitationClass, {'AV-media-notes', 'document', 'interview', 'mailinglist', 'map', 'podcast', 'pressrelease', 'report', 'speech', 'techreport', 'thesis'}) then TitleType = set_titletype (config.CitationClass, TitleType); if utilities.is_set (Degree) and "Thesis" == TitleType then -- special case for cite thesis TitleType = Degree .. ' ' .. cfg.title_types ['thesis']:lower(); end end if utilities.is_set (TitleType) then -- if type parameter is specified TitleType = utilities.substitute ( cfg.messages['type'], TitleType); -- display it in parentheses -- TODO: Hack on TitleType to fix bunched parentheses problem end -- legacy: promote PublicationDate to Date if neither Date nor Year are set. local Date = A['Date']; local Date_origin; -- to hold the name of parameter promoted to Date; required for date error messaging local PublicationDate = A['PublicationDate']; local Year = A['Year']; if utilities.is_set (Year) then validation.year_check (Year); -- returns nothing; emits maint message when |year= doesn't hold a 'year' value end if not utilities.is_set (Date) then Date = Year; -- promote Year to Date Year = nil; -- make nil so Year as empty string isn't used for CITEREF if not utilities.is_set (Date) and utilities.is_set (PublicationDate) then -- use PublicationDate when |date= and |year= are not set Date = PublicationDate; -- promote PublicationDate to Date PublicationDate = ''; -- unset, no longer needed Date_origin = A:ORIGIN('PublicationDate'); -- save the name of the promoted parameter else Date_origin = A:ORIGIN('Year'); -- save the name of the promoted parameter end else Date_origin = A:ORIGIN('Date'); -- not a promotion; name required for error messaging end if PublicationDate == Date then PublicationDate = ''; end -- if PublicationDate is same as Date, don't display in rendered citation --[[ Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates. This must be done before we do COinS because here is where we get the date used in the metadata. Date validation supporting code is in Module:Citation/CS1/Date_validation ]] local DF = is_valid_parameter_value (A['DF'], A:ORIGIN('DF'), cfg.keywords_lists['df'], ''); if not utilities.is_set (DF) then DF = cfg.global_df; -- local |df= if present overrides global df set by {{use xxx date}} template end local ArchiveURL; local ArchiveDate; local ArchiveFormat = A['ArchiveFormat']; local archive_url_timestamp; -- timestamp from wayback machine url ArchiveURL, ArchiveDate, archive_url_timestamp = archive_url_check (A['ArchiveURL'], A['ArchiveDate']) ArchiveFormat = style_format (ArchiveFormat, ArchiveURL, 'archive-format', 'archive-url'); ArchiveURL, ArchiveDate = is_unique_archive_url (ArchiveURL, URL, ChapterURL, A:ORIGIN('ArchiveURL'), ArchiveDate); -- add error message when URL or ChapterURL == ArchiveURL local AccessDate = A['AccessDate']; local COinS_date = {}; -- holds date info extracted from |date= for the COinS metadata by Module:Date verification local DoiBroken = A['DoiBroken']; local Embargo = A['Embargo']; local anchor_year; -- used in the CITEREF identifier do -- create defined block to contain local variables date_parameters_list, mismatch local date_parameters_list = { -- AirDate has been promoted to Date so not necessary to check it ['access-date'] = {val = AccessDate, name = A:ORIGIN ('AccessDate')}, ['archive-date'] = {val = ArchiveDate, name = A:ORIGIN ('ArchiveDate')}, ['date'] = {val = Date, name = Date_origin}, ['doi-broken-date'] = {val = DoiBroken, name = A:ORIGIN ('DoiBroken')}, ['pmc-embargo-date'] = {val = Embargo, name = A:ORIGIN ('Embargo')}, ['publication-date'] = {val = PublicationDate, name = A:ORIGIN ('PublicationDate')}, ['year'] = {val = Year, name = A:ORIGIN ('Year')}, }; local error_list = {}; anchor_year, Embargo = validation.dates(date_parameters_list, COinS_date, error_list); if utilities.is_set (Year) and utilities.is_set (Date) then -- both |date= and |year= not normally needed; validation.year_date_check (Year, A:ORIGIN ('Year'), Date, A:ORIGIN ('Date'), error_list); end if 0 == #error_list then -- error free dates only; 0 when error_list is empty local modified = false; -- flag if utilities.is_set (DF) then -- if we need to reformat dates modified = validation.reformat_dates (date_parameters_list, DF); -- reformat to DF format, use long month names if appropriate end if true == validation.date_hyphen_to_dash (date_parameters_list) then -- convert hyphens to dashes where appropriate modified = true; utilities.set_message ('maint_date_format'); -- hyphens were converted so add maint category end -- for those wikis that can and want to have English date names translated to the local language; not supported at en.wiki if cfg.date_name_auto_xlate_enable and validation.date_name_xlate (date_parameters_list, cfg.date_digit_auto_xlate_enable ) then utilities.set_message ('maint_date_auto_xlated'); -- add maint cat modified = true; end if modified then -- if the date_parameters_list values were modified AccessDate = date_parameters_list['access-date'].val; -- overwrite date holding parameters with modified values ArchiveDate = date_parameters_list['archive-date'].val; Date = date_parameters_list['date'].val; DoiBroken = date_parameters_list['doi-broken-date'].val; PublicationDate = date_parameters_list['publication-date'].val; end if archive_url_timestamp and utilities.is_set (ArchiveDate) then validation.archive_date_check (ArchiveDate, archive_url_timestamp, DF); -- does YYYYMMDD in archive_url_timestamp match date in ArchiveDate end else utilities.set_message ('err_bad_date', {utilities.make_sep_list (#error_list, error_list)}); -- add this error message end end -- end of do if utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) or -- {{cite book}}, {{cite encyclopedia}}; TODO: {{cite conference}} and others? ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) or -- {{citation}} as an encylopedia citation ('citation' == config.CitationClass and not utilities.is_set (Periodical)) then -- {{citation}} as a book citation if utilities.is_set (PublicationPlace) then if not utilities.is_set (PublisherName) then local date = COinS_date.rftdate and tonumber (COinS_date.rftdate:match ('%d%d%d%d')); -- get year portion of COinS date (because in Arabic numerals); convert string to number if date and (1850 <= date) then -- location has no publisher; if date is 1850 or later utilities.set_message ('maint_location_no_publisher'); -- add maint cat end else -- PublisherName has a value if cfg.keywords_xlate['none'] == PublisherName then -- if that value is 'none' (only for book and encyclopedia citations) PublisherName = ''; -- unset end end end end local ID_list_t; -- sequence table of rendered identifiers local ID_list_coins_t; -- table of identifiers and their values from args; key is same as cfg.id_handlers's key local Class = A['Class']; -- arxiv class identifier local ID_support = { {A['ASINTLD'], 'ASIN', 'err_asintld_missing_asin', A:ORIGIN ('ASINTLD')}, {DoiBroken, 'DOI', 'err_doibroken_missing_doi', A:ORIGIN ('DoiBroken')}, {Embargo, 'PMC', 'err_embargo_missing_pmc', A:ORIGIN ('Embargo')}, } ID_list_t, ID_list_coins_t = identifiers.identifier_lists_get (args, { DoiBroken = DoiBroken, -- for |doi= ASINTLD = A['ASINTLD'], -- for |asin= Embargo = Embargo, -- for |pmc= Class = Class, -- for |arxiv= CitationClass = config.CitationClass, -- for |arxiv= Year=anchor_year, -- for |isbn= }, ID_support); for _, id in ipairs (ID_list_t) do -- search through the ID_list_t sequence looking for an ISBN identifier string if id:find ('ISBN', 3, true) then -- plain find, start at index 3 ([[ISBN) if 'citation' == config.CitationClass then -- catch ve/citoid malformed book cites in {{citation}} templates if utilities.is_set (Periodical) then -- when a |work= alias is set utilities.set_message ('maint_work_isbn'); -- add maint cat break; -- and abandon end elseif ({['journal'] = true, ['magazine'] = true, ['news'] = true, ['web'] = true})[config.CitationClass] then utilities.set_message ('maint_periodical_has_isbn'); -- add maint cat break; -- and abandon end end end -- if 'citation' == config.CitationClass then -- catch ve/citoid malformed book cites in {{citation}} templates -- for _, id in ipairs (ID_list_t) do -- search through the ID_list_t sequence looking for an ISBN identifier string -- if id:find ('ISBN', 3, true) then -- plain find, start at index 3 ([[ISBN) -- if utilities.is_set (Periodical) then -- when a |work= alias is set -- utilities.set_message ('maint_work_isbn'); -- add maint cat -- end -- end -- end -- end -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, {{cite ssrn}}, before generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv=, |citeseerx=, |medrxiv=, |ssrn= required for their templates if not (args[cfg.id_handlers[config.CitationClass:upper()].parameters[1]] or -- can't use ID_list_coins_t k/v table here because invalid parameters omitted args[cfg.id_handlers[config.CitationClass:upper()].parameters[2]]) then -- which causes unexpected parameter missing error message utilities.set_message ('err_' .. config.CitationClass .. '_missing'); -- add error message end Periodical = ({['arxiv'] = 'arXiv', ['biorxiv'] = 'bioRxiv', ['citeseerx'] = 'CiteSeerX', ['medrxiv'] = 'medRxiv', ['ssrn'] = 'Social Science Research Network'})[config.CitationClass]; end -- Link the title of the work if no |url= was provided, but we have a |pmc= or a |doi= with |doi-access=free if config.CitationClass == "journal" and not utilities.is_set (URL) and not utilities.is_set (TitleLink) and not utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) then -- TODO: remove 'none' once existing citations have been switched to 'off', so 'none' can be used as token for "no title" instead if 'none' ~= cfg.keywords_xlate[auto_select] then -- if auto-linking not disabled if identifiers.auto_link_urls[auto_select] then -- manual selection URL = identifiers.auto_link_urls[auto_select]; -- set URL to be the same as identifier's external link URL_origin = cfg.id_handlers[auto_select:upper()].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['pmc'] then -- auto-select PMC URL = identifiers.auto_link_urls['pmc']; -- set URL to be the same as the PMC external link if not embargoed URL_origin = cfg.id_handlers['PMC'].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= elseif identifiers.auto_link_urls['doi'] then -- auto-select DOI URL = identifiers.auto_link_urls['doi']; URL_origin = cfg.id_handlers['DOI'].parameters[1]; end end if utilities.is_set (URL) then -- set when using an identifier-created URL if utilities.is_set (AccessDate) then -- |access-date= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_accessdate_missing_url'); -- add an error message AccessDate = ''; -- unset end if utilities.is_set (ArchiveURL) then -- |archive-url= requires |url=; identifier-created URL is not |url= utilities.set_message ('err_archive_missing_url'); -- add an error message ArchiveURL = ''; -- unset end end end -- At this point fields may be nil if they weren't specified in the template use. We can use that fact. -- Test if citation has no title if not utilities.is_set (Title) and not utilities.is_set (TransTitle) and not utilities.is_set (ScriptTitle) then -- has special case for cite episode utilities.set_message ('err_citation_missing_title', {'episode' == config.CitationClass and 'series' or 'title'}); end if utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) and utilities.in_array (config.CitationClass, {'journal', 'citation'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and ('journal' == Periodical_origin or 'script-journal' == ScriptPeriodical_origin) then -- special case for journal cites Title = ''; -- set title to empty string utilities.set_message ('maint_untitled'); -- add maint cat end if 'journal' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then if is_page_art_num (((utilities.is_set (Page) and Page) or (utilities.is_set (Pages) and Pages)) or nil, ID_list_coins_t['DOI']) then -- does |page(s)= look like it holds an article number utilities.set_message ('maint_page_art_num'); -- add maint cat end end -- COinS metadata (see <http://ocoins.info/>) for automated parsing of citation information. -- handle the oddity that is cite encyclopedia and {{citation |encyclopedia=something}}. Here we presume that -- when Periodical, Title, and Chapter are all set, then Periodical is the book (encyclopedia) title, Title -- is the article title, and Chapter is a section within the article. So, we remap local coins_chapter = Chapter; -- default assuming that remapping not required local coins_title = Title; -- et tu if 'encyclopaedia' == config.CitationClass or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then if utilities.is_set (Chapter) and utilities.is_set (Title) and utilities.is_set (Periodical) then -- if all are used then coins_chapter = Title; -- remap coins_title = Periodical; end end local coins_author = a; -- default for coins rft.au if 0 < #c then -- but if contributor list coins_author = c; -- use that instead end -- this is the function call to COinS() local OCinSoutput = metadata.COinS({ ['Periodical'] = utilities.strip_apostrophe_markup (Periodical), -- no markup in the metadata ['Encyclopedia'] = Encyclopedia, -- just a flag; content ignored by ~/COinS ['Chapter'] = metadata.make_coins_title (coins_chapter, ScriptChapter), -- Chapter and ScriptChapter stripped of bold / italic / accept-as-written markup ['Degree'] = Degree; -- cite thesis only ['Title'] = metadata.make_coins_title (coins_title, ScriptTitle), -- Title and ScriptTitle stripped of bold / italic / accept-as-written markup ['PublicationPlace'] = PublicationPlace, ['Date'] = COinS_date.rftdate, -- COinS_date.* has correctly formatted date values if Date is valid; ['Season'] = COinS_date.rftssn, ['Quarter'] = COinS_date.rftquarter, ['Chron'] = COinS_date.rftchron, ['Series'] = Series, ['Volume'] = Volume, ['Issue'] = Issue, ['ArticleNumber'] = ArticleNumber, ['Pages'] = coins_pages or metadata.get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At, QuotePage, QuotePages}, 7)), -- pages stripped of external links ['Edition'] = Edition, ['PublisherName'] = PublisherName or Newsgroup, -- any apostrophe markup already removed from PublisherName ['URL'] = first_set ({ChapterURL, URL}, 2), ['Authors'] = coins_author, ['ID_list'] = ID_list_coins_t, ['RawPage'] = this_page.prefixedText, }, config.CitationClass); -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, and {{cite ssrn}} AFTER generation of COinS data. if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- we have set rft.jtitle in COinS to arXiv, bioRxiv, CiteSeerX, medRxiv, or ssrn now unset so it isn't displayed Periodical = ''; -- periodical not allowed in these templates; if article has been published, use cite journal end -- special case for cite newsgroup. Do this after COinS because we are modifying Publishername to include some static text if 'newsgroup' == config.CitationClass and utilities.is_set (Newsgroup) then PublisherName = utilities.substitute (cfg.messages['newsgroup'], external_link( 'news:' .. Newsgroup, Newsgroup, Newsgroup_origin, nil )); end local Editors; local EditorCount; -- used only for choosing {ed.) or (eds.) annotation at end of editor name-list local Contributors; -- assembled contributors name list local contributor_etal = nil; -- must be intentionally initialized local Translators; -- assembled translators name list local translator_etal = nil; -- must be intentionally initialized local t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= local Interviewers; local interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters local interviewer_etal = nil; -- must be intentionally initialized -- Now perform various field substitutions. -- We also add leading spaces and surrounding markup and punctuation to the -- various parts of the citation, but only when they are non-nil. do local last_first_list; local control = { format = NameListStyle, -- empty string, '&', 'amp', 'and', or 'vanc' maximum = nil, -- as if display-authors or display-editors not set mode = Mode }; do -- do editor name list first because the now unsupported coauthors used to modify control table local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayEditors'], A['DisplayEditors'], A:ORIGIN ('DisplayEditors'), #e); control.maximum, editor_etal = get_display_names (display_names, #e, editor_etal, param); Editors, EditorCount = list_people (control, e, editor_etal); if 1 == EditorCount and (true == editor_etal or 1 < #e) then -- only one editor displayed but includes etal then EditorCount = 2; -- spoof to display (eds.) annotation end end do -- now do interviewers local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayInterviewers'], A['DisplayInterviewers'], A:ORIGIN ('DisplayInterviewers'), #interviewers_list); control.maximum, interviewer_etal = get_display_names (display_names, #interviewers_list, interviewer_etal, param); Interviewers = list_people (control, interviewers_list, interviewer_etal); end do -- now do translators local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayTranslators'], A['DisplayTranslators'], A:ORIGIN ('DisplayTranslators'), #t); control.maximum, translator_etal = get_display_names (display_names, #t, translator_etal, param); Translators = list_people (control, t, translator_etal); end do -- now do contributors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayContributors'], A['DisplayContributors'], A:ORIGIN ('DisplayContributors'), #c); control.maximum, contributor_etal = get_display_names (display_names, #c, contributor_etal, param); Contributors = list_people (control, c, contributor_etal); end do -- now do authors local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayAuthors'], A['DisplayAuthors'], A:ORIGIN ('DisplayAuthors'), #a, author_etal); control.maximum, author_etal = get_display_names (display_names, #a, author_etal, param); last_first_list = list_people (control, a, author_etal); if utilities.is_set (Authors) then Authors, author_etal = name_has_etal (Authors, author_etal, false, 'authors'); -- find and remove variations on et al. if author_etal then Authors = Authors .. ' ' .. cfg.messages['et al']; -- add et al. to authors parameter end else Authors = last_first_list; -- either an author name list or an empty string end end -- end of do if utilities.is_set (Authors) and utilities.is_set (Collaboration) then Authors = utilities.substitute (cfg.messages['collaboration'], {Authors, Collaboration}); -- add collaboration after et al. end end local ConferenceFormat = A['ConferenceFormat']; local ConferenceURL = A['ConferenceURL']; ConferenceFormat = style_format (ConferenceFormat, ConferenceURL, 'conference-format', 'conference-url'); Format = style_format (Format, URL, 'format', 'url'); -- special case for chapter format so no error message or cat when chapter not supported if not (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia))) then ChapterFormat = style_format (ChapterFormat, ChapterURL, 'chapter-format', 'chapter-url'); end if not utilities.is_set (URL) then if utilities.in_array (config.CitationClass, {"web", "podcast", "mailinglist"}) or -- |url= required for {{cite web}}, {{cite podcast}}, and {{cite mailing list}} ('citation' == config.CitationClass and ('website' == Periodical_origin or 'script-website' == ScriptPeriodical_origin)) then -- and required for {{citation}} with |website= or |script-website= if not url_was_archive_today then -- is <URL> empty/missing because it was a deprecated archive.today url utilities.set_message ('err_cite_web_url'); -- no; emit an error message for an empty/ missing |url= end end -- do we have |accessdate= without either |url= or |chapter-url=? if utilities.is_set (AccessDate) and not utilities.is_set (ChapterURL) then -- ChapterURL may be set when URL is not set; utilities.set_message ('err_accessdate_missing_url'); AccessDate = ''; end end local UrlStatus = is_valid_parameter_value (A['UrlStatus'], A:ORIGIN('UrlStatus'), cfg.keywords_lists['url-status'], ''); local OriginalURL local OriginalURL_origin local OriginalFormat local OriginalAccess; UrlStatus = UrlStatus:lower(); -- used later when assembling archived text if utilities.is_set ( ArchiveURL ) then if utilities.is_set (ChapterURL) then -- if chapter-url= is set apply archive url to it OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text OriginalURL_origin = ChapterURL_origin; -- name of |chapter-url= parameter for error messages OriginalFormat = ChapterFormat; -- and original |chapter-format= if 'live' ~= UrlStatus then ChapterURL = ArchiveURL -- swap-in the archive's URL ChapterURL_origin = A:ORIGIN('ArchiveURL') -- name of |archive-url= parameter for error messages ChapterFormat = ArchiveFormat or ''; -- swap in archive's format ChapterUrlAccess = nil; -- restricted access levels do not make sense for archived URLs end elseif utilities.is_set (URL) then OriginalURL = URL; -- save copy of original source URL OriginalURL_origin = URL_origin; -- name of URL parameter for error messages OriginalFormat = Format; -- and original |format= OriginalAccess = UrlAccess; if 'live' ~= UrlStatus then -- if URL set then |archive-url= applies to it URL = ArchiveURL -- swap-in the archive's URL URL_origin = A:ORIGIN('ArchiveURL') -- name of archive URL parameter for error messages Format = ArchiveFormat or ''; -- swap in archive's format UrlAccess = nil; -- restricted access levels do not make sense for archived URLs end end elseif utilities.is_set (UrlStatus) then -- if |url-status= is set when |archive-url= is not set utilities.set_message ('maint_url_status'); -- add maint cat end if utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or -- if any of the 'periodical' cites except encyclopedia ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) then local chap_param; if utilities.is_set (Chapter) then -- get a parameter name from one of these chapter related meta-parameters chap_param = A:ORIGIN ('Chapter') elseif utilities.is_set (TransChapter) then chap_param = A:ORIGIN ('TransChapter') elseif utilities.is_set (ChapterURL) then chap_param = A:ORIGIN ('ChapterURL') elseif utilities.is_set (ScriptChapter) then chap_param = ScriptChapter_origin; else utilities.is_set (ChapterFormat) chap_param = A:ORIGIN ('ChapterFormat') end if utilities.is_set (chap_param) then -- if we found one utilities.set_message ('err_chapter_ignored', {chap_param}); -- add error message Chapter = ''; -- and set them to empty string to be safe with concatenation TransChapter = ''; -- for now, ignore linter warnings ChapterURL = ''; ScriptChapter = ''; ChapterFormat = ''; end else -- otherwise, format chapter / article title local no_quotes = false; -- default assume that we will be quoting the chapter parameter value if utilities.is_set (Contribution) and 0 < #c then -- if this is a contribution with contributor(s) if utilities.in_array (Contribution:lower(), cfg.keywords_lists.contribution) then -- and a generic contribution title no_quotes = true; -- then render it unquoted end end Chapter = format_chapter_title (ScriptChapter, ScriptChapter_origin, Chapter, TransChapter, TransChapter_origin, ChapterURL, ChapterURL_origin, no_quotes, ChapterUrlAccess); -- Contribution is also in Chapter if utilities.is_set (Chapter) then Chapter = Chapter .. ChapterFormat ; if 'map' == config.CitationClass and utilities.is_set (TitleType) then Chapter = Chapter .. ' ' .. TitleType; -- map annotation here; not after title end Chapter = Chapter .. sepc .. ' '; elseif utilities.is_set (ChapterFormat) then -- |chapter= not set but |chapter-format= is so ... Chapter = ChapterFormat .. sepc .. ' '; -- ... ChapterFormat has error message, we want to see it end end -- Format main title local plain_title = false; local accept_title; Title, accept_title = utilities.has_accept_as_written (Title, true); -- remove accept-this-as-written markup when it wraps all of <Title> if accept_title and ('' == Title) then -- only support forced empty for now "(())" Title = cfg.messages['notitle']; -- replace by predefined "No title" message -- TODO: utilities.set_message ( 'err_redundant_parameters', ...); -- issue proper error message instead of muting ScriptTitle = ''; -- just mute for now TransTitle = ''; -- just mute for now plain_title = true; -- suppress text decoration for descriptive title utilities.set_message ('maint_untitled'); -- add maint cat end if not accept_title then -- <Title> not wrapped in accept-as-written markup if '...' == Title:sub (-3) then -- if ellipsis is the last three characters of |title= Title = Title:gsub ('(%.%.%.)%.+$', '%1'); -- limit the number of dots to three elseif not mw.ustring.find (Title, '%.%s*%a%.$') and -- end of title is not a 'dot-(optional space-)letter-dot' initialism ... not mw.ustring.find (Title, '%s+%a%.$') then -- ...and not a 'space-letter-dot' initial (''Allium canadense'' L.) Title = mw.ustring.gsub(Title, '%' .. sepc .. '$', ''); -- remove any trailing separator character; sepc and ms.ustring() here for languages that use multibyte separator characters end if utilities.is_set (ArchiveURL) and is_archived_copy (Title) then utilities.set_message ('maint_archived_copy'); -- add maintenance category before we modify the content of Title end if is_generic ('generic_titles', Title) then utilities.set_message ('err_generic_title'); -- set an error message end end if (not plain_title) and (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'document', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or ('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) or ('map' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)))) then -- special case for cite map when the map is in a periodical treat as an article Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from module provided quote marks Title = utilities.wrap_style ('quoted-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); elseif plain_title or ('report' == config.CitationClass) then -- no styling for cite report and descriptive titles (otherwise same as above) Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-quoted-title', TransTitle ); -- for cite report, use this form for trans-title else Title = utilities.wrap_style ('italic-title', Title); Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after title is wrapped TransTitle = utilities.wrap_style ('trans-italic-title', TransTitle); end if utilities.is_set (TransTitle) then if utilities.is_set (Title) then TransTitle = " " .. TransTitle; else utilities.set_message ('err_trans_missing_title', {'title'}); end end if utilities.is_set (Title) then -- TODO: is this the right place to be making Wikisource URLs? if utilities.is_set (TitleLink) and utilities.is_set (URL) then utilities.set_message ('err_wikilink_in_url'); -- set an error message because we can't have both TitleLink = ''; -- unset end if not utilities.is_set (TitleLink) and utilities.is_set (URL) then Title = external_link (URL, Title, URL_origin, UrlAccess) .. TransTitle .. Format; URL = ''; -- unset these because no longer needed Format = ''; -- for now, ignore linter warning elseif utilities.is_set (TitleLink) and not utilities.is_set (URL) then local ws_url; ws_url = wikisource_url_make (TitleLink); -- ignore ws_label return; not used here if ws_url then Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title-link'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], TitleLink, Title}); Title = Title .. TransTitle; else Title = utilities.make_wikilink (TitleLink, Title) .. TransTitle; end else local ws_url, ws_label, L; -- Title has italic or quote markup by the time we get here which causes is_wikilink() to return 0 (not a wikilink) ws_url, ws_label, L = wikisource_url_make (Title:gsub('^[\'"]*(.-)[\'"]*$', '%1')); -- make ws URL from |title= interwiki link (strip italic or quote markup); link portion L becomes tooltip label if ws_url then Title = Title:gsub ('%b[]', ws_label); -- replace interwiki link with ws_label to retain markup Title = external_link (ws_url, Title .. '&nbsp;', 'ws link in title'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? Title = utilities.substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, Title}); Title = Title .. TransTitle; else Title = Title .. TransTitle; end end else Title = TransTitle; end if utilities.is_set (Place) then Place = " " .. wrap_msg ('written', Place, use_lowercase) .. sepc .. " "; end local ConferenceURL_origin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL if utilities.is_set (Conference) then if utilities.is_set (ConferenceURL) then Conference = external_link( ConferenceURL, Conference, ConferenceURL_origin, nil ); end Conference = sepc .. " " .. Conference .. ConferenceFormat; elseif utilities.is_set (ConferenceURL) then Conference = sepc .. " " .. external_link( ConferenceURL, nil, ConferenceURL_origin, nil ); end local Position = ''; if not utilities.is_set (Position) then local Minutes = A['Minutes']; local Time = A['Time']; if utilities.is_set (Minutes) then if utilities.is_set (Time) then --TODO: make a function for this and similar? utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'minutes') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'time')}); end Position = utilities.substitute (cfg.messages.minutes, Minutes); else if utilities.is_set (Time) then local TimeCaption = A['TimeCaption'] if not utilities.is_set (TimeCaption) then TimeCaption = cs2_lower(cfg.messages['event']); end Position = " " .. TimeCaption .. " " .. Time; end end else Position = " " .. Position; At = ''; end Page, Pages, Sheet, Sheets = format_pages_sheets (Page, Pages, Sheet, Sheets, config.CitationClass, Periodical_origin, sepc, NoPP, use_lowercase); At = utilities.is_set (At) and (sepc .. " " .. At) or ""; Position = utilities.is_set (Position) and (sepc .. " " .. Position) or ""; if config.CitationClass == 'map' then local Sections = A['Sections']; -- Section (singular) is an alias of Chapter so set earlier local Inset = A['Inset']; if utilities.is_set ( Inset ) then Inset = sepc .. " " .. wrap_msg ('inset', Inset, use_lowercase); end if utilities.is_set ( Sections ) then Section = sepc .. " " .. wrap_msg ('sections', Sections, use_lowercase); elseif utilities.is_set ( Section ) then Section = sepc .. " " .. wrap_msg ('section', Section, use_lowercase); end At = At .. Inset .. Section; end local Others = A['Others']; if utilities.is_set (Others) and 0 == #a and 0 == #e then -- add maint cat when |others= has value and used without |author=, |editor= if config.CitationClass == "AV-media-notes" or config.CitationClass == "audio-visual" then -- special maint for AV/M which has a lot of 'false' positives right now utilities.set_message ('maint_others_avm') else utilities.set_message ('maint_others'); end end Others = utilities.is_set (Others) and (sepc .. " " .. Others) or ""; if utilities.is_set (Translators) then Others = safe_join ({sepc .. ' ', wrap_msg ('translated', Translators, use_lowercase), Others}, sepc); end if utilities.is_set (Interviewers) then Others = safe_join ({sepc .. ' ', wrap_msg ('interview', Interviewers, use_lowercase), Others}, sepc); end local TitleNote = A['TitleNote']; TitleNote = utilities.is_set (TitleNote) and (sepc .. " " .. TitleNote) or ""; if utilities.is_set (Edition) then if Edition:match ('%f[%a][Ee]d%n?%.?$') or Edition:match ('%f[%a][Ee]dition$') then -- Ed, ed, Ed., ed., Edn, edn, Edn., edn. utilities.set_message ('err_extra_text_edition'); -- add error message end Edition = " " .. wrap_msg ('edition', Edition); else Edition = ''; end Series = utilities.is_set (Series) and wrap_msg ('series', {sepc, Series}) or ""; -- not the same as SeriesNum local Agency = A['Agency'] or ''; -- |agency= is supported by {{cite magazine}}, {{cite news}}, {{cite press release}}, {{cite web}}, and certain {{citation}} templates if utilities.is_set (Agency) then -- this testing done here because {{citation}} supports 'news' citations if utilities.in_array (config.CitationClass, {'magazine', 'news', 'pressrelease', 'web'}) or ('citation' == config.CitationClass and utilities.in_array (Periodical_origin, {"magazine", "newspaper", "work"})) then Agency = wrap_msg ('agency', {sepc, Agency}); -- format for rendering else Agency = ''; -- unset; not supported utilities.set_message ('err_parameter_ignored', {'agency'}); -- add error message end end Volume = format_volume_issue (Volume, Issue, ArticleNumber, config.CitationClass, Periodical_origin, sepc, use_lowercase); if utilities.is_set (AccessDate) then local retrv_text = " " .. cfg.messages['retrieved']; AccessDate = nowrap_date (AccessDate); -- wrap in nowrap span if date in appropriate format retrv_text = cs2_lower(retrv_text); -- if mode is cs2, lower case AccessDate = utilities.substitute (retrv_text, AccessDate); -- add retrieved text AccessDate = utilities.substitute (cfg.presentation['accessdate'], {sepc, AccessDate}); -- allow editors to hide accessdates end if utilities.is_set (ID) then ID = sepc .. " " .. ID; end local Docket = A['Docket']; if "thesis" == config.CitationClass and utilities.is_set (Docket) then ID = sepc .. " Docket " .. Docket .. ID; end if "report" == config.CitationClass and utilities.is_set (Docket) then -- for cite report when |docket= is set ID = sepc .. ' ' .. Docket; -- overwrite ID even if |id= is set end if utilities.is_set (URL) then URL = " " .. external_link( URL, nil, URL_origin, UrlAccess ); end -- We check length of PostScript here because it will have been nuked by -- the quote parameters. We'd otherwise emit a message even if there wasn't -- a displayed postscript. -- TODO: Should the max size (1) be configurable? -- TODO: Should we check a specific pattern? if utilities.is_set(PostScript) and mw.ustring.len(PostScript) > 1 then utilities.set_message ('maint_postscript') end local Archived; if utilities.is_set (ArchiveURL) then if not utilities.is_set (ArchiveDate) then -- ArchiveURL set but ArchiveDate not set utilities.set_message ('err_archive_missing_date'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end else if utilities.is_set (ArchiveDate) then -- ArchiveURL not set but ArchiveDate is set utilities.set_message ('err_archive_date_missing_url'); -- emit an error message ArchiveURL = ''; -- empty string for concatenation ArchiveDate = ''; -- empty string for concatenation end end if utilities.is_set (ArchiveURL) then if "live" == UrlStatus then if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cfg.messages['archived-live'], { external_link( ArchiveURL, cs2_lower(cfg.messages['archived']), A:ORIGIN('ArchiveURL'), nil) .. ArchiveFormat, ArchiveDate } ); else Archived = ''; end if not utilities.is_set (OriginalURL) then utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (OriginalURL) then -- UrlStatus is empty, 'dead', 'unfit', 'usurped', 'bot: unknown' if utilities.in_array (UrlStatus, {'unfit', 'usurped', 'bot: unknown'}) then Archived = sepc .. ' ' .. utilities.substitute ( cs2_lower(cfg.messages['archived-unfit']), ArchiveDate); if 'bot: unknown' == UrlStatus then utilities.set_message ('maint_bot_unknown'); -- and add a category if not already added else utilities.add_prop_cat ('unfit'); -- and add a category if not already added end else -- UrlStatus is empty, 'dead' if utilities.is_set (ArchiveDate) then Archived = sepc .. ' ' .. utilities.substitute ( cs2_lower(cfg.messages['archived-dead']), { external_link( OriginalURL, cfg.messages['original'], OriginalURL_origin, OriginalAccess ) .. OriginalFormat, ArchiveDate } ); else Archived = ''; -- unset for concatenation end end else -- OriginalUrl not set utilities.set_message ('err_archive_missing_url'); Archived = ''; -- empty string for concatenation end elseif utilities.is_set (ArchiveFormat) then Archived = ArchiveFormat; -- if set and ArchiveURL not set ArchiveFormat has error message else Archived = ''; end local TranscriptURL = A['TranscriptURL'] local TranscriptFormat = A['TranscriptFormat']; TranscriptFormat = style_format (TranscriptFormat, TranscriptURL, 'transcript-format', 'transcripturl'); local Transcript = A['Transcript']; local TranscriptURL_origin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL if utilities.is_set (Transcript) then if utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, Transcript, TranscriptURL_origin, nil ); end Transcript = sepc .. ' ' .. Transcript .. TranscriptFormat; elseif utilities.is_set (TranscriptURL) then Transcript = external_link( TranscriptURL, nil, TranscriptURL_origin, nil ); end local Publisher; if utilities.is_set (PublicationDate) then PublicationDate = wrap_msg ('published', PublicationDate); end if utilities.is_set (PublisherName) then if utilities.is_set (PublicationPlace) then Publisher = sepc .. " " .. PublicationPlace .. ": " .. PublisherName .. PublicationDate; else Publisher = sepc .. " " .. PublisherName .. PublicationDate; end elseif utilities.is_set (PublicationPlace) then Publisher= sepc .. " " .. PublicationPlace .. PublicationDate; else Publisher = PublicationDate; end -- Several of the above rely upon detecting this as nil, so do it last. if (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical)) then if utilities.is_set (Title) or utilities.is_set (TitleNote) then Periodical = sepc .. " " .. format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); else Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); end end local Language = A['Language']; if utilities.is_set (Language) then Language = language_parameter (Language); -- format, categories, name from ISO639-1, etc. else Language=''; -- language not specified so make sure this is an empty string; --[[ TODO: need to extract the wrap_msg from language_parameter so that we can solve parentheses bunching problem with Format/Language/TitleType ]] end --[[ Handle the oddity that is cite speech. This code overrides whatever may be the value assigned to TitleNote (through |department=) and forces it to be " (Speech)" so that the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided). ]] if "speech" == config.CitationClass then -- cite speech only TitleNote = TitleType; -- move TitleType to TitleNote so that it renders ahead of |event= TitleType = ''; -- and unset if utilities.is_set (Periodical) then -- if Periodical, perhaps because of an included |website= or |journal= parameter if utilities.is_set (Conference) then -- and if |event= is set Conference = Conference .. sepc .. " "; -- then add appropriate punctuation to the end of the Conference variable before rendering end end end -- Piece all bits together at last. Here, all should be non-nil. -- We build things this way because it is more efficient in LUA -- not to keep reassigning to the same string variable over and over. local tcommon; local tcommon2; -- used for book cite when |contributor= is set local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (Periodical) then -- special cases for book cites if utilities.is_set (Contributors) then -- when we are citing foreword, preface, introduction, etc. tcommon = safe_join ({Title, TitleNote}, sepc); -- author and other stuff will come after this and before tcommon2 tcommon2 = safe_join ({TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); else tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc); end elseif 'map' == config.CitationClass then -- special cases for cite map if utilities.is_set (Chapter) then -- map in a book; TitleType is part of Chapter tcommon = safe_join ({Title, Edition, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); elseif utilities.is_set (Periodical) then -- map in a periodical tcommon = safe_join ({Title, TitleType, Periodical, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc); else -- a sheet or stand-alone map tcommon = safe_join ({Title, TitleType, Edition, Scale, Series, Language, Cartography, Others, Publisher}, sepc); end elseif 'episode' == config.CitationClass then -- special case for cite episode tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Edition, Publisher}, sepc); else -- all other CS1 templates tcommon = safe_join ({Title, TitleNote, Conference, Periodical, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc); end if #ID_list_t > 0 then ID_list_t = safe_join( { sepc .. " ", table.concat( ID_list_t, sepc .. " " ), ID }, sepc ); else ID_list_t = ID; end local Via = A['Via']; Via = utilities.is_set (Via) and wrap_msg ('via', Via) or ''; local idcommon; if 'audio-visual' == config.CitationClass or 'episode' == config.CitationClass then -- special case for cite AV media & cite episode position transcript idcommon = safe_join( { ID_list_t, URL, Archived, Transcript, AccessDate, Via, Quote }, sepc ); else idcommon = safe_join( { ID_list_t, URL, Archived, AccessDate, Via, Quote }, sepc ); end local text; -- local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; local OrigDate = A['OrigDate']; OrigDate = utilities.is_set (OrigDate) and wrap_msg ('origdate', OrigDate) or ''; if utilities.is_set (Date) then if utilities.is_set (Authors) or utilities.is_set (Editors) then -- date follows authors or editors when authors not set Date = " (" .. Date .. ")" .. OrigDate .. sepc .. " "; -- in parentheses else -- neither of authors and editors set if (string.sub(tcommon, -1, -1) == sepc) then -- if the last character of tcommon is sepc Date = " " .. Date .. OrigDate; -- Date does not begin with sepc else Date = sepc .. " " .. Date .. OrigDate; -- Date begins with sepc end end end if utilities.is_set (Authors) then if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Authors termination Authors = terminate_name_list (Authors, sepc); -- when no date, terminate with 0 or 1 sepc and a space end if utilities.is_set (Editors) then local in_text = ''; local post_text; if utilities.is_set (Chapter) and 0 == #c then in_text = cfg.messages['in'] .. ' '; in_text = cs2_lower(in_text); -- lowercase for cs2 end if EditorCount <= 1 then post_text = ' (' .. cfg.messages['editor'] .. ')'; -- be consistent with no-author, no-date case else post_text = ' (' .. cfg.messages['editors'] .. ')'; end Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space end if utilities.is_set (Contributors) then -- book cite and we're citing the intro, preface, etc. local by_text = sepc .. ' ' .. cfg.messages['by'] .. ' '; by_text = cs2_lower(by_text); -- lowercase for cs2 Authors = by_text .. Authors; -- author follows title so tweak it here if utilities.is_set (Editors) and utilities.is_set (Date) then -- when Editors make sure that Authors gets terminated Authors = terminate_name_list (Authors, sepc); -- terminate with 0 or 1 sepc and a space end if (not utilities.is_set (Date)) then -- when date is set it's in parentheses; no Contributors termination Contributors = terminate_name_list (Contributors, sepc); -- terminate with 0 or 1 sepc and a space end text = safe_join( {Contributors, Date, Chapter, tcommon, Authors, Place, Editors, tcommon2, pgtext, idcommon }, sepc ); else text = safe_join( {Authors, Date, Chapter, Place, Editors, tcommon, pgtext, idcommon }, sepc ); end elseif utilities.is_set (Editors) then if utilities.is_set (Date) then if EditorCount <= 1 then Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editor']; else Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editors']; end else if EditorCount <= 1 then Editors = Editors .. " (" .. cfg.messages['editor'] .. ")" .. sepc .. " " else Editors = Editors .. " (" .. cfg.messages['editors'] .. ")" .. sepc .. " " end end text = safe_join( {Editors, Date, Chapter, Place, tcommon, pgtext, idcommon}, sepc ); else if utilities.in_array (config.CitationClass, {"journal", "citation"}) and utilities.is_set (Periodical) then text = safe_join( {Chapter, Place, tcommon, pgtext, Date, idcommon}, sepc ); else text = safe_join( {Chapter, Place, tcommon, Date, pgtext, idcommon}, sepc ); end end if utilities.is_set (PostScript) and PostScript ~= sepc then text = safe_join( {text, sepc}, sepc ); -- Deals with italics, spaces, etc. if '.' == sepc then -- remove final seperator if present text = text:gsub ('%' .. sepc .. '$', ''); -- dot must be escaped here else text = mw.ustring.gsub (text, sepc .. '$', ''); -- using ustring for non-dot sepc (likely a non-Latin character) end end text = safe_join( {text, PostScript}, sepc ); -- Now enclose the whole thing in a <cite> element local options_t = {}; options_t.class = cite_class_attribute_make (config.CitationClass, Mode); local Ref = is_valid_parameter_value (A['Ref'], A:ORIGIN('Ref'), cfg.keywords_lists['ref'], nil, true); -- nil when |ref=harv; A['Ref'] else if 'none' ~= cfg.keywords_xlate[(Ref and Ref:lower()) or ''] then local namelist_t = {}; -- holds selected contributor, author, editor name list local year = first_set ({Year, anchor_year}, 2); -- Year first for legacy citations and for YMD dates that require disambiguation if #c > 0 then -- if there is a contributor list namelist_t = c; -- select it elseif #a > 0 then -- or an author list namelist_t = a; elseif #e > 0 then -- or an editor list namelist_t = e; end local citeref_id; if #namelist_t > 0 then -- if there are names in namelist_t citeref_id = make_citeref_id (namelist_t, year); -- go make the CITEREF anchor if mw.uri.anchorEncode (citeref_id) == ((Ref and mw.uri.anchorEncode (Ref)) or '') then -- Ref may already be encoded (by {{sfnref}}) so citeref_id must be encoded before comparison utilities.set_message ('maint_ref_duplicates_default'); end else citeref_id = ''; -- unset end options_t.id = Ref or citeref_id; end if string.len (text:gsub('%b<>', '')) <= 2 then -- remove html and html-like tags; then get length of what remains; z.error_cats_t = {}; -- blank the categories list z.error_msgs_t = {}; -- blank the error messages list OCinSoutput = nil; -- blank the metadata string text = ''; -- blank the the citation utilities.set_message ('err_empty_citation'); -- set empty citation message and category end local render_t = {}; -- here we collect the final bits for concatenation into the rendered citation if is_preview_mode and (0 ~= #z.error_msgs_t or 0 ~= #z.maint_cats_t) then -- when in preview mode if not utilities.is_set (options_t.id) then -- and when this template has not created an anchor ID math.randomseed (tonumber (mw.getLanguage ('en'):formatDate ('U')) * 10000 + os.clock() * 10000); options_t.id = 'CITEREF_temp_preview_id_' .. math.random (100000, 999999); -- create temporary anchor ID for preview mode end end if utilities.is_set (options_t.id) then -- here we wrap the rendered citation in <cite ...>...</cite> tags options_t.id = mw.uri.anchorEncode(options_t.id); -- do this here; also used when adding preview warning messages table.insert (render_t, utilities.substitute (cfg.presentation['cite-id'], {options_t.id, mw.text.nowiki(options_t.class), text})); -- when |ref= is set or when there is a namelist else table.insert (render_t, utilities.substitute (cfg.presentation['cite'], {mw.text.nowiki(options_t.class), text})); -- when |ref=none or when namelist_t empty and |ref= is missing or is empty end if OCinSoutput then -- blanked when citation is 'empty' so don't bother to add boilerplate metadata span table.insert (render_t, utilities.substitute (cfg.presentation['ocins'], OCinSoutput)); -- format and append metadata to the citation end local template_name = cfg.citation_class_map_t[config.CitationClass]; local template_link = '[[Template:' .. template_name .. '|' .. template_name .. ']]'; local msg_prefix = '<code class="cs1-code">{{' .. template_link .. '}}</code>: '; if 0 ~= #z.error_msgs_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_e, {template_link, options_t.id})); table.insert (render_t, ' '); -- insert a space between citation and its error messages table.sort (z.error_msgs_t); -- sort the error messages list; sorting includes wrapping <span> and <code> tags; hidden-error sorts ahead of visible-error local hidden = true; -- presume that the only error messages emited by this template are hidden for _, v in ipairs (z.error_msgs_t) do -- spin through the list of error messages if v:find ('cs1-visible-error', 1, true) then -- look for the visible error class name hidden = false; -- found one; so don't hide the error message prefix break; -- and done because no need to look further end end z.error_msgs_t[1] = table.concat ({utilities.error_comment (msg_prefix, hidden), z.error_msgs_t[1]}); -- add error message prefix to first error message to prevent extraneous punctuation table.insert (render_t, table.concat (z.error_msgs_t, '; ')); -- make a big string of error messages and add it to the rendering end if 0 ~= #z.maint_cats_t then mw.addWarning (utilities.substitute (cfg.messages.warning_msg_m, {template_link, options_t.id})); table.sort (z.maint_cats_t); -- sort the maintenance messages list local maint_msgs_t = {}; -- here we collect all of the maint messages if 0 == #z.error_msgs_t then -- if no error messages table.insert (maint_msgs_t, msg_prefix); -- insert message prefix in maint message livery end for _, v in ipairs( z.maint_cats_t ) do -- append maintenance categories table.insert (maint_msgs_t, -- assemble new maint message and add it to the maint_msgs_t table table.concat ({v, ' (', utilities.substitute (cfg.messages[':cat wikilink'], v), ')'}) ); end table.insert (render_t, utilities.substitute (cfg.presentation['hidden-maint'], table.concat (maint_msgs_t, ' '))); -- wrap the group of maint messages with proper presentation and save end if not no_tracking_cats then local sort_key; local cat_wikilink = 'cat wikilink'; if cfg.enable_sort_keys then -- when namespace sort keys enabled local namespace_number = mw.title.getCurrentTitle().namespace; -- get namespace number for this wikitext sort_key = (0 ~= namespace_number and (cfg.name_space_sort_keys[namespace_number] or cfg.name_space_sort_keys.other)) or nil; -- get sort key character; nil for mainspace cat_wikilink = (not sort_key and 'cat wikilink') or 'cat wikilink sk'; -- make <cfg.messages> key end for _, v in ipairs (z.error_cats_t) do -- append error categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end if cfg.id_limits_data_load_fail then -- boolean true when load failed utilities.set_message ('maint_id_limit_load_fail'); -- done here because this maint cat emits no message end for _, v in ipairs (z.maint_cats_t) do -- append maintenance categories table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key})); end for _, v in ipairs (z.prop_cats_t) do -- append properties categories table.insert (render_t, utilities.substitute (cfg.messages['cat wikilink'], v)); -- no sort keys end end return table.concat (render_t); -- make a big string and done end --[[--------------------------< V A L I D A T E >-------------------------------------------------------------- Looks for a parameter's name in one of several whitelists. Parameters in the whitelist can have three values: true - active, supported parameters false - deprecated, supported parameters nil - unsupported parameters ]] local function validate (name, cite_class, empty) local enum_name; -- parameter name with enumerator (if any) replaced with '#' local state; local function state_test () -- local function to do testing of state values; operates on the upvalues <state> and <name> if true == state then return true; end -- valid actively supported parameter if false == state then if empty then return nil; end -- empty deprecated parameters are treated as unknowns deprecated_parameter (name); -- parameter is deprecated but still supported return true; end if 'tracked' == state then local base_name = name:gsub ('%d', ''); -- strip enumerators from parameter names that have them to get the base name utilities.add_prop_cat ('tracked-param', {base_name}, base_name); -- add a properties category; <base_name> modifies <key> return true; end return nil; end if 'string' ~= type (name) or name:find ('#') then -- # is a cs1|2 reserved character so parameters with # not permitted; positional params are 'number' type; not supported return nil; end -- replace enumerator digit(s) with # (|last25= becomes |last#=) (mw.ustring because non-Western 'local' digits) enum_name = mw.ustring.gsub (name, '%d+$', '#'); -- where enumerator is last charaters in parameter name (these to protect |s2cid=) enum_name = mw.ustring.gsub (enum_name, '%d+([%-l])', '#%1'); -- where enumerator is in the middle of the parameter name; |author#link= is the oddity if 'document' == cite_class then -- special case for {{cite document}} state = whitelist.document_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test () then return true; end return false; end if utilities.in_array (cite_class, whitelist.preprint_template_list_t) then -- limited parameter sets allowed for these templates state = whitelist.limited_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters if true == state_test () then return true; end state = whitelist.preprint_arguments_t[cite_class][name]; -- look in the parameter-list for the template identified by cite_class if true == state_test () then return true; end return false; -- not supported because not found or name is set to nil end -- end limited parameter-set templates if utilities.in_array (cite_class, whitelist.unique_param_template_list_t) then -- template-specific parameters for templates that accept parameters from the basic argument list state = whitelist.unique_arguments_t[cite_class][name]; -- look in the template-specific parameter-lists for the template identified by cite_class if true == state_test () then return true; end end -- if here, fall into general validation state = whitelist.common_parameters_t[enum_name]; -- all other templates; all normal parameters allowed; this list holds enumerated and nonenumerated parameters if true == state_test () then return true; end return false; -- not supported because not found or name is set to nil end --[=[-------------------------< I N T E R _ W I K I _ C H E C K >---------------------------------------------- check <value> for inter-language interwiki-link markup. <prefix> must be a MediaWiki-recognized language code. when these values have the form (without leading colon): [[<prefix>:link|label]] return label as plain-text [[<prefix>:link]] return <prefix>:link as plain-text return value as is else ]=] local function inter_wiki_check (parameter, value) local prefix = value:match ('%[%[(%a+):'); -- get an interwiki prefix if one exists local _; if prefix and cfg.inter_wiki_map[prefix:lower()] then -- if prefix is in the map, needs preceding colon so utilities.set_message ('err_bad_paramlink', parameter); -- emit an error message _, value, _ = utilities.is_wikilink (value); -- extract label portion from wikilink end return value; end --[[--------------------------< M I S S I N G _ P I P E _ C H E C K >------------------------------------------ Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal sign, compare the alphanumeric string to the list of cs1|2 parameters. If found, then the string is possibly a parameter that is missing its pipe. There are two tests made: {{cite ... |title=Title access-date=2016-03-17}} -- the first parameter has a value and whitespace separates that value from the missing pipe parameter name {{cite ... |title=access-date=2016-03-17}} -- the first parameter has no value (whitespace after the first = is trimmed by MediaWiki) cs1|2 shares some parameter names with XML/HTML attributes: class=, title=, etc. To prevent false positives XML/HTML tags are removed before the search. If a missing pipe is detected, this function adds the missing pipe maintenance category. ]] local function missing_pipe_check (parameter, value) local capture; value = value:gsub ('%b<>', ''); -- remove XML/HTML tags because attributes: class=, title=, etc. capture = value:match ('%s+(%a[%w%-]+)%s*=') or value:match ('^(%a[%w%-]+)%s*='); -- find and categorize parameters with possible missing pipes if capture and validate (capture) then -- if the capture is a valid parameter name utilities.set_message ('err_missing_pipe', parameter); end end --[[--------------------------< H A S _ E X T R A N E O U S _ P U N C T >-------------------------------------- look for extraneous terminal punctuation in most parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_punc (param, value) if 'number' == type (param) then return; end param = param:gsub ('%d+', '#'); -- enumerated name-list mask params allow terminal punct; normalize if cfg.punct_skip[param] then return; -- parameter name found in the skip table so done end if value:match ('[,;:]$') then utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end if value:match ('^=') then -- sometimes an extraneous '=' character appears ... utilities.set_message ('maint_extra_punct'); -- has extraneous punctuation; add maint cat end end --[[--------------------------< H A S _ T W L _ U R L >-------------------------------------------------------- look for The Wikipedia Library urls in url-holding parameters. TWL urls are accessible only for readers who are active extended confirmed Wikipedia editors. This function sets an error message when such urls are discovered and when appropriate, sets the |<param>-url-access=subscription. returns nothing. looks for: '.wikipedialibrary.idm.oclc.org' ]] local function has_twl_url (url_params_t, cite_args_t) local url_error_t = {}; -- sequence of url-holding parameters that have a TWL url for param, value in pairs (url_params_t) do if value:find ('%.wikipedialibrary%.idm%.oclc%.org') then -- has the TWL base url? table.insert (url_error_t, param); -- add parameter name to the error list end end if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); -- sor for error messaging for i, param in ipairs (url_error_t) do if cfg.url_access_map_t[param] then -- if <param> has a matching -access parameter cite_args_t[cfg.url_access_map_t[param]] = cfg.keywords_xlate.subscription; -- set |<param>-url-access=subscription end url_error_t[i] = utilities.wrap_style ('parameter', param); -- make the parameter pretty for error message end utilities.set_message ('err_param_has_twl_url', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< M I S C _ U R L _ D E T E C T >------------------------------------------------ look for miscellaneous urls that might be converted to, or are duplicates of, identifiers. ]] local misc_url_patterns_t = { 'idm%.oclc%.org', -- but not wikipedialibrary.idm.oclc.org; has_twl_url() 'https?://citeseerx?%.ist%.psu%.edu/', -- simplified so we catch all citeseer and citeseerx urls except ~/document/... (the 'new' form) } local ignore_patterns_t = { 'wikipedialibrary.idm.oclc.org', -- handled by has_twl_url() 'https?://citeseerx?%.ist%.psu%.edu/document', -- 'new'-form citeseerx urls that mostly work; ignore for now } local function misc_url_detect (url_params_t) local ignore_flag = false; for _, value in pairs (url_params_t) do for _, ignore_pattern in ipairs (ignore_patterns_t) do if value:find (ignore_pattern) then -- matches this ignore_pattern? ignore_flag = true; -- found a pattern to ignore break; -- end end if not ignore_flag then -- if ignore_flag is set then don't bother to test this url <value> for _, misc_pattern in ipairs (misc_url_patterns_t) do if value:find (misc_pattern) then -- matches this misc_pattern? utilities.set_message ('maint_misc_url'); -- found one; set the message return; -- and done; no need to test other <value>s end end end ignore_flag = false; -- reset end end --[[--------------------------< H A S _ E X T R A N E O U S _ U R L >------------------------------------------ look for extraneous url parameter values; parameters listed in skip table are not checked ]] local function has_extraneous_url (non_url_param_t) local url_error_t = {}; check_for_url (non_url_param_t, url_error_t); -- extraneous url check if 0 ~= #url_error_t then -- non-zero when there are errors table.sort (url_error_t); utilities.set_message ('err_param_has_ext_link', {utilities.make_sep_list (#url_error_t, url_error_t)}); -- add this error message end end --[[--------------------------< _ C I T A T I O N >------------------------------------------------------------ Module entry point frame – from template call (citation()); may be nil when called from another module args_t – table of all cs1|2 parameters in the template (the parent frame) config_t – table of template-supplied parameter (the #invoke frame) ]] local function _citation (frame, args_t, config_t) -- save a copy in case we need to display an error message in preview mode if not frame then frame = mw.getCurrentFrame(); -- if called from another module, get a frame for frame-provided functions end -- i18n: set the name that your wiki uses to identify sandbox subpages from sandbox template invoke (or can be set here) local sandbox = ((config_t.SandboxPath and '' ~= config_t.SandboxPath) and config_t.SandboxPath) or '/sandbox'; -- sandbox path from {{#invoke:Citation/CS1/sandbox|citation|SandboxPath=/...}} is_sandbox = nil ~= string.find (frame:getTitle(), sandbox, 1, true); -- is this invoke the sandbox module? sandbox = is_sandbox and sandbox or ''; -- use i18n sandbox to load sandbox modules when this module is the sandox; live modules else cfg = mw.loadData ('Module:Citation/CS1/Configuration' .. sandbox); -- load sandbox versions of support modules when {{#invoke:Citation/CS1/sandbox|...}}; live modules else whitelist = mw.loadData ('Module:Citation/CS1/Whitelist' .. sandbox); utilities = require ('Module:Citation/CS1/Utilities' .. sandbox); validation = require ('Module:Citation/CS1/Date_validation' .. sandbox); identifiers = require ('Module:Citation/CS1/Identifiers' .. sandbox); metadata = require ('Module:Citation/CS1/COinS' .. sandbox); utilities.set_selected_modules (cfg); -- so that functions in Utilities can see the selected cfg tables identifiers.set_selected_modules (cfg, utilities); -- so that functions in Identifiers can see the selected cfg tables and selected Utilities module validation.set_selected_modules (cfg, utilities); -- so that functions in Date validataion can see selected cfg tables and the selected Utilities module metadata.set_selected_modules (cfg, utilities); -- so that functions in COinS can see the selected cfg tables and selected Utilities module z = utilities.z; -- table of error and category tables in Module:Citation/CS1/Utilities local cite_args_t = {}; -- because args_t is the parent (template) frame args (which cannot be modified); params and their values will be placed here is_preview_mode = not utilities.is_set (frame:preprocess ('{{REVISIONID}}')); local suggestions = {}; -- table where we store suggestions if we need to loadData them local error_text; -- used as a flag local capture; -- the single supported capture when matching unknown parameters using patterns local empty_unknowns = {}; -- sequence table to hold empty unknown params for error message listing for k, v in pairs (args_t) do -- get parameters from the parent (template) frame v = mw.ustring.gsub (v, '^%s*(.-)%s*$', '%1'); -- trim leading/trailing whitespace; when v is only whitespace, becomes empty string if v ~= '' then if cfg.enum_needs_xlation and 'string' == type (k) then -- for wikis that set date_names['local_digits'] to non-western digits k = mw.ustring.gsub (k, '%d', cfg.date_names.local_digits); -- translate 'local' digits enumerators to Western 0-9 end if not validate( k, config_t.CitationClass ) then if type (k) ~= 'string' then -- exclude empty numbered parameters if v:match("%S+") ~= nil then error_text = utilities.set_message ('err_text_ignored', {v}); end elseif validate (k:lower(), config_t.CitationClass) then error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, k:lower()}); -- suggest the lowercase version of the parameter else if nil == suggestions.suggestions then -- if this table is nil then we need to load it suggestions = mw.loadData ('Module:Citation/CS1/Suggestions' .. sandbox); --load sandbox version of suggestion module when {{#invoke:Citation/CS1/sandbox|...}}; live module else end for pattern, param in pairs (suggestions.patterns) do -- loop through the patterns to see if we can suggest a proper parameter capture = k:match (pattern); -- the whole match if no capture in pattern else the capture if a match if capture then -- if the pattern matches param = utilities.substitute (param, capture); -- add the capture to the suggested parameter (typically the enumerator) if validate (param, config_t.CitationClass) then -- validate the suggestion to make sure that the suggestion is supported by this template (necessary for limited parameter lists) error_text = utilities.set_message ('err_parameter_ignored_suggest', {k, param}); -- set the suggestion error message else error_text = utilities.set_message ('err_parameter_ignored', {k}); -- suggested param not supported by this template v = ''; -- unset end end end if not utilities.is_set (error_text) then -- couldn't match with a pattern, is there an explicit suggestion? if (suggestions.suggestions[ k:lower() ] ~= nil) and validate (suggestions.suggestions[ k:lower() ], config_t.CitationClass) then utilities.set_message ('err_parameter_ignored_suggest', {k, suggestions.suggestions[ k:lower() ]}); else utilities.set_message ('err_parameter_ignored', {k}); v = ''; -- unset value assigned to unrecognized parameters (this for the limited parameter lists) end end end end cite_args_t[k] = v; -- save this parameter and its value elseif not utilities.is_set (v) then -- for empty parameters if not validate (k, config_t.CitationClass, true) then -- is this empty parameter a valid parameter k = ('' == k) and cfg.err_msg_supl.empty_str or k; -- when k is empty string (or was space(s) trimmed to empty string), replace with descriptive text table.insert (empty_unknowns, utilities.wrap_style ('parameter', k)); -- format for error message and add to the list end end end if 0 ~= #empty_unknowns then -- create empty unknown error message utilities.set_message ('err_param_unknown_empty', { 1 == #empty_unknowns and '' or 's', utilities.make_sep_list (#empty_unknowns, empty_unknowns) }); end local non_url_param_t = {}; -- table of parameters and values that are not url-holding parameters local url_param_t = {}; -- table of url-holding paramters and their values for k, v in pairs (cite_args_t) do if 'string' == type (k) then -- don't evaluate positional parameters has_invisible_chars (k, v); -- look for invisible characters end has_extraneous_punc (k, v); -- look for extraneous terminal punctuation in parameter values missing_pipe_check (k, v); -- do we think that there is a parameter that is missing a pipe? cite_args_t[k] = inter_wiki_check (k, v); -- when language interwiki-linked parameter missing leading colon replace with wiki-link label if 'string' == type (k) then -- when parameter k is not positional if not cfg.url_skip[k] then -- and not in url skip table non_url_param_t[k] = v; -- make a parameter/value list for extraneous url check else -- and is in url skip table (a url-holding parameter) url_param_t[k] = v; -- make a parameter/value list to check for values that are The Wikipedia Library url end end end if cfg.suppress_archive_today_urls then has_archive_today_url (cite_args_t); -- look for and suppress archive.today urls and dependent parameters for all templates end has_extraneous_url (non_url_param_t); -- look for url in parameter values where a url does not belong has_twl_url (url_param_t, cite_args_t); -- look for url-holding parameters that hold a The Wikipedia Library url misc_url_detect (url_param_t); -- look for url-holding parameters that hold certain miscellaneous urls return table.concat ({ frame:extensionTag ('templatestyles', '', {src='Module:Citation/CS1' .. sandbox .. '/styles.css'}), citation0 (config_t, cite_args_t) }); end --[[--------------------------< C I T A T I O N >-------------------------------------------------------------- Template entry point ]] local function citation (frame) local config_t = {}; -- table to store parameters from the module {{#invoke:}} local args_t = frame:getParent().args; -- get template's preset parameters for k, v in pairs (frame.args) do -- get parameters from the {{#invoke}} frame config_t[k] = v; -- args_t[k] = v; -- crude debug support that allows us to render a citation from module {{#invoke:}}; skips parameter validation; TODO: keep? end return _citation (frame, args_t, config_t) end --[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------ ]] return { citation = citation, -- template entry point _citation = _citation, -- module entry point } mzkfjlhyhvftcb93lj0ik7zu7t1myhw Iweghachi ọhịa 0 26171 736832 169491 2026-10-08T02:23:45Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736832 wikitext text/x-wiki [[Usòrò:Degraded_land_ready_for_forest_restoration.jpg|áká_ịkẹngạ|thumb|320x320px|N'afọ ndị 1980, òtù na-ahụ maka nchekwa dọrọ aka ná ntị na, ozugbo e bibiri ya, a pụghị iweghachi ọhịa ndị dị n'ebe okpomọkụ. Afọ iri atọ nke nyocha mweghachi ugbu a na-agbagha nke a: a) Ebe a dị na Doi Suthep-Pui National Park, N. Thailand e gburu ọhịa, kụọ ya n'ike ma kpọọ ya ọkụ. Ogwe osisi ojii bụ otu n'ime osisi ọhịa mbụ. Ndị obodo ahụ sonyeere ndị ọkà mmụta sayensị iji rụzie mmiri ha.]] [[Usòrò:1_year_after_planting_framework_tree_species.jpg|áká_ịkẹngạ|thumb|320x320px|b) Mgbochi ọkụ, ịzụlite mmelite okike na ịkụ ụdị osisi na-eme ka osisi na-eto n'elu okpokoro ahịhịa n'ime otu afọ.]] [[Usòrò:12_year_old_restoration_plot_Doi_Suthep-Pui_National_Park_N._Thailand.jpg|áká_ịkẹngạ|thumb|320x320px|c) Mgbe afọ iri na abụọ gasịrị, oké ọhịa ahụ e weghachiri eweghachiri jupụtara n'osisi osisi ojii.]] A na-akọwa mweghachi ọhịa dị ka ihe iji weghachite usoro gburugburu ebe obibi, nke na-eme ka mgbake nke ọdịdị ọhịa, ọrụ gburugburu ebe obibi na ọkwa dị iche iche dị iche iche na ndị na-ahụkarị Ohia Climax bụ gburugburu ebe obibi kwụsiri ike nke mepụtara biomass kachasị, mgbagwoju anya na ụdị dị iche iche nke ga-ekwe omume n'ime oke ihu igwe na ala nyere ma na-enweghị ọgba aghara sitere na ụmụ mmadụ (nkọwa ọzọ ebe a).  Ya mere oke ohia Climax bu ihe ebum n'obi na gburugburu ebe obibi, nke na-akọwapụta ebumnobi kachasị nke mweghachi nke ọhịa.  Ebe ọ bụ na ihu igwe bụ isi ihe na-ekpebi nhazi oke ọhịa, mgbanwe ihu igwe zuru ụwa ọnụ nwere ike ime ka ebumnobi mweghachi na-agbanwe agbanwe.<ref>Sgró, C.M., A. J. Lowe and A. A. Hoffmann, 2011. Building evolutionary resilience for conserving biodiversity under climate change. Evolutionary Applications 4 (2): 326-337</ref> Tụkwasị na nke a, a ghaghị iburu n'uche mmetụta mgbanwe ihu igwe nwere ike inwe na ebumnuche mweghachi, dịka mgbanwe na okpomọkụ na usoro mmiri ozuzo nwere ike ịgbanwe ihe mejupụtara na nkesa nke oké ọhịa.<ref>{{Cite journal|author=Hoegh-Guldberg|first=Ove|date=2010-06-18|title=The Impact of Climate Change on the World's Marine Ecosystems|url=https://www.science.org/doi/10.1126/science.1189930|journal=Science|language=en|volume=328|issue=5985|pages=1523–1528|doi=10.1126/science.1189930|pmid=20558709|issn=0036-8075}}</ref> Mweghachi nke ọhịa bụ ụdị pụrụ iche nke mweghachi osisi dị n'ókè ọhịa, ma ọ dị iche na ịkọ osisi a na-emekarị n'ihi na ihe mgbaru ọsọ ya bụ isi bụ mgbake nke ụdị dị iche iche na nchebe gburugburu ebe obibi..<ref name="Lamb">{{Cite book|title=Regreening the Bare Hills|author=Lamb|first=David|publisher=Springer|year=2011|isbn=978-90-481-9870-2|pages=547|url=https://www.springer.com/us/book/9789048198696|series=World Forests}}</ref><ref name="Stanturf">{{Cite book|title=Restoration of boreal and temperate forests|author=Stanturf|first=John A.|publisher=CRC Press|year=2005|location=Boca Raton|pages=3–11|chapter=What is forest restoration?|chapterurl=http://www.treesearch.fs.fed.us/pubs/22209}}</ref> A na-akọwa mweghachi ọhịa na ala (FLR) dị ka usoro nke na-achọ iweghachite ọrụ gburugburu ebe obibi ma melite ọdịmma mmadụ na ala ndị e gburu ma ọ bụ ndị mebiri emebi.<ref name=":0">{{Cite journal|title=Restoring the Earth – The next decade|url=https://doi.org/10.4060/cb1600en|journal=Unasylva|year=2020|volume=71 2020/1|issue=252|doi=10.4060/cb1600en}}</ref> E mepụtara FLR dị ka nzaghachi maka mmebi na-arịwanye elu na ọnwụ nke oké ọhịa na ala, nke mere ka mbelata nke ụdị dị iche iche na ọrụ gburugburu ebe obibi.<ref name=":0" /> FLR dị irè ga-akwado mmezu nke Ihe mgbaru ọsọ mmepe na-adịgide adịgide.<ref name=":0" /> Afọ iri nke United Nations na mweghachi nke gburugburu ebe obibi (20212030) na-enye ohere iji weghachite ọtụtụ narị nde hekta nke oké ọhịa mebiri emebi na gburugburu ebe obibi ndị ọzọ.<ref name=":0" /> Nweghachi gburugburu ebe obibi nke na-aga nke ọma chọrọ nghọta dị mkpa banyere njirimara gburugburu ebe obibi maka ụdị ndị mejupụtara ya, yana ihe ọmụma banyere otu ha si agbakọta, na-emekọrịta ihe ma na-arụ ọrụ dị ka obodo<ref>{{Cite journal|author=Pywell|first=Richard F.|date=February 2003|title=Plant traits as predictors of performance in ecological restoration: Plant traits as predictors of performance|url=http://doi.wiley.com/10.1046/j.1365-2664.2003.00762.x|journal=Journal of Applied Ecology|language=en|volume=40|issue=1|pages=65–77|doi=10.1046/j.1365-2664.2003.00762.x}}</ref> == Ebe ọ na-emetụta == Mweghachi ọhịa nwere ike ịgụnye naanị ichebe ahịhịa fọdụrụnụ (mgbochi ọkụ, mwepu ehi wdg) ma ọ bụ ntinye aka na-arụsi ọrụ ike iji mee ka mmelite okike dị ngwa, yana ịkụ osisi na / ma ọ bụ ịgha mkpụrụ (ịgha mkpụrụ kpọmkwem) nke ụdị nke ụdị nke usoro okike a na-achọ.<ref>{{Cite web|title=Assisted natural regeneration of forests|url=http://www.fao.org/forestry/anr/en/|work=www.fao.org|accessdate=2016-02-24|first=Food and Agriculture Organization of the United|author=Nations|archivedate=2019-04-26|archiveurl=https://web.archive.org/web/20190426155321/http://www.fao.org/forestry/anr/en/}}</ref> Ụdị osisi a kụrụ (ma ọ bụ gbaa ume ka ha guzobe) bụ ndị a na-ahụkarị, ma ọ bụ na-enye ọrụ dị oke mkpa na gburugburu ebe obibi, usoro gburugburu ebe obibi. Otú ọ dị, ebe ọ bụla ndị mmadụ bi na ma ọ bụ nso ebe nrụzigharị, ọrụ nrụzigharị na-agụnyekarị ụdị akụ na ụba n'etiti osisi ndị a kụrụ, iji nweta ihe oriri ma ọ bụ ngwaahịa na-emepụta ego. Mweghachi ọhịa bụ usoro na-agụnye, nke na-adabere na mmekorita n'etiti ọtụtụ ndị metụtara gụnyere obodo, ndị ọrụ gọọmentị, òtù ndị na-abụghị gọọmentị. A na-atụle ihe ịga nke ọma ya na gburugburu ebe obibi n'ihe gbasara mmụba nke ụdị dị iche iche, biomass, mmepụta mbụ, ihe ndị dị n'ala na ikike ijide mmiri, yana nloghachi nke ụdị dị ụkọ na nke dị mkpa, njirimara nke usoro gburugburu ebe obibi. Otú ọ dị, dị ka FAO si kwuo, ọrụ mweghachi na-eche ihe mgbochi akụ na ụba ihu site na enweghị nnukwu ego dị maka gọọmentị ruo na obere ihe onwunwe na ikike teknụzụ nke obere ndị nwe ya.<ref name=":2">{{Cite book|author=Garrett, L.|url=https://doi.org/10.4060/cc2510en|title=The key role of forest and landscape restoration in climate action|publisher=FAO|year=2022|isbn=978-92-5-137044-5|location=Rome}}</ref> Ihe ngosi akụ na ụba nke ihe ịga nke ọma gụnyere uru nke ngwaahịa ọhịa na ọrụ gburugburu ebe obibi mepụtara (dịka nchedo mmiri, nchekwa carbon wdg), nke na-eme ka e belata ịda ogbenye. Ịkwụ ụgwọ maka ọrụ gburugburu ebe obibi (PES) na ngwaahịa ọhịa nwere ike inye ndị obodo ike ịkpali imejuputa ọrụ mweghachi.<ref>{{Cite journal|author=Martínez de Aragón|first=Juan|title=Economically profitable post fire restoration with black truffle (Tuber melanosporum) producing plantations|journal=New Forests|date=2012|volume=43|issue=5–6|pages=615–630|doi=10.1007/s11056-012-9316-x}}</ref> E gosipụtara mweghachi dị irè iji mee ka mgbake carbon nke oké ọhịa ndị mmadụ gbanwere site na pasent 50.<ref>{{Cite journal|author=Philipson|first=CD|title=Active restoration accelerates the carbon recovery of human-modified tropical forests|journal=Science|date=2020|volume=369|issue=6505|pages=838–841|doi=10.1126/science.aay4490|pmid=32792397|url=https://nottingham-repository.worktribe.com/output/4846915}}</ref> Dị ka FAO si kwuo, Ọnọdụ Ọhịa Ụwa 2020, a chọrọ iweghachi oké ọhịa buru ibu iji mezuo ebumnuche mmepe na-adịgide adịgide na iji gbochie, kwụsị ma gbanwee ''ọnwụ nke'' ụdị dị iche iche. Ọ bụ ezie na mba iri isii na otu, n'ozuzu ha, kwere nkwa iweghachi nde hekta iri asaa nke ala ọhịa mebiri emebi n'okpuru ihe ịma aka Bonn, ọganihu ruo ugbu a dị nwayọ. Mweghachi ọhịa, mgbe etinyere ya n'ụzọ kwesịrị ekwesị, na-enyere aka weghachite ebe obibi na gburugburu ebe obibi, mepụta ọrụ na ego ma bụrụ ihe ngwọta dị irè nke ọdịdị maka mgbanwe ihu igwe. Ọzọkwa, dị ka FAO si kwuo, mweghachi ọhịa na ala na-enye ọtụtụ uru maka ihu igwe, gụnyere nchụpụ na mbelata gas na-ekpo ọkụ.<ref name=":2"/> Afọ iri nke United Nations na mweghachi gburugburu ebe obibi 20212030, mara ọkwa na Machị 2019, na-ezube ime ka ọrụ mweghachi gburugburu ụlọ dị n'ụwa niile dị ngwa.<ref>{{Cite book|url=https://doi.org/10.4060/ca8985en|title=The State of the World's Forests 2020. Forests, biodiversity and people –In brief|publisher=FAO & UNEP|year=2020|isbn=978-92-5-132707-4|location=Rome|doi=10.4060/ca8985en}}</ref> == Ohere maka iweghachi ọhịa == [[Usòrò:ESF-Forest-Restoration-Corner-2014.jpg|áká_èkpè|thumb|200x200px|Ihe ngosi nke mgbake ọhịa, SUNY-ESF, Syracuse, NY]] Mweghachi ọhịa kwesịrị ekwesị ebe ọ bụla mgbake nke ụdị dị iche iche bụ otu n'ime ebumnuche ndị isi nke ime ka ọhịa dịghachi, dị ka maka nchekwa anụ ọhịa, nchedo gburugburu ebe obibi, njem nleta gburugburu ebe obibi ma ọ bụ inye ọtụtụ ngwaahịa ọhịa dị iche iche na obodo ndị dị n'ógbè ahụ.<ref>{{Cite journal|author=Chazdon|first=Robin L.|authorlink=Robin Chazdon|date=2019-07-01|title=Global restoration opportunities in tropical rainforest landscapes|journal=Science Advances|language=en|volume=5|issue=7|pages=eaav3223|doi=10.1126/sciadv.aav3223|issn=2375-2548|pmid=31281881}}</ref> Enwere ike iweghachi ọhịa n'ọnọdụ dịgasị iche iche, mana ebe ndị mebiri emebi n'ime ebe echedoro bụ ihe kachasị mkpa, ọkachasị ebe ụfọdụ oké ọhịa na-anọgide dị ka isi iyi mkpụrụ n'ime ala. Ọbụna n'ebe ndị a na-echebe, a na-enwekarị nnukwu ebe ndị a na'oké ọhịa: ndị a na - ndị a na na-egbutu n'elu ebe ma ọ bụ ebe ndị a kpochapụrụ maka ọrụ ugbo. Ọ bụrụ na ebe ndị a na-echebe ga-arụ ọrụ dị ka ebe mgbaba anụ ọhịa ikpeazụ nke ụwa, a ga-achọ iweghachi ebe ndị dị otú ahụ.<ref name="Lamb"/><ref name="Stanturf"/> A na-etinye ọtụtụ ọrụ mweghachi ugbu a n'okpuru nchebe nke mweghachi ala nke oké ọhịa (FLR), akọwapụtara dị ka usoro a na-eme atụmatụ iji nwetaghachi iguzosi ike n'ezi ihe gburugburu ebe obibi ma melite ọdịmma mmadụ n'ọhịa ma ọ bụ ala mebiri emebi.<ref>Mansourian, S., D. Vallauri, and N. Dudley (eds.) (in co-operation with WWF International), 2005. Forest Restoration in Landscapes: Beyond Planting Trees. Springer, New York</ref> FLR ghọtara na mweghachi ọhịa nwere ọrụ mmekọrịta mmadụ na ibe ya na akụ na ụba. Ebumnuche ya bụ iji nweta nkwekọrịta kachasị mma n'etiti izute ebumnuche nchekwa na mkpa nke obodo ime obodo.<ref>Reitbergen-McCraken, J., S. Maginnis A. Sarre, 2007. The Forest Landscape Restoration Handbook. Earthscan, London, 175 pp.</ref> Ka nrụgide mmadụ na ala na-abawanye, a ga-emekarị mgbake ọhịa n'ime ụdị nchịkwa ọhịa ndị ọzọ, iji gboo mkpa akụ na ụba nke ndị obodo. Ebe a na-elekwasị anya na nso nso a maka mgbalị iweghachi ọhịa dị n'ime obodo ukwu, ebe ma ndị mmadụ na ụdị dị iche iche ga-erite uru, agbanyeghị, ọnọdụ a na-eweta ihe ịma aka pụrụ iche.<ref>{{Cite journal|author=Wallace|first=K. J.|title=Exotic weeds and fluctuating microclimate can constrain native plant regeneration in urban forest restoration|journal=Ecological Applications|date=2017|volume=27|issue=4|pages=1268–1279|doi=10.1002/eap.1520|pmid=28182314}}</ref> == Mweghachi okike == Ịkụ osisi abụghị mgbe niile ihe dị mkpa iji weghachite usoro okike ọhịa. Enwere ike inweta ọtụtụ ihe site n'ịmụ otú oké ọhịa si emelite n'ụzọ okike, ịchọpụta ihe ndị na-egbochi mmelite na ịmepụta ụzọ iji merie ha. Ihe ndị a nwere ike ịgụnye ịgha ahịhịa na ịgbakwunye fatịlaịza gburugburu mkpụrụ osisi, igbochi ọkụ, iwepụ ehi na ihe ndị ọzọ. Nke a bụ "mgbatị" ma ọ bụ "enyemaka" mmelite okike.<ref>Shono, K., E. A. Cadaweng and P. B. Durst, 2007. Application of Assisted Natural Regeneration to Restore Degraded Tropical Forestlands. Restoration Ecology, 15(4): 620–626.</ref> Ọ dị mfe ma dị ọnụ ala, mana ọ nwere ike ịrụ ọrụ naanị na osisi ndị dịlarị, ọtụtụ n'ime ha bụ ụdị ndị ọsụ ụzọ na-ahụ n'anya. Ụdị osisi ndị dị otú ahụ anaghị abụkarị ndị mejupụtara oké ọhịa climax, mana ha nwere ike ịkwalite recolonization nke saịtị ahụ site na ụdị osisi osisi climax na-anabata ndò, site na mgbasa mkpụrụ sitere n'oké ọhịa fọdụrụnụ. N'ihi na nke a bụ usoro na-adịghị ngwa ngwa, a na-enwekarị ike ịgbake mgbake nke ụdị dị iche iche site n'ịkụ ụdị osisi ụfọdụ dị n'oké ọhịa, ọkachasị nnukwu mkpụrụ, ụdị ndị na-adịghị agbasa agbasa. Ọ gaghị ekwe omume ịkụ ụdị osisi niile nke nwere ike itolite n'oge gara aga n'oké ọhịa mbụ ma ọ na-adịkarị mkpa ime ya, ma ọ bụrụ na enwere ike iji [[Framework species method|usoro]]<ref>Elliott S, Navakitbumrung P, Kuarak C, Zankum S, Anusarnsunthorn V, Blakesley D, 2003. Selecting framework tree species for restoring seasonally dry tropical forests in northern Thailand based on field performance. For Ecol Manage 184:177-191</ref> ụdị usoro. N'ọnọdụ ụfọdụ pụrụ iche, ọkachasị ụfọdụ oké ọhịa [[Àláskà|Alaska]], mgbake ogologo oge site na ọkụ ọhịa nwere ike iwepụ carbon na-apụta n'oge ọkụ ahụ n'ihi mgbanwe n'ụdị osisi ma ọ bụrụ na osisi ahụ na-anọgide, gosipụta na ọ bụ akụkụ nke biomes na-eguzogide ma dị ọtụtụ dị ka oké ọhịa mbụ.<ref>{{Cite news|author=Sawal|first=Ibrahim|title=Alaskan forests may store more carbon after being burned by wildfire|url=https://www.newscientist.com/article/2274752-alaskan-forests-may-store-more-carbon-after-being-burned-by-wildfire/|accessdate=9 May 2021|work=New Scientist}}</ref><ref>{{Cite journal|author=Mack|first=Michelle C.|title=Carbon loss from boreal forest wildfires offset by increased dominance of deciduous trees|journal=Science|date=16 April 2021|volume=372|issue=6539|pages=280–283|doi=10.1126/science.abf3903|pmid=33859032|url=https://www.science.org/doi/10.1126/science.abf3903|accessdate=9 May 2021|language=en|issn=0036-8075}}</ref> === Ichebe ebe mmelite site na anụmanụ na-achọgharị === Ọhịa na-eche ọtụtụ ihe ịma aka ihu, dị ka mkpụrụ na nnweta ihe oriri, mana ọ dị oke egwu maka anụmanụ na-achọgharị. Ọ bụ ezie na ịnyagharị anụmanụ dị mkpa iji lekọta ala nke oké ọhịa, ha nwere ike ili ala ọhịa a kụrụ ọhụrụ n'ụzọ dị mfe, ebe a na-enweta obere samplings n'ụzọ dịkwa mfe. Ịzụbiga anụ ókè bụ nsogbu karịsịa n'okwu a ebe ọ bụ na ihe nnwale na osisi ndị ọzọ na-eto eto nwere ike imebi karịa ebe a ga-agbake, na-akpata mbelata nke ụdị dị iche iche. A ghaghị ịkpachara anya iji "mgbidi mgbada" chebe ebe mmelite, ma ọ bụ ebe ọ na-agaghị ekwe omume, ịkụ osisi nke na-ebute uto na mgbake ụzọ.<ref>{{Cite journal|doi=10.1016/j.foreco.2017.10.037|title=Species selection – A fundamental silvicultural tool to promote forest regeneration under high animal browsing pressure|year=2018|author=Burney|first=Owen T.|journal=Forest Ecology and Management|volume=408|pages=67–74}}</ref> == Mgbanwe mgbe ọkụ gasịrị == N'akụkụ buru ibu nke ụwa, ọkụ ọhịa na-ekpuchi nnukwu ihe na-egbu ọhịa. Nke ahụ nwere ike ịbụ n'ihi mgbukpọ ọhịa iji dochie ọhịa site na ebe a na-akụ ihe ọkụkụ, ma ọ bụ n'ebe kpọrọ nkụ, n'ihi ọkụ ọhịa na-eme n'ụzọ okike ma ọ bụ kpachara anya. Akụkụ dum nke mweghachi ala ọhịa na-ejikọta ya na nsogbu a, dịka n'ọtụtụ ọnọdụ, ọnụọgụ nke uru gburugburu ebe obibi dị elu ma nwee ike imeghe ọdịda na mmebi ngwa ngwa nke ọnọdụ ala site na mbuze na ọzara. Nke a n'ezie nwere mmetụta dị egwu na ogo nke ebe obibi na anụmanụ ha metụtara. Ka o sina dị, n'ọnọdụ ụfọdụ, ọkụ ọhịa na-enye ohere n'ezie ịbawanye ọnụọgụ dị iche iche nke ebe ọkụ gbara, n'ihi ya, Usoro Nweghachi Ọhịa na-achọkarị iji ala eme ihe dị iche.<ref>{{Cite journal|author=Regos|first=Adrian|title=Predicting the future effectiveness of protected areas for bird conservation in Mediterranean ecosystems under climate change and novel fire regime scenarios|journal=Diversity and Distributions|date=2016|volume=22|issue=1|pages=83–96|doi=10.1111/ddi.12375}}</ref><ref>{{Cite journal|author=Martín-Alcón|first=Santiago|title=Unraveling the relative importance of factors driving post-fire regeneration trajectories in non-serotinous Pinus nigra forests|journal=Forest Ecology and Management|date=2016|volume=361|pages=13–22|doi=10.1016/j.foreco.2015.11.006|url=http://arxiudigital.ctfc.cat/docs/upload/27_489_Martin-Alcon_and_Coll_2016_FORECO.pdf}}</ref> == Ọrụ mweghachi ọhịa == Nnyocha na-achọpụta na ihe fọrọ nke nta ka ọ bụrụ nde mmadụ 300 bi n'ala ohere mweghachi nke oké ọhịa na Global South, na-eme ka akụkụ dị ukwuu nke ndị bi na mba ndị na-enweta ego dị ala, ma na-arụ ụka maka itinye "obodo ndị dị n'ógbè" n'ọrụ mweghachi ọhịa.<ref>{{Cite news|title=Global forest restoration and the importance of empowering local communities|url=https://phys.org/news/2020-08-global-forest-importance-empowering-local.html|accessdate=5 September 2020|work=phys.org|language=en}}</ref><ref>{{Cite news|title=300 million world over can have their forests restored: study|url=https://www.thehindu.com/news/cities/Hyderabad/300-million-world-over-can-have-their-forests-restored-study/article32440958.ece|accessdate=5 September 2020|work=The Hindu|date=25 August 2020|language=en-IN}}</ref><ref>{{Cite journal|author=Erbaugh|first=J. T.|title=Global forest restoration and the importance of prioritizing local communities|journal=Nature Ecology & Evolution|date=24 August 2020|volume=4|issue=11|pages=1472–1476|doi=10.1038/s41559-020-01282-2|pmid=32839542|url=https://www.nature.com/articles/s41559-020-01282-2|accessdate=5 September 2020|language=en|issn=2397-334X}}</ref> Project Drawdown depụtara mweghachi nke oké ọhịa ndị dị n'ebe okpomọkụ dị ka otu n'ime ihe ngwọta kachasị mkpa maka mbelata mgbanwe ihu igwe n'ihi ikike ya pụrụ iche iji weghara carbon ma na-atụ aro na "obodo ndị dị n"ógbè kwesịrị inwe òkè na ihe na-eto eto, ma ọ bụrụ na mweghachi ga-anọgide.<ref>{{Cite web|date=2020-02-07|title=Tropical Forest Restoration|url=https://drawdown.org/solutions/tropical-forest-restoration|accessdate=2020-12-05|work=Project Drawdown|language=en}}</ref> Otu mbipụta FAO na-adịbeghị anya na-akọ na ndị obodo so na ndị na-eche ihe ize ndụ kachasị ukwuu maka ọdịmma ha na ụzọ ndụ ha site na mmetụta nke mgbanwe ihu igwe, ya mere, a ghaghị ilekwasị anya na mweghachi na nchekwa ọhịa.<ref name=":2"/> === Ọrụ Nlekọta Ọhịa Ashland === The Ashland Forest Resiliency Stewardship Project (AFR) bụ afọ iri, ọrụ dabeere na sayensị malitere na 2010 na ebumnuche nke ibelata nnukwu ihe ize ndụ ọkụ ọhịa, kamakwa ichebe ogo mmiri, oké ọhịa ochie, anụ ọhịa, ndị mmadụ, ihe onwunwe, na ogo ndụ n'ime mmiri Ashland.<ref>{{Cite web|title=City of Ashland, Oregon - Ashland Forest Resiliency Project - What is AFR?|url=http://www.ashland.or.us/Page.asp?NavID=12907|work=www.ashland.or.us|accessdate=2016-02-05|archivedate=2016-02-03|archiveurl=https://web.archive.org/web/20160203125528/http://www.ashland.or.us/Page.asp?NavID=12907}}</ref> Ndị isi na-etinye aka na mgbalị nrụzigharị a bụ US Forest Service, City of Ashland, Lomakatsi Restoration Project, na The Nature Conservancy.<ref>{{Cite web|title=Ashland Forest Resilency Project - Lomakatsi Restoration Project|url=http://lomakatsi.org/ashland-forest-resilency-project/|work=Lomakatsi Restoration Project|accessdate=2016-02-05|language=en-US|archivedate=2016-02-10|archiveurl=https://web.archive.org/web/20160210082015/http://lomakatsi.org/ashland-forest-resilency-project/}}</ref> A malitere ọrụ ahụ site na ego mbụ sitere na Economic Recovery stimulus, ma nata ego site na mmemme Forest Service Hazardous Fuels na mmemme Joint Chiefs Landscape Restoration Partnerships iji kwado ọrụ ahụ site n'afọ 2016. N'ịbụ nke dị n'oké ọhịa kpọrọ nkụ nke ndịda Oregon, egwu ọkụ ọhịa bụ eziokwu maka ndị na-elekọta ala na ndị nwe ala. Mpaghara nke obodo Ashland na ọhịa gbara ya gburugburu na ihe a na-akpọ interface nke ọhịa (WUI).<ref>Toman, E., Stidham, M., Shindler, B., McCaffrey, S. 2011. Reducing fuels in the wildland-urban interface: community perceptions of agency fuel treatments. Intl. Journal of Wildland Fire 20 (3):340-349</ref> N'akụkọ ihe mere eme, oké ọhịa nke mpaghara a nwere oge ọkụ na-enwetakarị, nke gbochiri mkpokọta mmanụ dị arọ.<ref>Hagmann, R.K., Franklin, J.F., Johnson, N.K. 2013. Historical structure and composition of ponderosa pine and mixed-conifer forests in south-central Oregon. Forest Ecology and Management 304: 492-504</ref> Otu narị afọ nke iwepụ ọkụ na mgbochi na ala gọọmentị etiti na Pacific Northwest emeela ka oke ọhịa na ibu mmanụ dịkwuo ukwuu, ya mere egwu na-adịgide adịgide nke ọkụ ọhịa na-ebibi ihe.<ref>Franklin, J.F., and Johnson, K.N. 2012. A restoration framework for federal forests in the Pacific Northwest. Journal of Forestry 110 (8): 429-439</ref> Ihe oru AFR emejuputala usoro mweghachi na ndenye ndenye nke bu n'obi megharia usoro nke onodi gburugburu ebe obibi n'ime oke ohia akọrọ, conifer agwakọtara nke Pacific Northwest.  Usoro a na-agụnye nchikota nke mbelata mmanụ ọkụ, ibelata osisi ndị dị n'ime obere dayameta, na ịme ọkụ ọkụ.  A na-ebute ụzọ n'ịnọgide na-arụ ọrụ gburugburu ebe obibi na mgbagwoju anya site n'ijigide osisi ndị kasị ibu na nke ochie, ichekwa ebe obibi anụ ọhịa na mpaghara mmiri, na ichekwa ala ndị na-emebi emebi na ịnọgide na-enwe nkwụsi ike nke mkpọda. Kemgbe e bidoro ya na 2010, ọrụ AFR enyewo ọtụtụ puku ụmụ akwụkwọ ahụmịhe agụmakwụkwọ ma baara ndị obodo ahụ uru site n'ịmepụta ọrụ na inye ọzụzụ ndị ọrụ. Ihe dị ka 13,000 acres a gwọrọ na ọrụ AFR nọ n'ọnọdụ mmezi ka ọ na-erule n'ọnwa Febụwarị 2022, na Oregon's Landscape Resiliency Program, nke e guzobere site na Senate Bill 762, na-enye ego ịkpụcha brush na ọkụ ọkụ dị ala iji rite uru na gburugburu ebe obibi n'oké ọhịa ọkụ. === Ime ka osisi dị ọhụrụ ngwa site na ihe mkpofu ugbo === N'afọ 1998, e debere atụmatụ ndị Costa Rican iji weghachite ebe ndị a na-egbu egbu, nke a na-ejibu dị ka ebe ehi na-ata ahịhịa. Ala a dị n'otu ma mee ka ala ahụ gwụ, na-eme ka mmelite okike sie ike. Dị ka mmekorita ya na mkpofu ugbo, a na-etinye ihe dịka miligram pụkụ ịrị na abụọ Mg nke akpụkpọ oroma na pulp na mpaghara hekta atọ nke ebe ịta nri mbụ. Mgbakwunye a nke biomass n'ala nyere ohere maka mmụba pasent otu narị na iri asaa na isii (176%) na uto osisi, mmụba nke ụdị, okpukpu atọ nke osisi (nke a tụrụ site na Shannon Index), na ọkwa dị elu nke ihe na-edozi ahụ n'ala, nke a tụrụ ''na'' afọ abụọ na ịrị na isii mgbe etinyechara ya (Truer et al. 2018).<ref>{{Cite journal|doi=10.1111/rec.12565|title=Low-cost agricultural waste accelerates tropical forest regeneration|year=2018|author=Treuer|first=Timothy L. H.|journal=Restoration Ecology|volume=26|issue=2|pages=275–283}}</ref> A hụkwara mmụba dị ịrịba ama na mmechi okpokoro site na iji ọdịdị ala hemispheric, na-atụkwa aro na ihe mkpofu ugbo nwere ike ịrụ ọrụ dị ukwuu na mweghachi ọhịa n'ọdịnihu. == Iweghachi ala ọhịa == A na-akọwa mweghachi ala ọhịa (Forest Landscape Restoration - FLR) dị ka usoro a na-eme atụmatụ iji nwetaghachi iguzosi ike n'ezi ihe gburugburu ebe obibi ma melite ọdịmma mmadụ n'ọhịa ma ọ bụ ala mebiri emebi.<ref>Reitbergen-McCraken, J., S. Maginnis A. Sarre, 2007. ''The Forest Landscape Restoration Handbook''. Earthscan, London, 175 pp</ref> Ọ na-agụnye ngwá ọrụ na usoro iji jikọta ọrụ mweghachi ọhịa dị n'ọkwa na ebumnuche dị mma, nke a na-ekpebi site na usoro dị iche iche na-ekere òkè n'etiti ndị metụtara. Echiche a etolitela site na mmekorita n'etiti ụfọdụ n'ime nnukwu ụlọ ọrụ nchekwa mba ụwa gụnyere International Union for Conservation of Nature (IUCN), World Wide Fund for Nature (WWF), World Resources Institute na International Tropical Timber Organization (ITTO). === Ebumnuche === E chepụtara echiche nke FLR iji weta nkwekọrịta n'etiti igbo mkpa nke ụmụ mmadụ na anụ ọhịa, site na [[Iweghachi ala|iweghachi]] n'ọdịnihu ghere oghe. Ọ na-agụnye omume iji wusie ike nkwụsi ike na ịdị n'ezi ihe gburugburu ebe obibi ma si otú a na-emeghe nhọrọ nlekọta n'ọdịnihu.  Ntinye aka nke ndị obodo bụ isi n'echiche a, n'ihi na ha na-ekere òkè dị egwu n'ịkpụzi odida obodo ma nweta uru dị ukwuu site na akụ ọhịa eweghachitere.  Ya mere, mmemme FLR na-agụnye ma bụrụ nke a na-ekere òkè.<ref>Lamb, D., 2011. ''Regreening the Bare Hills''. Springer 547pp.</ref> === Nsonaazụ ndị a na-achọsi ike === Nsonaazụ ndị a na-achọsi ike nke mmemme FLR na-agụnyekarị ngwakọta nke ihe ndị a, dabere na mkpa na ọchịchọ mpaghara: * njirimara nke ihe na-akpata mmebi ọhịa na mgbochi nke mgbukpọ ọhịa. * ntinye aka dị mma nke ndị mmadụ na atụmatụ nke mweghachi ọhịa, ngwọta nke esemokwu iji ala eme ihe na nkwekọrịta na usoro ịkekọrịta uru. * nkwekọrịta banyere mgbanwe nke iji ala eme ihe nke ọtụtụ ndị metụtara na-anabata. * ebe nchekwa nke ụdị dị iche iche nke obodo na nke ụwa. * nnyefe nke uru dịgasị iche iche maka obodo ndị dị n'ógbè gụnyere: ** mmiri dị ọcha a pụrụ ịdabere na ya, ** nchekwa gburugburu ebe obibi karịsịa ọrụ mmiri (dịka mbelata mbuze ala, mbelata ihe ize ndụ ala, mbepụ idei mmiri / ụkọ mmiri ozuzo wdg.[Ihe e dere n'ala ala peeji] ** ihe na-adịgide adịgide nke ngwaahịa dịgasị iche iche nke ọhịa gụnyere nri, ọgwụ, nkụ wdg. ** ego ego sitere na isi mmalite dị iche iche dịka njem gburugburu ebe obibi, ahia carbon site na usoro REDD + na site na ịkwụ ụgwọ maka ọrụ gburugburu ebe obibi ndị ọzọ (PES)<ref>Mansourian, S., D. Vallauri, and N., Dudley (eds.) (in co-operation with WWF International), ''Forest Restoration in Landscapes: Beyond Planting Trees''. Springer, New York.</ref> === Ihe omume === FLR na-agwakọta ọtụtụ ụkpụrụ na usoro nke mmepe, nchekwa na njikwa akụ sitere n'okike, dị ka ntule njirimara ọdịdị ala, nyocha ime obodo na-ekere òkè, njikwa mgbanwe wdg n'ime nyocha doro anya na nke na-agbanwe agbanwe na usoro mmụta.  Mmemme FLR nwere ike ịgụnye omume dị iche iche nke ọhịa na saịtị dị iche iche n'ime odida obodo, dabere na gburugburu ebe obibi na ihe gbasara akụ na ụba.  Ndị a nwere ike ịgụnye nchekwa na njikwa nke oke ohia nke abụọ na nke dara ada, usoro mweghachi nke oke ọhịa dị ka "enyere aka" ma ọ bụ "accelerated" natural regeneration (ANR) na ịkụnye ụdị osisi dị iche iche iji weghachi ebe ndị mebiri emebi, yana ihe ọkụkụ osisi na-emekarị.  sistemu agroforestry iji gboo mkpa ego ozugbo..<ref>Elliott, S., D. Blakesley and K. Hardwick, in press. ''Restoring Tropical Forests: a Practical Guide''. Kew Publications, London</ref> IUCN na-akwado Global Partnership on Forest Landscape Restoration, nke na-ahazi mmepe nke echiche ahụ gburugburu ụwa.<ref>{{Cite web|title=The Global Partnership on Forest and Landscape Restoration|url=http://www.forestlandscaperestoration.org/|work=The Global Partnership on Forest and Landscape Restoration|publisher=IUCN|access-date=2023-05-06|archive-url=https://web.archive.org/web/20190414074431/http://www.forestlandscaperestoration.org/|archive-date=2019-04-14|url-status=dead}}</ref> N'afọ 2014, Òtù Nri na Ọrụ Ugbo (Food and Agricultural Organization) nke otu United Nations guzobere Usoro Mweghachi Ọhịa na Ala.<ref>{{Cite web|author=Food and Agriculture Organization of the United Nations|title=Forest and Landscape Restoration Mechanism|url=http://www.fao.org/forestry/flrm/en/|publisher=Food and Agriculture Organization of the United Nations|accessdate=2023-05-06|archivedate=2016-04-23|archiveurl=https://web.archive.org/web/20160423031849/http://www.fao.org/forestry/flrm/en/}}</ref> Usoro ahụ na-akwado mba iji mejuputa FLR dị ka onyinye iji nweta [[ihe ịma aka Bonn]]<ref>{{Cite web|author=Global Partnership on Forest Landscape Restoration|title=The Bonn Challenge|url=http://www.bonnchallenge.org/|work=The Bonn Challenge|publisher=International Union for Conservation of Nature}}</ref> - mweghachi nke nde hekta otú narị na iri ise nke ala ndị e gburu egbu na ala ndị mebiri emebi site na 2020 - na Nkwekọrịta na Biological Diversity Aichi Biodiversity Targets - metụtara nchekwa na mweghachi nke gburugburu ebe obibi.<ref>{{Cite web|author=Convention on Biological Diversity|title=Aichi Biodiversity Targets|url=https://www.cbd.int/doc/strategic-plan/targets/T15-quick-guide-en.pdf|publisher=Convention on Biological Diversity}}</ref> Na mmekorita ya na Global Mechanism of the United Nations Convention to Combat Desertification, FAO wepụtara akwụkwọ mkparịta ụka abụọ gbasara ego na-adịgide adịgide maka FLR na 2015. Inye ego na-adịgide adịgide maka oke ọhịa na mweghachi ala: Ọrụ nke Ndị na-eme amụma ọha na eze na-enye ndụmọdụ na ihe atụ nke ego FLR maka mba.<ref>{{Cite book|title=Sustainable Financing for Forest and Landscape Restoration. The Role of Public Policy Makers|date=June 2015|publisher=Food and Agricultural Organization of the United Nations and the Global Mechanism of the UNCCD|url=http://www.fao.org/3/a-i5032e.pdf}}</ref> Nkwado na-adịgide adịgide maka Mweghachi Ọhịa na Ala - Ohere, ihe ịma aka na ụzọ ịga n'ihu na-enye nchịkọta nke isi mmalite ego na ngwá ọrụ ego dị maka ọrụ FLR.<ref>{{Cite book|title=Sustainable Financing for Forest and Landscape Restoration - Opportunities, challenges and the way forward|date=June 2015|publisher=Food and Agriculture Organization of the United Nations and the Global Mechanism of the UNCCD|isbn=978-92-5-108992-7|url=http://www.fao.org/3/a-i5174e.pdf}}</ref> === Nkwado ego === Iji kwado atụmatụ na mmejuputa ọrụ mgbake ọhịa na ala (FLR), Food and Agriculture Organization of the United Nations (FAO) achọpụtala usoro ego dị iche iche nke na-adaba na ọkwa dị iche iche na usoro FLR ma kpuchie azụmahịa na mkpokọta nke ụlọ ọrụ maka mweghachi na-adịgide adịgide.<ref name=":1" /> Enwere ọtụtụ nhọrọ iji kwado mweghachi.<ref name=":1" /> Iji gboo ihe ndị pụrụ iche achọrọ nke ọrụ FLR ọ bụla, ọ dị oke mkpa ịchọpụta usoro ego kachasị mma.<ref name=":1" /> Nhọrọ ego nke na-emepụta ihe dịgasị iche iche maka ndị na-eme ihe nkiri n'ógbè ahụ nwere ike ịbụ usoro maka uru, dị ka ụgwọ ma ọ bụ mgbazinye ego, ma ọ bụ usoro na-abụghị maka uru nke gụnyere onyinye, iwu ego, maọ bụ mmefu site na ngalaba ọha na eze.<ref name=":1" /> Dị ka FAO si kwuo, ichikota ọdịiche dị n'etiti ndị obere na ndị na-etinye ego, ịhazi ego, ịkwalite ikike ime obodo nke atụmatụ ego FLR, na mmepe nke ọrụ bankable na usoro ego jikọtara ọnụ na-emepụta ihe dị mma maka mmetụta FLR na ọnụ ọgụgụ..<ref name=":1">{{Cite book|title=Local financing mechanisms for forest and landscape restoration: A review of local-level investment mechanisms|publisher=Food and Agriculture Organization of the United Nations|year=2021|isbn=978-92-5-134102-5|edition=1|location=Rome|pages=1–11|language=English|doi=10.4060/cb3760en}}</ref> == Hụkwa ==   * Ịrụghachi Ọhịa * Mweghachi gburugburu ebe obibi * Oké ọhịa nke abụọ * Iweghachi osisi mangrove * [[Iweghachi ala]] * Mgbukpọsị ọhịa * Ụbọchị Oké Ọhịa Mba Nile == Edensibia == {{Reflist}} == Njikọ mpụga == * The Global Partnership on Forest and Landscape Restoration - Ozi ndị ọzọ gbasara atụmatụ zuru ụwa ọnụ iji weghachite usoro okike ọhịa * [http://aprildialog.com/2013/06/28/issuance-of-eco-restorations-license/ Ntinye nke Ikike Nweghachi Mpaghara] * [http://www.fs.fed.us/restoration/CFLR/index.shtml Nkwekọrịta Nweghachi Ọhịa], United States Forest Service, Washington, DC * [http://www.wri.org/project/forest-landscape-restoration Ọrụ Mweghachi Ọhịa na Ala], World Resources Institute, Washington, DC * [https://www.fao.org/in-action/forest-landscape-restoration-mechanism Usoro Mweghachi Ọhịa na Ala] [[Òtù:Pages with unreviewed translations]] fu4cgms6uibpu3t7pw1dhk82qgpccyj Kennedy Agyapong 0 27359 736850 700731 2026-10-08T08:00:23Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736850 wikitext text/x-wiki {{Infobox officeholder|honorific-prefix=Hon.|name=Kennedy Agyapong|honorific-suffix=MP|image=KEN OHENE AGYAPONG.jpg|alt=|caption=|constituency_MP=|parliament=Ghana|majority=|term_start=|term_end=<!--Can be repeated up to eight times by adding a number-->|predecessor=|successor=<!--Can be repeated up to eight times by adding a number-->|prior_term=|order2=|office2=[[Parliament of Ghana|Member of Parliament]]<br>for [[Assin Central (Ghana parliament constituency)|Assin Central]]|term_start2=7 January 2004|term_end2=|president2=[[Nana Akuffo-Addo]]|predecessor2=''New constituency''|successor2=|order3=<!--Can be repeated up to eight times by changing the number-->|office3=[[Parliament of Ghana|Member of Parliament]]<br />for [[Assin North (Ghana parliament constituency)|Assin North]]|term_start3=1 January 2001|term_end3=6 January 2013|president3=|predecessor3=[[Florence Kumi]]|successor3=[[Samuel Ambre]]|birth_date={{birth date and age|1960|06|16|df=y}}<ref name=":1"/>|birth_place=Assin Dompim, [[Central Region (Ghana)|Central Region]], [[Ghana]]|death_date=|death_place=|restingplace=|restingplacecoordinates=|birthname=Kennedy Ohene Agyapong <!-- from parliament.gh site -->|nationality=[[Ghanaian nationality law|Ghanaian]]|party=[[New Patriotic Party]]|otherparty=<!--For additional political affiliations-->|spouse=|partner=<!--For those with a domestic partner and not married-->|relations=|children=|residence=|alma_mater=[[Fordham University]]|occupation=[[Politician]]|profession=[[Businessman]]|cabinet=|committees=Defense and Interior Committee (Chairperson); Judiciary Committee; Special Budget Committee|portfolio=|signature=|signature_alt=|website=|footnotes=}}{{Databox}} Kennedy Ohene Agyapong (amụrụ June16,1960) bụ onye ndọrọndọrọ ọchịchị na onye ọchụnta ego Ghana nke na-anọchite anya Assin Central na nzuko omeiwu maka New Patriotic Party. .<ref>{{Cite web|title=I don't fear for my life, 'all die be die' – Kennedy Agyapong – MyJoyOnline.com|url=https://www.myjoyonline.com/composition/top-story/i-dont-fear-for-my-life-all-die-be-die-kennedy-agyapong/|language=en-US|accessdate=2020-05-26}}</ref><ref>{{Cite web|title=No time for demonstration again; our gods will deal with you - Assin youth tells politicians - MyJoyOnline.com|url=https://www.myjoyonline.com/no-time-for-demonstration-again-our-gods-will-deal-with-you-assin-youth-tells-politicians/|accessdate=2021-05-19|work=www.myjoyonline.com|language=en-US}}</ref> A họpụtara ya ka ọ bụrụ onye omeiwu na 2000 na oche nke Assin North.<ref>{{Cite web|url=http://psephos.adam-carr.net/countries/g/ghana/ghana20003.txt|title=REPUBLIC OF GHANA - LEGISLATIVE ELECTION OF 7 DECEMBER 2000|work=Adam Carr's Election Archives|accessdate=2010-08-28|publisher=Adam Carr}}</ref> Ọ nọgidere n'oche ya na ntuli aka ndị omeiwu nke afọ 2004 na 2008<ref>{{Cite web|url=http://www.ec.gov.gh/userfiles/file/2004ParliamentaryDetResults.pdf|title=Electoral Commission of Ghana - Parliamentary Election Results - Date of Election:- Tuesday, 7th December 2004|accessdate=2010-08-28|publisher=[[Electoral Commission of Ghana]]|archiveurl=https://web.archive.org/web/20110112175254/http://www.ec.gov.gh/userfiles/file/2004ParliamentaryDetResults.pdf|archivedate=2011-01-12}}</ref>.<ref>{{Cite web|url=http://www.ec.gov.gh/userfiles/Central.pdf|title=Electoral Commission of Ghana - Parliamentary Election Results - Date of Election:- Sunday, 7th December 2008|accessdate=2010-08-28|publisher=[[Electoral Commission of Ghana]]|archiveurl=https://web.archive.org/web/20100326210858/http://www.ec.gov.gh/userfiles/Central.pdf|archivedate=2010-03-26}}</ref> N'afọ 2012, a họpụtara ya n'oche ọhụrụ nke Assin Central ma họpụta ya ọzọ n'afọ 2016. Ọ nọgidekwara n'oche ya na ntuli aka nke afọ 2020.<ref>{{Cite web|title=Assin Central: Kennedy Agyapong retains seat, gets sixth term as MP|url=https://www.graphic.com.gh/news/politics/assin-central-kennedy-agyapong-retains-seat-gets-sixth-term-as-mp.html|accessdate=2020-12-08|work=Graphic Online|language=en-gb}}</ref> Ọ bụ onye isi oche nke Kọmitii Nchebe na Interior nke Nzukọ Ndị Omeiwu ugbu a.<ref>{{Cite web|title=Akufo-Addo must clear out NPP officials involved in 'galamsey' first, or the fight will fail - Kennedy Agyepong - MyJoyOnline.com|url=https://www.myjoyonline.com/akufo-addo-must-clear-out-npp-officials-involved-in-galamsey-first-or-the-fight-will-fail-kennedy-agyepong/|accessdate=2021-05-18|work=www.myjoyonline.com|language=en-US}}</ref> == Ndụ mmalite na agụmakwụkwọ == A mụrụ Ohene Agyapong na 16 June 1960 ma si Assin Dompim na Central Region nke Ghana.<ref name=":1">{{Cite web|title=Parliament of Ghana|url=https://www.parliament.gh/mps?mp=34|accessdate=2022-11-24|work=www.parliament.gh|archivedate=2022-10-01|archiveurl=https://web.archive.org/web/20221001174403/https://www.parliament.gh/mps?mp=34}}</ref> Ọ gụrụ akwụkwọ sekọndrị na Adisadel College na Central Region. Agyapong nwere GCE A Level ma hapụ Mahadum Fordham, New York, USA. Ọ bụ onye ọrụ ugbo na onye ọchụnta ego, onye nduzi nke Assin Farms, Supercare Group of Companies na Hollywood Shopping Centre. Ọ lụrụ di ma nwee ụmụ iri abụọ na abụọ.<ref name=":0">{{Cite web|title=Ghana MPs - MP Details - Agyapong Ohene Ken|url=http://www.ghanamps.com/mps/details.php?id=2529|accessdate=2019-04-27|work=www.ghanamps.com|archivedate=2024-09-26|archiveurl=https://web.archive.org/web/20240926063120/https://ghanamps.com/mps/details.php/?id=2529}}</ref> == ndọrọ ndọrọ ọchịchị == Kennedy Agyapong ka na-anọgide na-abụ otu n'ime ndị ndọrọ ndọrọ ọchịchị na-enwetụbeghị ntuli aka Ọrụ ọgụgụ isi ya na ntuli aka 2016 butere mmeri nke Nana Addo Dankwah Akufo-Addo.O nyekwara aka nke ukwuu na mmeri nke ọtụtụ ndị omeiwu NPP dịka K.T Hammond na ọtụtụ ndị ọzọ. Kennedy Agyapong bụ onye isi oche kọmitii nkwurịta okwu na nzuko omeiwu, n'okpuru onyeisi oche Nana Akufo-Addo ugbu a. Agyapong ṅụrụ iyi igbu onwe ya ma ọ bụrụ na gọọmentị Akufo-Addo ejighi nwanne onye bụbu onye isi ala John Mahama, Ibrahim, maka ụfọdụ ọrụ nrụrụ aka nke, dị ka Agyapong si kwuo, mere ka steeti ahụ tụfuo ego. Otu ihe atụ o kwuru, bụ enweghị ịkwụ ụtụ isi site n'aka [[Ibrahim Mahama]] ihe karịrị otu afọ mgbe nwanne ya nwoke bụ onye isi ala nke Republic of Ghana. Mgbalị nke Agyapong n'onwe ya n'okwu ahụ iji mee ka ndị mgbasa ozi mara ya dugara na nyocha nke Ibrahim Mahama na nkwekọrịta nke Ibrahim Maham iji kwụọ ụtụ isi ahụ. Omume a mere ka Kennedy Agyapong nweta otuto site n'aka ọtụtụ ndị Ghana.<ref>{{Cite web|author=Ayumu|first=Patrick|title=I'll drink poison if Ibrahim Mahama isn't jailed: Agyapong|url=https://classfmonline.com/1.10910325|accessdate=17 January 2019|work=www.classfmonline.com|archivedate=19 January 2019|archiveurl=https://web.archive.org/web/20190119174253/https://www.classfmonline.com/1.10910325}}</ref><ref>{{Cite web|url=https://www.ghanaweb.com/GhanaHomePage/NewsArchive/I-will-poison-myself-if-Ibrahim-Mahama-is-not-jailed-Ken-Agyapong-523675|title=I will poison myself if Ibrahim Mahama is not jailed – Ken Agyapong|work=www.ghanaweb.com|language=en|accessdate=2017-08-06|archivedate=6 August 2017|archiveurl=https://web.archive.org/web/20170806222246/https://www.ghanaweb.com/GhanaHomePage/NewsArchive/I-will-poison-myself-if-Ibrahim-Mahama-is-not-jailed-Ken-Agyapong-523675}}</ref> Mwakpo Agyapong na-apụtaghị ìhè na Kọmishọna Electoral nke Ghana Charlotte Osei maka, o kwuru na, ịzụ ahịa mmekọahụ maka ọnọdụ ya dị ka onye isi Kọmishọna Elektụrụla (EC) wetara ya nkatọ site n'aka ndị isi dị iche iche gụnyere ndị nne eze nwanyị na ndị na-ahụ maka ihe ndị ruuru mmadụ yana ndị ọzọ so na ndị omeiwu.<ref>{{Cite web|url=http://ghanapoliticsonline.com/queen-mothers-petition-parliament-over-ken-agyapong/|title=Queen mothers petition parliament over Ken Agyapong - GhanaPoliticsOnline|work=ghanapoliticsonline.com|date=11 July 2016|language=en-US|accessdate=2017-08-06|archivedate=2023-03-29|archiveurl=https://web.archive.org/web/20230329221645/https://ghanapoliticsonline.com/queen-mothers-petition-parliament-over-ken-agyapong/}}</ref> N'afọ 2018, mgbe e jidere onye isi oche nke Ghana Football Association Kwasi Nyantakyi, o kwuru na a ga-akwụsị onye nta akụkọ na-ahụ maka nrụrụ aka Anas Aremeyaw Anas tupu ya amalite inyocha ndị mmadụ nọ na "ọnụ ụlọ ihi ụra ha".<ref>{{Cite news|title=Let's stop Anas before he gets into our bedrooms - Kennedy Agyapong pleads|url=https://www.ghanaweb.com/GhanaHomePage/NewsArchive/Let-s-stop-Anas-before-he-gets-into-our-bedrooms-Kennedy-Agyapong-pleads-655231|accessdate=28 May 2018|work=GhanaWeb|date=27 May 2018|archive-url=https://web.archive.org/web/20180527212117/https://www.ghanaweb.com/GhanaHomePage/NewsArchive/Let-s-stop-Anas-before-he-gets-into-our-bedrooms-Kennedy-Agyapong-pleads-655231|archive-date=27 May 2018|url-status=dead}}</ref> Ọ na-eyi Anas egwu ugboro ugboro ma kọmitii na-echebe ndị nta akụkọ na ndị nta akụkọ n'enweghị ókèala katọọ ya na mba ụwa. O kwuru na usoro Anas 'zighị ezi'.<ref>{{Cite web|url=https://cpj.org/2018/06/ghana-investigative-film-crew-faces-death-threats.php|title=In Ghana, investigative film crew faces death threats, harassment|first=Committee to Protect Journalists 330 7th|author=Avenue|work=cpj.org|date=4 June 2018|accessdate=17 January 2019}}</ref><ref>{{Cite web|url=https://rsf.org/en/news/death-threats-against-well-known-ghanaian-investigative-journalist|title=Death threats against well-known Ghanaian investigative journalist - Reporters without borders|date=6 June 2018|work=RSF|accessdate=17 January 2019}}</ref> N'ikwu okwu na Adom FM na 4 June 2018, ọ kpọrọ Anas "onye na-emegbu mmadụ, onye na-apụnara mmadụ ihe", mere ka a na-ebipụ ya akpịrị ma kwuo na a ga-akwụgbu ya.<ref>{{Cite web|url=https://www.youtube.com/watch?v=tgwhtw5LFoo|title=Full Interview of Kennedy Agyapong on Anas on Adom FM|author=joe Quaye|publisher=|accessdate=17 January 2019}}</ref> Ọ rịọkwara maka "ịbọ ọbọ" megide onye nta akụkọ ibe Anas, Ahmed Hussein-Suale, na-ekwu "Ọ bụrụ na ọ bịa ebe a, tie ya ihe... Ihe ọ bụla ga-eme, m ga-akwụ ụgwọ. " E mechara gbuo Hussein-Suale.<ref name="BBC-46902748">{{Cite news|title=Football bribes investigator shot dead|url=https://www.bbc.co.uk/news/world-africa-46902748|accessdate=17 January 2019|publisher=[[BBC News]]|date=17 January 2019}}</ref><ref name="YCSM">{{Cite web|title=You can't silence me - Anas reacts to the killing of his partner at Madina|url=https://www.ghanaweb.com/GhanaHomePage/NewsArchive/You-can-t-silence-me-Anas-reacts-to-the-killing-of-his-partner-at-Madina-715823|work=www.ghanaweb.com|date=17 January 2019|accessdate=17 January 2019|language=en}}</ref> Na July 2018, a na-enyocha ya maka nlelị nke nzuko omeiwu.<ref>{{Cite web|url=https://www.myjoyonline.com/politics/2018/June-26th/kennedy-agyapongs-useless-parliament-contempt-hearing-set-for-july-3.php|title=Kennedy Agyapong's 'useless parliament' contempt hearing set for July 3|work=www.myjoyonline.com|accessdate=17 January 2019}}</ref> Ekwenyere na ọ bụ onye Ghana mbụ nwere nde Rolls-Royce ¢8Ekwenyere na ọ nwekwara ụgbọ elu nkeonwe, oku na-egbuke egbuke maka nyocha site n'aka ụlọ ọrụ Customs Excise and Preventive Service gbasara akụ na ụba ya..<ref>{{Cite web|url=https://www.ghanaweb.com/GhanaHomePage/NewsArchive/Kennedy-Agyapong-buys-8bn-Rolls-Royce-183477|title=Kennedy Agyapong buys ¢8bn Rolls Royce|work=www.ghanaweb.com|date=30 November 2001|language=en|accessdate=2017-08-06}}</ref><ref>{{Cite web|url=http://ghanavibes.com/photos-of-kennedy-agyapongs-rolls-royce-and-rumoured-private-jet/|title=Photos Of Kennedy Agyapong's Rolls Royce And 'Rumoured' Private jet|work=ghanavibes.com|language=en-US|accessdate=2017-08-06|archivedate=6 August 2017|archiveurl=https://web.archive.org/web/20170806223322/http://ghanavibes.com/photos-of-kennedy-agyapongs-rolls-royce-and-rumoured-private-jet/}}</ref> === Kọmitii === Ọ bụ onye isi oche maka Kọmitii Nchebe na Interior; ọ bụkwa onye otu Kọmitii Ikpe na onye otu Kọمitii Mmefu Ego Pụrụ Iche.<ref name=":1"/> == Ndụ onwe onye == Ọ bụ Onye Kraịst.<ref name=":1"/> == Hụkwa == * [[Who Watches the Watchman exposé|Onye Na-ele Onye Nche]] * Nkwupụta nke 12 * [[Net2TVGh]] == Ntụaka == <references group="" responsive="1"></references> 19.ʌ "[https://web.archive.org/web/20200811045445/https://legitloaded.com/kennedy-agyapong-admits-that-he-almost-died-last-month/ Kennedy Agyapong kwetara na ọ fọrọ nke nta ka ọ nwụọ n'ọnwa gara aga]. legitloaded.com. E nwetara ya na 21 Julaị 2020. [[Òtù:1960 births]] [[Òtù:Mmadụ ndi di ndụ]] 3y40p4f2mxqeryiv29j1rki6v4p5u8a Drones na njikwa ọkụ ọhịa 0 28994 736700 725643 2026-10-07T12:13:43Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736700 wikitext text/x-wiki [[Usòrò:163d_Attack_Wing_Converts_Reapers_into_Hunter-Killers_of_Wildfire.jpg|thumb|Otu ụgbọelu MQ-9 Reaper nke e kenyere 163d Attack Wing na-efe n'elu igwe Southern California na ụgbọ elu ọzụzụ na March Air Reserve Base, California, na foto faịlụ a. nku ahụ na-efe MQ-9s iji kwado ndị ọchịchị obodo na-alụ ọgụ megide ọkụ ọhịa na Northern California. (Foto Air National Guard site na Tech. Sgt. Neil Ballecer)]] [[Usòrò:Drone_reconnaissance_during_wildfire_season_(39411577714).jpg|thumb|Vidio infrared a sitere n'elu North Umpqua Fire nke Marcus Tobey, BLM. Ọkụ ndịda ọdịda anyanwụ Oregon ahụ gbara ihe dị ka hekta 43,000 ọkụ.]] Ihe ọmụma a chịkọtara site na ngwaọrụ ndị a pụrụ iche ma bụrụ nke ziri ezi ka ha na-efe ala, nwayọ, na ogologo oge. Ha nwekwara ike ịnakọta ihe oyiyi dị elu na data sub-centimeter na anwụrụ ọkụ na n'abalị. Ọ na-enye ndị ọrụ mgbanyụ ọkụ ohere ịnweta data oge n'etinyeghị ndụ ndị ọkwọ ụgbọelu n'ihe ize ndụ.<ref name=":13">{{Cite news|author=Duewel|first=Jeff|title='The best friend a firefighter could have': How drones help battle Oregon wildfires|url=https://kval.com/outdoors/the-best-friend-a-firefighter-could-have-how-drones-help-battle-oregon-wildfires|work=KVAL|date=17 August 2018}}</ref><ref name=":2">{{Cite web|title=Drones and Wildfires: How New Tech is Shaping Wildfire Response - Wildfires, Drones, and Emergency Management|url=https://veoci.com/blog/wildfires-drones|work=veoci.com|accessdate=2020-05-01}}</ref><ref name=":1">{{Cite web|title=Using Drones to Eliminate Future Forest Fires|url=https://futuristspeaker.com/technology-trends/using-drones-to-eliminate-future-forest-fires/|author=Frey|first=Thomas|date=2018-08-22|work=Futurist Speaker|language=en-US|accessdate=2020-05-01}}</ref> A na-amanye ụlọ ọrụ na-ahụ maka ọkụ ka ụgbọelu ha daa iji zere ohere maka mgbagwoju anya n'etiti ikuku.<ref name=":20">"[https://www.faa.gov/uas/media/FAA_drones_wildfires_toolkit.pdf Drones & Wildfires Digital Toolkit.]" ''Federal Aviation Administration.'' Retrieved 2020-05-01. {{PD-notice}}</ref> Iwu dị na [[Njikọ̀taọ̀hà|United States]], [[Kánada|Canada]], na [[Ostraliya|Australia]] na-egbochi iji drones ọha na eze mee ihe n'akụkụ ọkụ ọhịa.<ref name=":7">Fatemah Afgah et al. "[[arxiv:1905.00492|Wildfire Monitoring in Remote Areas using Autonomous Unmanned Aerial Vehicles]]" Northern Arizona University & University of Alabama. Retrieved 2020-05-01.</ref><ref name=":21">{{Cite web|title=Drones on the Fire Ground - Australia Update|url=https://www.iawfonline.org/article/drones-on-the-fire-ground-australia-update/|work=International Association of Wildland Fire|language=en-US|accessdate=2020-05-01}}</ref><ref name=":22">"[https://web.archive.org/web/20220902134748/https://www2.gov.bc.ca/gov/content/safety/wildfire-status/fire-bans-and-restrictions/drones-uavs Drones and UAVs]" gov.bc.ca. Retrieved 2020-05-01.</ref> == Nkọwa == [[Usòrò:Thermal-infrared_imaging_sensors_on_NASA's_Ikhana_unmanned_research_aircraft_recorded_this_image_in_the_San_Bernardino_Mountains_of_Southern_California.jpg|thumb|Ihe mmetụta foto nke thermal-infrared na ụgbọ elu nyocha nke NASA Ikhana na-enweghị onye na-ahụ ya dekọrọ foto a nke Grass Valley / Slide Fire na nso Lake Arrowhead / Running Springs na Ugwu San Bernardino nke Southern California obere oge tupu ehihie Ọkt. 25. Ihe oyiyi a na-ahazi na 3-D bụ ihe oyiyi na-acha anụnụ anụnụ nke ihe oyiyi ndị a na-ekpuchi n'elu ala, na-ele anya n'ebe ọwụwa anyanwụ. A na-ahụ ọkụ na-arụ ọrụ na odo, ebe ebe ọkụ, ebe ọkụ gbara n'oge gara aga dị na agba ọbara ọbara na odo odo. A na-egosi ebe ndị a na-ere ọkụ na-acha akwụkwọ ndụ akwụkwọ ndụ.]] Ojiji nke UAVs na-egbochi ikpughe ma belata ihe ize ndụ nye ndị ọkwọ ụgbọelu na ndị ọrụ mgbanyụ ọkụ ọhịa. Ọ dị mfe ịkwanye ma nwee ike ife n'ebe ndị dịpụrụ adịpụ. Ndị a nwere ike ife ngwa ngwa dị ka kilomita 40 n'otu awa. Ndị na-anya ụgbọelu nwere ike iji ngwaọrụ ahụ rụọ ọrụ na ọsọ dịgasị iche iche iji nyere ndị mmadụ aka ịhụ ihe na-eme nke ọma. Enwere ike ile nnyefe sitere na drones ma ọ bụ UAV anya na kọmputa laptọọpụ na ọdụ ụgbọ ala na-agagharị agagharị. Drone nke dị kilogram 15 n'arọ na nku dị mita isii, nwere ihe dị ka kilomita asatọ ma nwee ike ịnọ n'ime ikuku ruo otu awa n'enweghị ike ịgbanye ọkụ. Enwere ike ịhazi ụgbọelu ahụ ka ọ na-efe n'onwe ya, mana onye na-anya ụgbọelu ga-enyocha ọrụ n'oge ule.<ref>{{Cite web|title=Drones: A Tool For Early Wildfire Detection|url=https://vpm.org/articles/4416/drones-a-tool-for-early-wildfire-detection|work=VPM.org|language=en|accessdate=2020-05-01|archivedate=2021-09-08|archiveurl=https://web.archive.org/web/20210908145703/https://vpm.org/articles/4416/drones-a-tool-for-early-wildfire-detection}}</ref> Ndị a na-arụkwa ọrụ dị ka ngwá ọrụ maka ịmalite atụmatụ ọkụ, nke a na-achịkwa iji kpochapụ ahịhịa siri ike igbu.<ref name=":9">{{Cite web|title=Feds Directed to Use Drones to Fight Wildfires|url=https://insideunmannedsystems.com/feds-directed-to-use-drones-to-fight-wildfires/|author=Divis|first=Dee Ann|date=2019-02-05|work=Inside Unmanned Systems|language=en-US|accessdate=2020-05-01}}</ref> Drones bụ akụkụ nke nyocha na njikwa ọkụ.<ref>{{Cite web|title=Fire|url=https://www.mdpi.com/journal/fire/special_issues/UAS|work=www.mdpi.com|language=en|accessdate=2020-05-01}}</ref> [[Usòrò:NASA_Ikhana.jpg|thumb|Ụgbọelu Ikhana nke NASA na-akwọ ụgbọelu, nke dị na Armstrong Flight Research Center nke ụlọ ọrụ ahụ, na-efe efe iji kwadebe maka ọrụ mbụ ya na mbara igwe ọha na eze na-enweghị ụgbọelu nchekwa.]] ==== Iwu Nchịkwa Ọkụ Ọkụ ==== Na Machị 2019, [[Donald Trump|Onye isi ala Trump]] bịanyere aka na Iwu Nchịkwa Ọhịa dị ka Nkebi 1114.<ref name=":16">{{Cite web|title=Bipartisan law pushes use of drones for fighting wildfires|url=https://www.fedscoop.com/bipartisan-bill-pushes-use-drones-fighting-wildfires/|date=12 March 2019|work=www.fedscoop.com|accessdate=2020-05-01}}</ref> Ebumnuche nke iwu ahụ bụ "ịmepụta usoro na atụmatụ na-agbanwe agbanwe maka iji ọkụ ọhịa nke teknụzụ usoro ụgbọ elu na-enweghị onye na-anya, gụnyere maka mmepe nke map oge nke ebe ọkụ ọhịa dị".<ref name=":16" /> Ewebatara ụgwọ ahụ na 2015 ka Carlton Complex Fire gasịrị.[1] [2].<ref name=":15">{{Cite web|title=What to know about the Wildfire Management Technology Advancement Act|url=https://www.firerescue1.com/fire-products/drones/articles/what-to-know-about-the-wildfire-management-technology-advancement-act-x99VVGGLMEvWZVdj/|work=FireRescue1|language=en|accessdate=2020-05-01}}</ref><ref>{{Cite news|author=Knicely|first=John|title=Wildfire firefighting technology bill headed to Trump, would expand drone mapping and GPS|url=https://www.kiro7.com/news/local/wildfire-firefighting-technology-bill-headed-to-trump-would-expand-drone-mapping-and-gps/925489555/|work=KIRO|date=February 26, 2019}}</ref> Ọrụ Elevated Robotic nke gọọmentị Alberta nwere nkwekọrịta, nke na-etinye drones maka ụlọ ọrụ ndị na-egwupụta ihe iji nyere ndị ọrụ mgbanyụ ọkụ aka ịhụ ebe ọkụ ahụ dị.<ref>{{Cite news|author=Berke|first=Jeremy|title=Firefighters are using drones to fight the raging wildfire in Alberta|url=https://www.businessinsider.com/alberta-irefighters-are-using-drones-2016-5|work=Business Insider|date=May 7, 2016}}</ref> N'ọnwa Disemba 2017, ndị nchọpụta na Mahadum nke British Columbia jiri drones nyochaa ihe si na ọkụ ọhịa pụta na British Columbia.<ref>{{Cite news|title=Surveying the Fury: Drones Assess Costs of 2017 BC Wildfires|url=https://forestry.ubc.ca/news/surveying-the-fury-drones-count-the-costs-of-the-2017-bc-wildfires/|work=UBC Faculty of Forestry|date=15 December 2017|archive-url=https://web.archive.org/web/20230601163057/https://forestry.ubc.ca/news/surveying-the-fury-drones-count-the-costs-of-the-2017-bc-wildfires/|archive-date=1 June 2023|access-date=16 August 2023|url-status=dead}}</ref> === China === .<ref>{{Cite journal|author=Li|first=Songsheng|title=Wildfire early warning system based on wireless sensors and unmanned aerial vehicle|journal=Journal of Unmanned Vehicle Systems|date=1 March 2019|volume=7|issue=1|pages=76–91|doi=10.1139/juvs-2018-0022}} </ref>Onye nyocha injinia kọmpụta na Guangdong College of Business and Technology na Zhaoqing, China, Dr. Songsheng Li na-arụ ọrụ na usoro ịdọ aka ná ntị mbụ nke kwụụrụ onwe ya maka ọkụ ọkụ. Ọ na-eji obere drones na-echegharị n'oké ọhịa, na-achịkọta data gburugburu ebe obibi, na nyocha ihe egwu nke ọkụ. Akụkụ ndị bụ isi nke sistemụ ya gụnyere sistemu GPS, ụgbọ ala ikuku na-enweghị mmadụ (UAV), na ụdị ụgbọ elu nwere ọgụgụ isi. [[Usòrò:MQ-9_Reaper_unmanned_aerial_vehicle.jpg|thumb|Ndị otu 163d Aircraft Maintenance Squadron,163d Attack Wing, California Air National Guard, na-eme nyocha tupu ụgbọ elu na MQ-9 Reaper nke nku ahụ tupu ọrụ nkwado ọkụ, Ọgọst 1, 2018, na March Air Reserve Base, California. Akụkụ ahụ na-akwado ụlọ ọrụ gọọmentị na-alụ ọgụ megide ọtụtụ ọkụ ọhịa na Northern California, gụnyere Carr Fire na Mendocino Complex Fire.]] Drones na-abịa n'ụdị dị iche iche ma nwee ihe nchọpụta na ngwá ọrụ dị iche iche.<ref name=":1" /> E nwere drones na-akpata ọkụ nke na-enyere aka belata mmebi nke ọkụ ọhịa kpatara.<ref name=":8">{{Cite news|author=Cagle|first=Susie|title='Dragon' drones: the flame throwers fighting wildfires with fire|url=https://www.theguardian.com/us-news/2019/sep/03/wildfires-drones-controlled-prescribed-burns|work=The Guardian|date=4 September 2019}}</ref> Ụgbọ elu ndị na-enwe mmasị n'anya bụ ndị ọha na-anya. Ndị ọchịchị na United States na Canada machibidoro iji drones ndị a mee ihe n'ọkụ ọhịa. Drones ndị a na-egbochi ọrụ mgbanyụ ọkụ ma gbochie ụlọ ọrụ iji usoro ikuku.<ref name=":18">{{Cite web|title=Drones and Wildfire {{!}} Department of Forestry and Fire Management|url=https://dffm.az.gov/fire/information/drones-and-wildfire|work=dffm.az.gov|accessdate=2020-05-01}}</ref> 71xw7fg29n8x0cdvv0qktm16r2a3bwn Jonah Wuyep 0 31885 736844 735511 2026-10-08T05:37:04Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736844 wikitext text/x-wiki {{Databox}} Jonah Domfa Wuyep (amụrụ na 23 Nọvemba 1948) bụ onye bụbu Chief of the Air Staff of the Nigerian Air Force. Jonah Domfa Wuyep Ndị Agha Naịjirịa Dị ka onye na-anya ụgbọelu, ọ na-anya C-130 Hercules ụgbọelu. C-130 Hercules == Oge ọ malitere ndu ya == A mụrụ Wuyep na 23 Nọvemba 1948 na Pil-Gani nke dị na mpaghara Langtang nke ihe ndị Britain na-achị ugbu a na Plateau State, Nigeria. Wuyep Langtang Plateau Steeti Nigeria Ọ gara Native Authority Primary School na Shendam site na 1959 ruo 1964 wee gaa Government Teachers College Toro na ugwu ọwụwa anyanwụ Nigeria site na 1966 ruo 1969. Shendam<ref name="naf"/> == Ọrụ ndị agha ụgbọelu == Wuyep banyere n'usuu ndị agha Naijiria dị ka onye isi cadet n'afọ 1970 ma nye ya ọrụ n'ime ndị agha ụgbọelu Naijiria n'afọ 1973. Ndị agha Naijiria Wuyep gụsịrị ọzụzụ ụgbọ elu ya na Kaduna Nigeria wee nweta nku ya mgbe ọ zụchara ọzụzụ na United States Air Force na Vance Air Force Base. Nnụnụ Kaduna United States Air Force Vance Air Force Base<ref name="naf">{{Cite web|url=http://www.nigerianairforce.net/fc_Wuyep.htm|title=Air Marshal J D Wuyep|accessdate=2007-04-26|work=The Official Web Site of the Nigerian Air Force|archiveurl=https://web.archive.org/web/20070928054655/http://www.nigerianairforce.net/fc_Wuyep.htm|archivedate=2007-09-28|url-status=bot: unknown}}<cite class="citation web cs1" data-ve-ignore="true">. ''The Official Web Site of the Nigerian Air Force''. Archived from [http://www.nigerianairforce.net/fc_Wuyep.htm the original] on 2007-09-28<span class="reference-accessdate">. Retrieved <span class="nowrap">2007-04-26</span></span>.</cite></ref><ref name="china">{{Cite news|url=http://english.people.com.cn/200408/10/eng20040810_152379.html|title=Nigeria sacks top security chiefs|publisher=[[People's Daily Online]]|date=2004-08-10|accessdate=2007-04-26}}</ref> Dị ka onye na-anya ụgbọelu a zụrụ azụ, Wuyep na-anya ma ụgbọelu na ụgbọelu ụgbọelu ọ bụ ezie na ọtụtụ n'ime ọrụ ụgbọ elu ya ejirila na C-130 Hercules. Nke a gụnyere ọrụ ụgbọ elu na Eastern na Southern Africa iji kwado nnwere onwe na Mozambique, Zimbabwe na Namibia yana ọrụ iji kwado United Nations Peace-Keeping Force na Lebanon. Mozambique Zimbabwe Namibia United Nations Peace-Keeping Force na Lebanọn N'afọ 1980, Wuyep gara Junior Command and Staff College na Pakistan ma site na 1983 ruo 1984, ọ malitere Senior Staff Course na Armed Forces Command and Staph College, Jaji. Kọleji ndị agha nke Pakistan Command and Staff, Jaji<ref name="naf" /> N'April 2001, e mere Wuyep ka ọ bụrụ onye isi ndị ọrụ ụgbọelu, onye isi nhọpụta na Nigerian Air Force na ọ kwalitere Air Marshal na 1 October 2001.[1]  Ka ndị agha ụgbọelu Naịjirịa nwetagoro ihe enyemaka ruru nde dollar atọ n'ụdị nke American C-130 spareparts, Wuyep kpọrọ oku ka enwee mmekọrịta dị n'etiti ndị agha ikuku Naịjirịa na ndị agha United States.  Wuyep kwetara na mmepe nke mmanụ na gas na Gulf of Guinea nwere ike ịbara ma Nigeria na United States uru.  Wuyep na-ekwupụtakwa olile anya ya na a ga-eweghachi mmemme ọzụzụ mbụ maka ndị ọrụ ụgbọ elu Naịjirịa na ndị agha ikuku US.[2]  Na May 2006, Onye isi ala Olusegun Obasanjo chụrụ Wuyep na mberede ka ọ bụrụ onye isi ndị ọrụ ụgbọ elu.  Air Marshal Paul Dike nọchiri Wuyep.<ref name="bbc">{{Cite news|url=http://news.bbc.co.uk/1/hi/world/africa/5031262.stm|title=Nigeria sacks top security chiefs|publisher=[[bbc.co.uk]]|date=2006-05-30|accessdate=2007-04-26}}</ref> == Edensibia == {{Reflist|2}} [[Òtù:Mmadụ ndi di ndụ]] b0ke6mxp1idt0uwk1oo2d3n5ax395wh José Luis Cuevas 0 32595 736845 735444 2026-10-08T06:07:11Z InternetArchiveBot 11600 Rescuing 2 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736845 wikitext text/x-wiki {{Infobox person|name=José Luis Cuevas|image=José Luis Cuevas 2011.jpg|caption=Luis Cuevas in 2011|birth_name=|birth_date=February 26, 1934|birth_place=Mexico City, Mexico|death_date=July 3, 2017 (aged 83)|death_place=Mexico City, Mexico|nationality=Mexican|occupation=painter, illustrator, printmaker, sculptor, writer|movement=[[Modernism]],<br> [[Neo-figurative|Neo-figurativism]],<br> [[Mexican muralism]]|awards=[[National Prize for Arts and Sciences]] of Fine Arts (1981)|website=[http://www.joseluiscuevas.com.mx Official website]}} [[Category:Articles with hCards]] '''José Luis Cuevas''' (February 26, 1934 &#x2D; July 3, 2017) bụ onye na-ese ihe na Mexico, ọ na-arụkarị ọrụ dị ka onye na-ise ihe, onye edemede, onye na-ede ihe, onye na'ese ihe, onye eserese, na onye na-ebi akwụkwọ. Cuevas bụ otu n'ime ndị mbụ na-ama ndị na-ahụ maka muralism na Mexico aka n'oge ahụ dị ka onye ama ama nke Generación de la Ruptura (English: Breakaway Generation). Ọ bụ onye na-ese ihe n'onwe ya, nke ụdị ya na mmetụta ya na-ejikọta n'akụkụ gbara ọchịchịrị nke ndụ, na-egosipụtakarị ndị gbagọrọ agbagọ na mmebi nke ihe a kpọrọ mmadụ. Ọ nọgidere bụrụ onye na-ese okwu n'oge niile ọ na-arụ ọrụ, ọ bụghị naanị maka ihe oyiyi ya na-awụ akpata oyi n'ahụ, kamakwa maka mmegide ya na ndị edemede na ndị na-ese ihe ọ na-eche na ha na-ekere òkè na nrụrụ aka ma ọ bụ na-emepụta naanị maka ego. N'afọ 1992, e meghere ụlọ ngosi ihe mgbe ochie José Luis Cuevas n'etiti akụkọ ihe mere eme nke Mexico City na-ejide ọtụtụ ọrụ ya na nchịkọta nka nke onwe ya. Nwa nwa ya Alexis de Chaunac bụ onye na-ese ihe n'oge a.<ref>{{Cite web|url=https://www.vanidades.com/estilo-de-vida/exposicion-mala-sangre-bestiario-de-alexis-de-chaunac-en-veracruz/|title=Se inaugura en Veracruz la exposición Mala Sangre / Bestiario de Alexis de Chaunac|work=vanidades.com|accessdate=2020-08-02}}</ref> == Akụkọ ndụ == === Oge ọ bụ nwata === A mụrụ José Luis Cuevas na Febụwarị 26, 1934, n'ezinụlọ nọ n'etiti na Mexico City. A mụrụ ya n'elu ụlọ ọrụ akwụkwọ na pensụl nke nna nna ya, Adalberto Cuevas.<ref name="biografia"/><ref name="sjsu"/> Mgbe ọ dị afọ iri, ọ malitere ịmụ ihe na National School of Painting and Sculpture "La Esmeralda", ọ malitekwara ise ihe osise na akwụkwọ akụkọ na akwụkwọ. <ref name="sjsu">{{Cite web|url=http://gallery.sjsu.edu/mexican_amerixan_tradition/muralists/cuevas.html|title=Jose Luis Cuevas|publisher=San José State University Digital Art Lobby|accessdate=June 2, 2012|archiveurl=https://web.archive.org/web/20121201143020/http://gallery.sjsu.edu/mexican_amerixan_tradition/muralists/cuevas.html|archivedate=December 1, 2012|url-status=dead}}<cite class="citation web cs1" data-ve-ignore="true">. San José State University Digital Art Lobby. Archived from [https://web.archive.org/web/20121201143020/http://gallery.sjsu.edu/mexican_amerixan_tradition/muralists/cuevas.html the original] on December 1, 2012<span class="reference-accessdate">. Retrieved <span class="nowrap">June 2,</span> 2012</span>.</cite></ref>Otú ọ dị, a manyere ya ịhapụ ọmụmụ ya na 1946 mgbe ọ butere Ọrịa rheumatic fever. Ọrịa ahụ hapụrụ ya n'àkwà ruo afọ abụọ. N'oge a, ọ mụtara ọrụ ịkpụ ihe nke Lola Cueto nke Mexico City College kụziiri.<ref name="sjsu" /> === Ọrụ mmalite === Mgbe ọ dị afọ iri na anọ, ọ gbazitere ohere n'okporo ámá Donceles iji mee ihe dị ka ụlọ ọrụ kama ịlaghachi n'ụlọ akwụkwọ n'ihi na ahụike ya na-adịghị mma pụtara na ọ maghị ogologo oge ọ ga-adị ndụ. O kpebiri na ọ ga-aka mma itinye onwe ya na nka ya. Cuevas mụtara otu esi agba ịnyịnya na ịkpa nkata maka ego. Ọ rụrụ ọrụ na ihe osise maka The News, n'agbanyeghị enweghị ọzụzụ, ọ kụziri klas ''Akụkọ'' nka na Coronet Hall Institute. <ref name="entrevista"/><ref name="biografia">{{Cite web|url=http://www.joseluiscuevas.com.mx/biografia.html|title=Cronología biográfica|publisher=José Luis Cuevas Museum|language=es|accessdate=June 2, 2012}}<cite class="citation web cs1 cs1-prop-foreign-lang-source" data-ve-ignore="true">[http://www.joseluiscuevas.com.mx/biografia.html "Cronología biográfica"] &#x5B;Biographical chronology&#x5D; (in Spanish). Mexico City: José Luis Cuevas Museum<span class="reference-accessdate">. Retrieved <span class="nowrap">June 2,</span> 2012</span>.</cite> [[Category:CS1 Spanish-language sources (es)]]</ref>Otu akụkụ nke ọzụzụ ya bụ ohere ileta ụlọ ọgwụ ndị isi mgbaka La Castaneda ebe nwanne ya nwoke na-arụ ọrụ iji dọta ndị ọrịa. === Ọgbọ nke Nkwụsị === A na-akọwa Cuevas mgbe ụfọdụ dị ka onye efu, onye ụgha na hypochondriac, nke na-arịa ọrịa na ọnwụ, ọkachasị nke ya. <ref name="entrevista">{{Cite news|title=Entrevista/ Jose Luis Cuevas/ El ombligo de Cuevas|first=Silvia|author=Cherem S|work=Reforma|date=May 28, 2000|page=1|language=es}}<cite class="citation news cs1 cs1-prop-foreign-lang-source" data-ve-ignore="true" id="CITEREFCherem_S2000">Cherem S, Silvia (May 28, 2000). "Entrevista/ Jose Luis Cuevas/ El ombligo de Cuevas" &#x5B;Interview/Jose Luis Cuevas/The navel of Cuevas&#x5D;. ''Reforma'' (in Spanish). Mexico City. p.&nbsp;1.</cite> [[Category:CS1 Spanish-language sources (es)]]</ref>Onye edemede René Avilés Fabila kwuru n'otu oge na "Ịhụnanya kasịnụ nke José Luis Cuevas bụ José Luis Cuavas, n'ihi na ọ bụ onye na-ese ihe hụrụ onwe ya n'anya karịa ọrụ ya. "Ihe kpatara nke a bụ na o meela ọtụtụ foto onwe ya nke na ọ dị ka inwe ọtụtụ enyo. <ref name="lsanchez">{{Cite news|title=Jose Luis Cuevas, enamorado de si mismo|first=Leticia|author=Sanchez|work=Reforma|date=May 23, 1997|page=1|language=es}}</ref>Cuevas kwuru na ya ekwenyeghị na ọ bụ ihe efu ma kwuo na echiche ahụ malitere na 1955 mgbe o kpebiri iwere foto onwe ya kwa ụbọchị, nke ọ nọgidere na-eme ruo ọgwụgwụ ndụ ya. <ref name="entrevista" />Ọ bụ otu n'ime ndị na-ese foto nke oge a na Mexico. <ref name="ftoledo"/>Otu akụkọ na-enweghị isi na-ekwu na ọ gara "ụlọ ndị akwụna" ebe ha na-akpụ akpụ ma na-akpọrọ ndị ahịa.   Akụkọ ọzọ na-akọwa ya na nwanyị dị afọ 70 aha ya bụ Gloria onye ọ nwara ịrata na onye ọzọ nke Marlene Dietrich tụbara onwe ya n'ebe ọ nọ. <sup class="noprint Inline-Template Template-Fact" style="white-space:nowrap;">&#x5B;''[[wikipedia:Tinye edensibịa|<span title="This claim needs references to reliable sources. (May 2013)">citation needed</span>]]''&#x5D;</sup><ref name="entrevista" />O kwetara na ọ bụ onye na-atụ ụjọ na onye na-agbachitere onwe ya, na-echegbu onwe ya banyere ịbụ onye a tụbara n'ụzọ na-adịghị mma.   O kwuru na Julio Scherer García bụ onye iro maka itinye aka n'ọrụ edemede ya. <sup class="noprint Inline-Template Template-Fact" style="white-space:nowrap;">&#x5B;''[[wikipedia:Tinye edensibịa|<span title="This claim needs references to reliable sources. (May 2013)">citation needed</span>]]''&#x5D;</sup>Ya na onye na-ese ihe Rufino Tamayo nwekwara esemokwu. <ref name="entrevista" />O kwuru na José Chávez Morado, Guillermo González Camarena na "Frente Popular de Artes Plasticas" na-enwere ya anyaụfụ nakwa na ha boro ya ebubo na ya na CIA na-arụ ọrụ n'afọ ndị 1950 mgbe ọ na-achọ ndị omenkà. <ref name="entrevista" />Ọbụna n'afọ ndị ikpeazụ ya, o mere nsọpụrụ site na imeghe ebe ngosi ihe mgbe ochie ya nye ndị enyi ya niile mana ndị ọ na-ewere dị ka ndị iro anaghị ekwe ka ha banye.<ref name="taibo">{{Cite journal|author=Taibo I|first=Pace Ignacio|date=September 1994|title=The Museo Jose Luis Cuevas|journal=Americas|volume=46|issue=5}}</ref> N'afọ ndị 1960, ọ gara [[Morocco]] ịmụ nka [[Àlakụ̀ba|Islam]], izute onye na-ese ihe Francis Bacon na Tangier. <ref name="biografia"/>Ọ ghọrọ onye na-ekweghị na Chineke mgbe nne ya nwụsịrị n'afọ ndị 1970. <ref name="entrevista"/>Site na 1976 ruo 1979, ọ "gbapụrụ onwe ya", hapụ Mexico gaa France, na-arụ ọrụ na akwụkwọ dị iche iche, serigraphs na lithographs maka mbipụta. Mgbe ọ laghachiri Mexico, o gosipụtara ihe ngosi "José Luis Cuevas. El regreso de otro hijo pródigo." (José Luis Fuevas. Nlaghachi nke nwa ọzọ na-enweghị ego).<ref name="biografia" /><ref name="entrevista" /> N'agbanyeghị amụma ya na ọ ga-adị ndụ ruo ihe karịrị otu narị n'ihi na ọgụgụ tarot dị iche iche gwara ya, Cuevas nwụrụ na July 3, 2017, na Mexico City mgbe ọ dị afọ 83.<ref>{{Cite news|language=es|work=El Paīs|date=4 July 2017|title=Muere el artista mexicano José Luis Cuevas|author=DAVID MARCIAL PÉREZ|url=https://cultura.elpais.com/cultura/2017/07/04/actualidad/1499123052_291713.html}}</ref><ref>{{Cite web|language=es|publisher=BBC Mundo|date=4 July 2017|title=Muere el artista plástico mexicano José Luis Cuevas, el líder de la "Generación de la Ruptura"|author=Alberto Nájar|url=http://www.bbc.com/mundo/noticias-america-latina-40490276}}</ref><ref>{{Cite web|url=https://abcnews.go.com/International/wireStory/mexican-painter-jose-luis-cuevas-dies-83-48426060|title=Mexican painter Jose Luis Cuevas dies at 83|publisher=ABC News|date=3 July 2017}}</ref> == Alụmdi na nwunye == [[Usòrò:Bertha Riestra de Cuevas 1982.jpg|thumb|Bertha Riestra de Cuevas, 1982]] [[Usòrò:José Luis Cuevas Novelo 1984.png|thumb|José Luis Cuevas, ngosi na Galeria de la Secretaría de Hacienda y Crédito Público, Centro Histórico de la Ciudad de México, 1984.]] Cuevas lụrụ nwunye mbụ ya, Bertha Riestra, na 1961. <ref name="biografia"/>Ọ zutere Bertha n'ụlọ ọgwụ La Castaneda mgbe ọ nọ ebe ahụ na-arụ ọrụ obodo na eserese. Nne na nna ya abịaghị agbamakwụkwọ ahụ n'ihi na ha anabataghị ya ebe ọ bụ na ọ bụ onye na-ese ihe. <ref name="entrevista"/>N'agbanyeghị na ọ lụrụ di, ọ nwetara aha dị ka onye na-eme ihe ike, nke a na-akpọ "gato macho" (nwoke nwamba) ma ọ bụ onye na-eduhie ụmụ nwanyị, nke o ji mee ihe iji kwalite onwe ya. <ref name="entrevista" />N'otu akwụkwọ akụkọ Mexico City nke o dere, o kwuru na ya nwere ihe karịrị 650 mmekọahụ. <ref name="entrevista" />Ọ na-ekwu na e kweghị ka Bertha nwee otu nnwere onwe ahụ nakwa na ọ maghị banyere ihe omume ya n'agbanyeghị ihe odide ya banyere ha. <ref name="entrevista" />Ya na Bertha nwere ụmụ nwanyị atọ, Mariana, Ximena na María Jose. <ref>{{Cite journal|author=Gutiérrez|first=Laura G.|title=Reframing the Retablo : Mexican Feminist Critical Practice in Ximena Cuevas' Corazon Sangrante|journal=Feminist Media Studies|date=14 December 2010|volume=1|issue=1|pages=73–90|doi=10.1080/14680770120042873}}</ref>N'afọ 2000, Berta Riestra, nwunye ya na, n'oge ahụ, onye nduzi nke José Luis Cuevas Museum, nwụrụ n'ihi ọrịa kansa ara na leukemia. N'afọ sochirinụ, ọ zutere Beatriz del Carmen Bazán, onye ọ lụrụ na 2003 na ebe ngosi ihe mgbe ochie.<ref name="biografia" /><ref name="entrevista" /> Cuevas na nwunye ya bi na mpaghara San Ángel nke Mexico City. E wuru ụlọ ahụ maka Cuevas n'afọ ndị 1970 site n'aka ndị na-ese ụkpụrụ ụlọ Abraham Zabludovsky na Teodoro González de León n'ụdị na-echetara Luis Barragán. Mgbidi ndị ahụ bụ ụcha na-acha ntụ ntụ na ahịrị kwụ ọtọ. Ihe dị n'ime ya bụ minimalist na ihe osise nke onye na-ese ihe na mgbidi na oche osisi na akwa Mexico. Ọ bụ ezie na ụlọ ahụ dị ọcha ma dị n'usoro, oghere a raara nye dị ka ụlọ ọrụ ya bụ ihe na-adịghị mma, jupụtara na akwụkwọ, ígwè ọrụ ochie, onyokomita, enyo, ọtụtụ foto na ihe ndị ọzọ.<ref name="ftoledo">{{Cite news|title=Jose Luis Cuevas: En la cueva de Cuevas|first=Fernando|author=Toledo|work=Reforma|date=December 21, 1995|page=4|language=es}}<cite class="citation news cs1 cs1-prop-foreign-lang-source" data-ve-ignore="true" id="CITEREFToledo1995">Toledo, Fernando (December 21, 1995). "Jose Luis Cuevas: En la cueva de Cuevas" &#x5B;Jose Luis Cuevas: In the cave of Cuevas&#x5D;. ''Reforma'' (in Spanish). Mexico City. p.&nbsp;4.</cite> [[Category:CS1 Spanish-language sources (es)]]</ref> == Ihe ngosi == [[Usòrò:CourtyardJLCMuseumDF.JPG|thumb|Ogige nke José Luis Cuevas Museum na "La Giganta"]] N'ime ọrụ nke gafere ihe karịrị afọ iri asaa, Cuevas bụ onye na-ese ihe, onye edemede, onye na-ede ihe, onye na'ese ihe, na onye na-ebi akwụkwọ. <ref name="sjsu"/><ref name="rendiran">{{Cite news|title=Rendirán homenaje al artista plástico José Luis Cuevas|url=http://www.eluniversal.com.mx/notas/832149.html|work=El Universal|date=February 23, 2012|accessdate=June 2, 2012|language=es}}</ref>E nweela ihe ngosi onwe onye na ọrụ Cuevas na ebe ngosi ihe mgbe ochie na gallery n'ụwa niile. <ref name="rogallery"/>Ihe ngosi mbụ ya bụ mgbe ọ dị naanị afọ iri na anọ na Seminario Axiologico mana ọ dịghị onye bịara, ọrụ ndị ahụ si na mgbidi pụta ma gaa n'ihu. <ref name="sjsu" /><ref name="entrevista"/>Ihe ngosi mbụ ya nke ọma bụ na Galería Prisse nke Mexico City na 1953, mgbe ọ dị afọ iri na itoolu. <ref name="biografia"/><ref name="sjsu" />N'afọ 1954, ọ zutere onye nkatọ Jose Gomez-Sicre onye kpọrọ ya ka ọ gosipụta na Panamerican Union na [[Washington, D.C.|Washington, DC]]. <ref name="biografia" />Oge a, ihe ngosi mbụ ya na US, rere n'abalị mmeghe ma mee ka ọ gbaa Time na Washington Post ajụjụ ọnụ, nke kpọrọ ya "nwa nwoke ọlaedo", na-emeghe ọnụ ụzọ ma na-enyere aka ire ihe osise ya. <ref name="entrevista" />N'afọ 1955, o sonyere na Salón de Arte Libre nke mbụ nke Galería Proteo haziri, ebe ọ zutere David Alfaro Siqueiros. N'ime afọ ndị fọdụrụnụ na 1950, o gosipụtara na Havana, Caracas, Lima na Buenos Aires, ebe ọ zutere Jorge Luis Borges.<ref name="biografia" /> N'afọ 1960, o gosipụtara na David Herbert Gallery, Oge NY Times jiri ya tụnyere Picasso. N'afọ 1961, abụọ n'ime ọrụ ya na Galería del L'Oblisco na Rom, Los Funerales de un Dictador na La Caída de Franco kpatara esemokwu ndọrọ ndọrọ ọchịchị na Spain nke rịọrọ ka ewepụ ihe oyiyi ahụ. N'afọ 1962, o gosipụtara usoro ọrụ ndị dabeere na ihe ọkpụkpụ nke Tilman Riemenschneider ọ hụrụ na Munich. Ihe ngosi ndị ọzọ Cuevas gosipụtara site n'oge a gụnyere otu na Silvan Simone Gallery na 1967.<ref name="biografia"/> N'ime afọ ndị 1970, o gosipụtara foto onwe ya 72 na Centro Cultural Universitario na UNAM, ma gosipụta ọrụ ndị ọzọ na San Francisco Museum of Art, Museo de Arte Contemporáneo na Caracas, Phoenix Art Museum, Musee d'Art Moderne na Paris na Museo de Arte Moderno na Mexico City. <ref name="biografia"/>N'afọ 1976, o nwere ụmụ nwanyị anọ egbugbu na atụmatụ mbụ nke ya, ka nka ahụ "ga-etolite na ya" Nke a n'agbanyeghị eziokwu ahụ bụ na egbugbu bụ iwu na-akwadoghị na Mexico n'oge ahụ. <ref name="entrevista"/>N'afọ 1979, Jose Luis gosipụtara ihe osise mmiri 50 na ihe osise tinyere akwụkwọ ozi ndị e sere na Tasende Gallery, La Jolla, California. N'afọ 1981, ọ meghere ihe ngosi "Signs of Life" nke nwere karama nwere ọbara ọcha ya na electrocardiogram e weere mgbe ọ na-enwe mmekọahụ. O kwuru na broshuọ nke ihe ngosi ahụ na ọ ga-etinye ime nwanyị ọ bụla rịọrọ ya ime otú ahụ, mana Secretaría de Gobernación mere ka o wepụ broshuọ ahụ n'ihi na a na-ewere ya dị ka omume ịgba akwụna. <ref name="entrevista"/>N'afọ 1982, ụlọ ngosi iri na anọ dị na Mexico City, Barcelona, Paris na ndị ọzọ nwere ihe ngosi nke "Marzo. Mes de José Luis Cuevas" ("March. Month of Jose Luis Cueves.") Site na 1984 ruo 1988, usoro ihe osise 50 buru ibu a na-akpọ "Intolerance" gara mahadum na ebe ngosi ihe mgbe ochie na US, [[Kánada|Canada]], Mexico na Europe. Ihe osise ndị a sitere na onyinye Jose Tasende nyere Cuevas nke akwụkwọ "The Witches' Advocate" nke Gustav Henningsen. <ref name="biografia"/>N'afọ 1985, ya na Henry Moore na Eduardo Chillida gosipụtara na ngosi Figure Space Image na Tasende Gallery, La Jolla, California. A na-egosipụta akwụkwọ ozi ndị o degaara onye na-ere ahịa ya JM Tasende n'oge ọ na-esi na Mexico na Tasende Gallery tupu ọ bụrụ akụkụ nke nchịkọta na-adịgide adịgide nke Metropolitan Museum of Art, New York. N'afọ 1991, "Celebrating 25 Years with Jose Luis Cuevas" meghere na Tasende Gallery, La Jolla. O mepụtara ihe osise Talavera nke e debere na Mpaghara Rosa Rosa na 1995. N'afọ 1997, o gosipụtara na Tasende Gallery, West Hollywood, California. N'afọ 1998, o gosipụtara "Retrospectiva de Dibujo y Escultura" na Museo Nacional Centro de Arte Reina Sofía. N'afọ 1999, Pablo Picasso Foundation gosipụtara ihe ngosi "José Luis Cuevas. Ọrụ eserese".<ref name="biografia"/> N'afọ 2001, o nyere obodo Colima ihe a tụrụ atụ a na-akpọ "Figura Obscena" (Obscene Figure). Ihe a a tụrụ atụ ghọrọ etiti ihe ihere na 2006. <ref name="biografia"/>Ihe ngosi ndị ọzọ sitere na afọ 2000 gụnyere na 2005 "Jose Luis Cuevas na Drawing and Sculpture" na Latin American Art Museum na Long Beach, California. "Ihe osise na Watercolors ahọpụtara" Tasende Gallery, West Hollywood, California. N'afọ 2006, o meghere Paseo Escultórico Nezahualcóyotl na ihe a tụrụ atụ aha ya bụ nwunye ya nke a na-akpọ "Carmen". Retrospective Exhibition na Museum of the Palace of Fine Arts na Mexico City n'afọ 2008. "Exposición Siameses 50 Años de la Plástica del Maestro José Luis Cuevas" na 2009 na 2011 na "Dibujo y Escultura" na 2010. Ọ gara n'ihu na-egosipụta ọrụ ya ruo mgbe ọ nwụrụ, ọkachasị na Mexico.<ref name="biografia" /> == Akwụkwọ ndị e bipụtara == [[Usòrò:José Luis Cuevas 1984.jpg|thumb|José Luis Cuevas]] Ka ọ na-erule afọ iri na anọ, Cuevas sere ọtụtụ akwụkwọ akụkọ na akwụkwọ. <ref name="rogallery">{{Cite web|url=http://rogallery.com/cuevas_jose_luis/cuevas-biography.htm|title=José Luis Cuevas biography|publisher=Ro Gallery|accessdate=June 2, 2012}}<cite class="citation web cs1" data-ve-ignore="true">[http://rogallery.com/cuevas_jose_luis/cuevas-biography.htm "José Luis Cuevas biography"]. Ro Gallery<span class="reference-accessdate">. Retrieved <span class="nowrap">June 2,</span> 2012</span>.</cite></ref>N'afọ 1957, ọ gara Philadelphia iji gosipụta akwụkwọ "The World of Kafka and Cuevas" maka Falcon Prest Publishers. <ref name="biografia"/>Na ngwụcha afọ 1950, ọ malitere ide ihe gbasara ọdịbendị maka mbipụta Novedades de México, ebe ọ zoro aka na ndị na-ese ihe n'oge ahụ dị ka Diego Rivera dị ka "cortina del nopal" (Nopal Cactus Curtain) ma kwado maka nnwere onwe nka ka ukwuu. Nkà ihe ọmụma a kpaliri ntọala na 1960 nke otu Nueva Presencia, nke ọ sonyeere maka oge dị mkpirikpi. Ìgwè ahụ kwalitere ngosipụta onwe onye na nka ihe atụ nke na-egosipụta ọnọdụ mmadụ nke oge a.<ref name="biografia" /><ref name="rogallery" /> == Ihe odide == {{Reflist}} [[Òtù:Pages with unreviewed translations]] cdc9qlwfx23mru9s8h207fge37jlufk Elvira Devinamira 0 32779 736826 721083 2026-10-07T20:22:38Z IgboRefBot 66663 736826 wikitext text/x-wiki {| class="infobox biography vcard" ! colspan="2" class="infobox-above" style="font-size:125%;" |<div class="fn" style="display:inline">Elvira Devinamira</div> |- | colspan="2" class="infobox-image" |[[File:Elvira_Devinamira_The_Best_of_Ini_Talkshow.jpg|frameless]]<div class="infobox-caption">Miss Universe Indonesia 2014, Elvira Devinamira Wirayanti na Ini Talkshow, [[NET (Indonesian TV network)|NET TV]]</div> |- ! class="infobox-label" scope="row" |A mụrụ ya | class="infobox-data" |<div class="nickname" style="display:inline"><span class="nowrap">Elvira Devinamira Wirayanti</span></div><br /><span style="display:none"> </span> <span style="display:none">(<span class="bday">1993-06-28</span>)</span> 28 June 1993 (afọ 30) <br /><div class="birthplace" style="display:inline">[[Surabaya]], East Java[[East Java|Ebe Ọwụwa Anyanwụ Java]]</div> |- ! class="infobox-label" scope="row" |Alma mater&nbsp; | class="infobox-data" |[[Airlangga University|Mahadum Airlangga]]<ref name="Law Degree (1)">{{cite web|url=http://news.unair.ac.id/en/2016/05/30/putri-indonesia-2014-conferred-bachelor-of-law-after-pageant-contest/|title=Putri Indonesia 2014 Conferred Bachelor of Law after Pageant Contest|publisher=[[Airlangga University]]|accessdate=May 30, 2016|archivedate=June 5, 2016|archiveurl=https://web.archive.org/web/20160605140843/http://news.unair.ac.id/en/2016/05/30/putri-indonesia-2014-conferred-bachelor-of-law-after-pageant-contest/}}</ref><ref name="Law Degree (2)">{{cite web|url=http://alumni.unair.ac.id/site/article/read/780/berawal-dari-cak-dan-ning-surabaya.html|title=Universitas Airlangga Pencapaian Alumni Berawal dari Cak dan Ning Surabaya|publisher=[[Airlangga University]]|accessdate=June 2, 2020|archive-date=June 18, 2020|archive-url=https://web.archive.org/web/20200618114626/http://alumni.unair.ac.id/site/article/read/780/berawal-dari-cak-dan-ning-surabaya.html|url-status=dead|archivedate=June 18, 2020|archiveurl=https://web.archive.org/web/20200618114626/http://alumni.unair.ac.id/site/article/read/780/berawal-dari-cak-dan-ning-surabaya.html}}</ref><ref name="Law Degree (3)">{{cite web|url=https://www.jawapos.com/nasional/pendidikan/17/07/2017/bahagia-akhirnya-putri-indonesia-arek-suroboyo-itu-diwisuda/|title=Bahagia Akhirnya Putri Indonesia Arek Suroboyo itu Diwisuda|publisher=[[Jawa Pos]]|accessdate=July 17, 2017}}</ref> |- ! class="infobox-label" scope="row" |Ọrụ | class="infobox-data role" |<templatestyles src="Hlist/styles.css"></templatestyles><div class="hlist"> * Onye na-eme ihe nkiri<ref name="Acting">{{Cite web|url=https://www.cnnindonesia.com/hiburan/20151112062330-220-91134/elvira-devinamira-kecanduan-berakting|title=Elvira Devinamira Kecanduan Berakting|publisher=[[CNN Indonesia]]|date=November 12, 2015|language=id}}</ref><ref name="Single (1)">{{Cite web|url=https://www.merdeka.com/artis/bertinggi-177-cm-elvira-devinamira-ikutan-single.html|title=Bertinggi 177 cm, Elvira Devinamira ikutan 'SINGLE'|publisher=[[merdeka.com]]|date=November 10, 2015|language=id}}</ref><ref name="Single (2)">{{Cite web|url=https://www.liputan6.com/showbiz/read/2361411/elvira-devinamira-dan-raditya-dika-mesra-di-single|title=Elvira Devinamira dan Raditya Dika Mesra di Single|publisher=[[Liputan 6]]|date=November 9, 2015|language=id}}</ref>><ref name="Single (3)">{{Cite web|url=https://hot.detik.com/movie/d-3066158/pengalaman-pertama-puteri-indonesia-2014-di-film-komedi-single|title=Pengalaman Pertama Puteri Indonesia 2014 di Film Komedi 'Single'|publisher=[[detik.com|Detik News]]|date=November 9, 2015|language=id}}</ref> * Ihe nlereanya * Onye na-eme ihe nkiri ịma mma </div> |- ! class="infobox-label" scope="row" |Ogologo | class="infobox-data" |1.76 m (5 ft 9 in) &nbsp;&nbsp;&nbsp; |- | colspan="2" class="infobox-full-data" |<templatestyles src="Module:Infobox/styles.css"></templatestyles>'''Onye na-eme ihe nkiri ịma mma''' |- ! class="infobox-label" scope="row" |Aha ya | class="infobox-data" |Puteri Indonesia 2014<br />Miss Universe Indonesia 2014 |- ! class="infobox-label" scope="row" |Agba ntutu | class="infobox-data" |Ọcha nchara |- ! class="infobox-label" scope="row" |Agba anya | class="infobox-data" |Ọcha nchara |- ! class="infobox-label" scope="row" |<span class="nowrap">Nnukwu asọmpi<br /></span> | class="infobox-data" |[[Puteri Indonesia 2014]]">Puteri East Java 2014 ''''''(Onye mmeri)'''''' Puteri Indonesia 2014 (Owe mmeri) Miss Universe 2014 (Top 15) (Ewe Kasị Mma nke Mba) <br /><br /><br /><br /><br /><ref name="Elvira Top 15 semifinalist (1)">{{Cite web|url=https://www.usmagazine.com/stylish/pictures/miss-universe-2015-top-15-finalists-bikini-photos-2015261/43705/|title=Miss Universe 2014: Top 15 Model Bikinis!|publisher=[[Us Weekly]]|accessdate=January 20, 2015}}</ref><ref name="Elvira Top 15 semifinalist (2)">{{Cite web|url=https://www.prnewswire.com/news-releases/miss-universe-colombia-paulina-vega-crowned-miss-universe-2014-during-the-63rd-annual-miss-universe-pageant-300025314.html|title=Miss Universe 2014 During The 63rd Annual Miss Universe® Pageant|publisher=[[PR Newswire]]|accessdate=January 26, 2015}}</ref><ref name="Elvira Top 15 semifinalist (3)">{{Cite web|url=https://www.floridatoday.com/picture-gallery/entertainment/2015/01/25/photos-miss-universe-pageant-2015-in-miami/22329161/|title=Photos: Miss Universe pageant 2015 in Miami|publisher=[[Florida Today]]|accessdate=January 26, 2015}}</ref><ref name="Elvira Top 15 semifinalist (4)">{{Cite web|url=https://www.cnnindonesia.com/gaya-hidup/20150126103711-277-27319/kutukan-15-besar-miss-universe-untuk-indonesia|title='Kutukan' 15 Besar Miss Universe untuk Indonesia|publisher=[[CNN Indonesia]]|accessdate=February 26, 2014}}</ref><ref name="Elvira Top 15 semifinalist (5)">{{Cite web|url=https://tucson.com/elvira-devinamira/image_6667c7e8-a519-11e4-9b60-67984851c513.html|title=Miss Universe 2014: Top 15 Elvira Devinamira!|publisher=[[Tucson, Arizona|Tucson Weekly News]]|accessdate=January 26, 2015}}</ref><br /><ref name="Best National Costume (1)">{{Cite web|url=https://www.wsj.com/articles/BL-SEAB-5650|title=Photo of the Day: Miss Indonesia's Borobudur Chronicles Costume|publisher=[[The Wall Street Journal]]|accessdate=January 26, 2015}}</ref><ref name="Best National Costume (2)">{{Cite web|url=https://jakartaglobe.id/culture/miss-indonesia-wins-best-national-costume-miss-universe-pageant/|title=Miss Indonesia Wins Best National Costume at Miss Universe Pageant|publisher=[[Jakarta Globe]]|accessdate=January 26, 2015}}</ref><ref name="Best National Costume (3)">{{Cite web|url=https://www.cosmopolitan.com/entertainment/news/a35668/miss-indonesia-national-costume-miss-universe-2014/|title=Miss Indonesia Wins Best National Costume at Miss Universe 2014|publisher=[[Cosmopolitan (magazine)|Cosmopolitan]]|accessdate=January 26, 2015}}</ref><ref name="Best National Costume (4)">{{Cite web|url=https://www.rappler.com/world/asia-pacific/miss-indonesia-best-national-costume-miss-universe-2014|title=Miss Universe 2014: Indonesia wins Best National Costume|publisher=[[Rappler]]|accessdate=January 26, 2015}}</ref> |} [[Category:Articles with hCards]] '''Elvira Devinamira Wirayanti''' (amụrụ na 28 June 1993 na Surabaya, East Java) bụ onye Indonesia na-eme ihe nkiri, Model, Beauty Pageant titleholder onye e kpuwere okpueze Puteri Indonesia 2014, ma nọchite anya mba ya na asọmpi Miss Universe 2014 nke emere na FIU Arena na [[Flórídạ|Florida]], [[Njikọ̀taọ̀hà|United States]], ebe ọ nọ n'ime ''"Top 15"'' wee merie "Best National Costume" nke ugboro abụọ maka Indonesia, mgbe Agni Pratistha gasịrị na 2007. <ref name="Acting"/><ref name="Single (1)"/><ref name="Single (2)"/><ref name="Single (3)"/><ref name="Pageantry (1)">{{Cite news|url=https://www.thejakartapost.com/news/2014/02/07/elvira-devinamira-the-princess-perseverance.html|title="Elvira Devinamira: The princess of perseverance"|publisher=[[The Jakarta Post]]|accessdate=February 7, 2014}}</ref><ref name="Pageantry (2)">{{Cite news|url=https://padangpariamankab.go.id/2014/04/30/putri-indonesia-2014-kunjungi-padang-pariaman-60961/|title=Putri Indonesia 2014 Kunjungi Padang Pariaman|publisher=[[Padang Pariaman Regency|Padang Pariaman Regency Government]]|accessdate=April 30, 2014|archive-date=June 26, 2021|archive-url=https://web.archive.org/web/20210626212249/https://padangpariamankab.go.id/2014/04/30/putri-indonesia-2014-kunjungi-padang-pariaman-60961/|url-status=dead}}</ref><ref name="Pageantry (3)">{{Cite news|url=https://padangpariamankab.go.id/2014/04/08/putri-indonesia-2014-kunjungi-padang-pariaman/|title=Putri Indonesia 2014 Kunjungi Padang Pariaman|publisher=[[Padang Pariaman Regency|Padang Pariaman Regency Government]]|accessdate=April 8, 2014|archive-date=June 26, 2021|archive-url=https://web.archive.org/web/20210626210735/https://padangpariamankab.go.id/2014/04/08/putri-indonesia-2014-kunjungi-padang-pariaman/|url-status=dead}}</ref><ref name="Pageantry (4)" /><ref name="Puteri Indonesia (1)">{{Cite web|url=http://en.ce.cn/main/photo/201401/30/t20140130_2236728.shtml|title=Elvira Devinamira crowned Puteri Indonesia 2014|publisher=[[Economic Daily|China Economic Daily]]|accessdate=January 30, 2014|archivedate=February 2, 2014|archiveurl=https://web.archive.org/web/20140202222937/http://en.ce.cn/main/photo/201401/30/t20140130_2236728.shtml}}</ref><ref name="Puteri Indonesia (2)">{{Cite web|url=https://www.emirates247.com/lifestyle/miss-puteri-indonesia-2014-elvira-devinamira-2014-01-30-1.536626|title=Miss Puteri Indonesia 2014: Elvira Devinamira|publisher=[[Emirates 24/7]]|accessdate=January 30, 2014}}</ref><ref name="Puteri Indonesia (3)">{{Cite web|url=http://en.people.cn/90782/8526302.html|title=Elvira Devinamira crowned Puteri Indonesia 2014|publisher=[[People's Daily|China People's Daily]]|accessdate=January 30, 2014}}</ref><ref name="Puteri Indonesia (4)">{{Cite web|url=https://www.thejakartapost.com/news/2014/01/30/indonesia-s-2014-queen.html|title=Puteri Indonesia 2014 Queens|publisher=[[The Jakarta Post]]|accessdate=January 30, 2014}}</ref><ref name="Elvira Top 15 semifinalist (1)"/><ref name="Elvira Top 15 semifinalist (2)"/><ref name="Elvira Top 15 semifinalist (3)"/><ref name="Elvira Top 15 semifinalist (4)"/><ref name="Elvira Top 15 semifinalist (5)"/><ref name="Best National Costume (1)"/><ref name="Best National Costume (2)"/><ref name="Best National Costume (3)"/> <ref name="Best National Costume (4)"/><ref name="Best National Costume (5)">{{Cite web|url=https://www.usmagazine.com/stylish/news/miss-indonesia-best-costume-miss-universe-2015-photo-2015261/|title=Miss Indonesia Elvira Devinamira Wins Best Costume for Miss Universe 2015: See Her Amazing Look|date=26 January 2015|publisher=[[Us Weekly]]|accessdate=January 26, 2015}}</ref><ref name="Best National Costume (6)">{{Cite web|url=https://indonesiatatler.com/society/8-indonesian-celebrities-and-tatler-friends-with-mombodgoals|title=5 Boldest Indonesian National Costumes In Miss Universe|publisher=[[Tatler|Tatler Indonesia]]|accessdate=December 12, 2018|archivedate=June 26, 2021|archiveurl=https://web.archive.org/web/20210626185201/https://indonesiatatler.com/society/8-indonesian-celebrities-and-tatler-friends-with-mombodgoals}}</ref><ref name="Best National Costume (7)">{{Cite web|url=https://en.tempo.co/read/637813/indonesia-wins-best-national-costume-in-miss-universe-event|title=Indonesia Wins Best National Costume in Miss Universe Event|date=19 October 2018|publisher=[[Tempo (Indonesian magazine)]]|accessdate=October 19, 2018}}</ref><ref name="Best National Costume (8)">{{Cite web|url=https://hollywoodlife.com/2015/01/25/miss-indonesia-wins-best-national-costume-miss-universe-pic/|title=Miss Indonesia Wins Best NationalCostume At Miss Universe 2014|publisher=[[Hollywood Life]]|accessdate=January 25, 2015|archivedate=January 27, 2015|archiveurl=https://web.archive.org/web/20150127070536/http://hollywoodlife.com/2015/01/25/miss-indonesia-wins-best-national-costume-miss-universe-pic/}}</ref>Ọ bụ onye Indonesia nke atọ na onye Javanese mbụ a kpọrọ Miss Universe Finalists.<ref name="Elvira Top 15 semifinalist (1)" /><ref name="Elvira Top 15 semifinalist (2)" /><ref name="Elvira Top 15 semifinalist (3)" /><ref name="Elvira Top 15 semifinalist (4)" /><ref name="Elvira Top 15 semifinalist (5)" />ref == Mbido ndụ na agụmakwụkwọ == A mụrụ Elvira ma zụlite ya na Surabaya, East Java - Indonesia n'aka nne na nna Javanese, Ọ bụ nwa mbụ n'ime ụmụnne abụọ. <ref name="Law Degree (2)"/><ref name="Law Degree (3)"/>Elvira na-arụ ọrụ dị ka ihe nlereanya kemgbe ọ dị afọ iri na isii, ọ gụsịrị akwụkwọ na Mahadum Airlangga, Surabaya - East Java na Cum Laude. <ref name="Law Degree (1)"/><ref name="Law Degree (2)"/><ref name="Law Degree (3)"/>O ruru ọtụtụ ihe ọ rụzuru ma bụrụkwa otu n'ime ndị nnọchi anya Indonesia na mmemme njem mgbanwe Model United Nations na Seoul, South Korea, 24th Harvard Model United Nations Conference na 2011, ma bụrụkwa akụkụ nke ndị nnọchianya Indonesia na Harvard National Model United Nations Conference 2012 na Boston, [[Njikọ̀taọ̀hà|United States]].<ref name="Law Degree (1)"/><ref name="Law Degree (2)" /><ref name="Law Degree (3)"/> == Egwuregwu == [[Usòrò:Elvira_Devinamira_Wirayanti_for_Jamu_Event_With_Ministry_of_Industry_and_Ministry_of_Youth_and_Sport_of_The_Republic_of_Indonesia.jpg|áká_èkpè|thumb|260x260px|Elvira na Jamu Event na Ministry of Industry na Ministry of Youth and Sport nke Republic of Indonesia.<ref name="Pageantry (4)">{{Cite news|url=https://kemenperin.go.id/artikel/11049/Minum-Jamu-Bersama-di-Kementerian-Pemuda-dan-Olahraga|title=Minum Jamu Bersama di Kementerian Pemuda dan Olahraga|publisher=[[Ministry of Industry (Indonesia)|Ministry of Industry of The Republic of Indonesia]]|accessdate=February 6, 2015}}<cite class="citation news cs1" data-ve-ignore="true">[https://web.archive.org/web/20150623055729/http://www.kemenperin.go.id/artikel/11049/Minum-Jamu-Bersama-di-Kementerian-Pemuda-dan-Olahraga "Minum Jamu Bersama di Kementerian Pemuda dan Olahraga"]. [[Ngalaba Na-ahụ Maka Ụlọ Ọrụ (Indonesia)|Ministry of Industry of The Republic of Indonesia]]<span class="reference-accessdate">. Retrieved <span class="nowrap">February 6,</span> 2015</span>.</cite></ref>]] === Cak Ning Surabaya === Tupu ọ banye n'ọhịa nke asọmpi, Elvira sonyere na asọmpi ntụrụndụ nke obodo ya Surabaya, nke a na-akpọ ''"Cak Ning Surabaya"'', ebe a họpụtara ya dị ka onye nke abụọ na Cak Ning Sur abaya.<ref name="Law Degree (2)"/><ref name="Pageantry (1)"/><ref>{{cite web|title=Elvira Devinamira Wirayanti – Profil Alumnus Universitas Airlangga|url=https://alumni.unair.ac.id/profile/4f725b16-ecfe-4bd4-a8a9-dabed9f7a6fb|website=Alumnipedia UNAIR|publisher=Universitas Airlangga|access-date=30 Desember 2025}}</ref> === Puteri Indonesia East Java 2014 === Elvira sonyeere asọmpi ahụ na mpaghara nke Puteri Indonesia East Java 2014, ma mechaa bụrụ onye mmeri nke Puteri Indonesian East Java 2014.<ref name="Law Degree (2)"/><ref name="Pageantry (1)"/> === Puteri Indonesia 2014 === Mgbe ọ ruru eru maka aha mpaghara nke [[Indonesia]]_2014" id="mwvw" rel="mw:WikiLink" title="Puteri Indonesia 2014">Puteri Indonesia East Java 2014, Elvira nọchitere anya mpaghara nke East Java na asọmpi ịma mma mba, Puteri Indonesia 2014, nke emere na Jakarta Convention Center, Jakarta, Indonesia na 29 Jenụwarị 2014. <ref name="Pageantry (2)"/><ref name="Pageantry (3)"/><ref name="Pageantry (4)"/>Na ngwụcha asọmpi ahụ, a họpụtara Elvira nke ọma dị ka onye mmeri nke Puteri Indonesia 2014 (Miss Universe Indonesia 2014) ,<ref name="Puteri Indonesia (1)"/><ref name="Puteri Indonesia (2)"/> Onye nọchiri ya bụ Puteri Indonesia 2013 na Top 16 Miss Universe 2013, Whulandary Herman nke West Sumatra kpuwere Elvira okpueze. <ref name="Puteri Indonesia (3)"/><ref name="Puteri Indonesia (7)">{{Cite web|url=https://coconuts.co/jakarta/news/miss-indonesia-2014-says-scandalous-pics-kpk-chief-abraham-samad-not-real/|title=Miss Indonesia 2014 Says Scandalous Pics With KPK Chief Abraham Samad Not Real|publisher=[[Coconuts Media]]|accessdate=January 15, 2015}}</ref>Elvira na Elfin Pertiwi Rappa bụ Puteri Indonesia Lingkungan 2014 (Miss International Indonesia 2014) na Lily Estelita Liana bụ Puteri Indonesian Pariwisata 2014 (Mess Supranational Indonesia 2014). <ref name="Puteri Indonesia (4)"/><ref name="Puteri Indonesia (5)">{{Cite web|url=https://www.antaranews.com/berita/416604/elvira-devinamira-jadi-puteri-indonesia-2014|title=Elvira Devinamira jadi Puteri Indonesia 2014|publisher=[[Antara (news agency)]]|accessdate=January 29, 2014}}</ref><ref name="Puteri Indonesia (6)">{{Cite web|url=http://showbiz.liputan6.com/read/813575/elvira-devinamiri-puteri-indonesia-2014|title=Elvira Devinamira Wirayanti terpilih memenangkan gelar Puteri Indonesia 2014|publisher=[[Liputan 6]]|accessdate=January 30, 2014}}</ref>N'abalị ikpeazụ e chiri eze bụ nke Miss Universe 2013 na-achị, Gabriela Isler nke [[Venezuela]] dị ka kọmitii nhọpụta.<ref>{{Cite news|url=https://www.thejakartapost.com/news/2014/01/27/beauty-queen.html|title=Beauty queen; Miss Universe 2013, Gabriela Isler was happy to be back in Indonesia|publisher=[[The Jakarta Post]]|accessdate=January 27, 2014}}</ref><ref>{{Cite news|url=http://www1.jcc.co.id/index.php/news-archive.html?start=220|title=The Grand Final Putri Indonesia Pageant (PPI) 2014|publisher=[[Jakarta Convention Center]]|accessdate=January 29, 2014|archive-date=May 4, 2017|archive-url=https://web.archive.org/web/20170504231847/http://www.jcc.co.id/index.php/news-archive.html?start=220|url-status=dead}}</ref> == Ihe nkiri == [[Usòrò:Elvira_Devinamira_Keluarga_Besar.jpg|áká_ịkẹngạ|thumb|270x270px|Miss Universe Indonesia 2014, Elvira Devinamira Wirayanti na [[:id:Keluarga Besar|Keluarga Besar]], NET TV.<ref name="Keluarga Besar (1)">{{Cite web|url=https://republika.co.id/berita/omkytg280/emkeluarga-besarem-sitkom-tentang-mertua-menantu-dan-ipar-dalam-satu-atap|title=Keluarga Besar, Sitkom tentang Mertua, Menantu dan Ipar dalam Satu Atap|publisher=[[Republika (Indonesian newspaper)]]|date=March 10, 2017|language=id}}</ref><ref name="Keluarga Besar (2)">{{Cite web|url=https://wartakota.tribunnews.com/2019/07/13/ketika-kehadiran-dan-kecantikan-elvira-devinamira-menghebohkan-laki-laki-warga-kampung-lapak|title=Ketika Kehadiran dan Kecantikan Elvira Devinamira Menghebohkan Keluarga Besar|publisher=[[NET (Indonesian TV network)]]|date=July 13, 2019|language=id}}</ref>]] Mgbe ọ laghachiri Indonesia, otu afọ ka e mesịrị, Elvira natara onyinye igwu egwu na ihe nkiri nke Ram Soraya na John nke Rantau duziri nke akpọrọ "Single" na ''"[[:id:Dilarang Menyanyi di Kamar Mandi (film)|Dilarang Menyanyi di Kamar Mandi]]"''. <ref name="Acting"/><ref name="Single (1)"/><ref name="Single (2)"/><ref name="Single (3)"/><ref name="Dilarang Menyanyi di Kamar Mandi (1)">{{Cite web|url=https://seleb.tempo.co/read/1225584/elvira-devinamira-dikritik-lantaran-adegan-mandi-di-film-barunya|title=Elvira Devinamira Dikritik Lantaran Adegan Mandi di Film Barunya|publisher=[[Tempo (Indonesian magazine)]]|date=July 17, 2019|language=id}}</ref><ref name="Dilarang Menyanyi di Kamar Mandi (2)">{{Cite web|url=https://republika.co.id/berita/senggang/blitz/pu5a9o328/elvira-devinamira-tolak-adegan-vulgar-tanpa-busana|title=Elvira Devinamira Tolak Adegan Vulgar tanpa Busana|publisher=[[Republika (Indonesian newspaper)]]|date=July 5, 2019|language=id}}</ref><ref name="Dilarang Menyanyi di Kamar Mandi (3)">{{Cite web|url=https://wartakota.tribunnews.com/2019/07/13/ketika-kehadiran-dan-kecantikan-elvira-devinamira-menghebohkan-laki-laki-warga-kampung-lapak|title=Ketika Kehadiran dan Kecantikan Elvira Devinamira Menghebohkan Laki-laki Warga Kampung Lapak|publisher=[[Tribun Network]]|date=July 13, 2019|language=id}}</ref>Elvira na-akpa nganga n'onwe ya n'ihi na mgbe ọ dị obere, Elvira nwere ohere iso ọtụtụ ndị na-eme ihe nkiri na ndị na-ese ihe nkiri ama ama dịka Raditya Dika, Rina Hasyim, Pandji Pragiwaksono, Surya Saputra na Seno Gumira Ajidarma mee ihe. <ref name="Single (2)" /><ref name="Single (3)" />Kemgbe ahụ, Elvira apụtala na ọtụtụ ihe nkiri na ihe nkiri telivishọn na Indonesia.<ref name="Acting" /><ref name="Dilarang Menyanyi di Kamar Mandi (1)" /><ref name="Dilarang Menyanyi di Kamar Mandi (2)" /> <references group="" responsive="0"></references> == Ihe odide == {{DEFAULTSORT:Devinamira, Elvira}} [[Òtù:Mmadụ ndi di ndụ]] s5oyngbbc9j0uftz62q0oynxlxcx6a7 Joe G. N. Garcia 0 33496 736841 727873 2026-10-08T04:57:21Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736841 wikitext text/x-wiki {{databox}} [[Category:Articles with hCards]] <ref name="auto3">{{Cite web|url=https://tucson.com/news/local/education/college/triple-threat-ua-health-vp-to-earn-k-year/article_303e9a3e-cb28-5604-90f0-eec9dda203ee.html|title='Triple threat' UA health VP to earn $810K/year|first=Stephanie Innes Arizona Daily|author=Star|work=Arizona Daily Star}}</ref>'''Joe G. N. "Skip" Garcia''' (amụrụ n'afọ 1954) bụ onye sayensị nke akpa ume nke America, dọkịta na onye nkuzi. == Akụkọ ndụ na ọrụ == A mụrụ Garcia na 1954 na El Paso, Texas ma mechaa B.S. ya na Biology na Mahadum Dallas na 1976. Ọ natara M.D. ya na Mahadum Texas Southwestern Medical School na 1980. <ref name="auto3"/> Ọ gụsịrị ọzụzụ na ọzụzụ obibi na Internal Medicine na Mahadum nke Iowa Hospitals and Clinics (1980-1983) na ọzụzụ mkpakọrịta na Pulmonary and Critical Care Medicine na Albany Medical College (1983-1985). Garcia malitere ọrụ agụmakwụkwọ ya dị ka onye enyemaka Prọfesọ nke Ọgwụ na Mahadum Texas Health Center na Tyler (1985-1988) ebe o guzobere ụlọ ọrụ akpa ume. Ọ ghọrọ osote prọfesọ na Indiana University School of Medicine (1988-1998) ebe (na 1992) e nyere ya prọfesor zuru oke na Indiana University Academy of Medicine akụkọ ihe mere eme dị ka Dr. Calvin H. English Prọfesọ nke Ọgwụ. Maka ọrụ afọ ofufo ya na ọrụ obodo ya na ndị ọrụ ugbo Hispanic nke Indiana, Garcia natara onyinye Otis Bowen Community Service nke steeti Indiana (1994) na Physician Community Service Award (1994) site na Indiana State Medical Association.   <sup class="noprint Inline-Template Template-Fact" style="white-space:nowrap;">&#x5B;''[[wikipedia:Tinye edensibịa|<span title="This claim needs references to reliable sources. (July 2019)">citation needed</span>]]''&#x5D;</sup> N'afọ 1998, Garcia kwagara na Johns Hopkins University School of Medicine na-eje ozi dị ka Dr. David Marine Professor of Medicine, Environmental Health Sciences and Biomedical Engineering, na Director of Pulmonary and Critical Care Medicine (1998-2005) ma jee ozi dị ka Division Director (1998-2005). E nyere Garcia Levine Excellence in Mentoring Award n'afọ 2005. <ref>{{Cite web|url=http://www.hopkinsmedicine.org/medicine/research/levine_award_recipients.pdf|title=Levine Award Recipients|work=www.hopkinsmedicine.org|accessdate=2019-07-08|archivedate=2017-08-16|archiveurl=https://web.archive.org/web/20170816233807/http://www.hopkinsmedicine.org/medicine/research/levine_award_recipients.pdf}}</ref> Na Mee 2005 Garcia sonyeere Mahadum Chicago dị ka Lowell T. Coggeshall Prọfesọ nke Ọgwụ na Onye isi oche nke Ngalaba Ọgwụ. <ref>{{Cite web|author=|title=Joe G.N. Garcia appointed chairman of medicine at the University of Chicago|url=http://www.uchospitals.edu/news/2005/20050501-joe-garcia.html|quote=Joe G.N. "Skip" Garcia, MD--a leading authority on lung biology and disease; the genetics, prevention, and treatment of pulmonary edema; and the molecular biology of blood vessels--has been appointed the Lowell T. Coggeshall Professor and chairman of the department of medicine, the largest department at the University of Chicago, effective May 1, 2005. ...|publisher=[[University of Chicago]]|date=May 1, 2005|accessdate=2014-12-27}}</ref> N'oge ọ nọ n'ọkwa (2005 - 2009) Garcia duziri uto atụmatụ nke ngalaba kachasị ukwuu na Mahadum Chicago. N'okpuru idu ndú ya, ego nyocha karịrị $ 80 nde kwa afọ na ọkwa mba nke Ngalaba maka nyocha gọọmentị etiti na-arị elu site na # 25 ruo # 10 (2005 - 2009). Mgbe <ref>{{Cite web|url=https://today.uic.edu/health-system-making-progress|title=Health system 'making progress' &#124; UIC Today|work=today.uic.edu}}</ref> bụ onye isi oche, Garcia duziri ọtụtụ atụmatụ na-emeziwanye okike, agbụrụ na agbụrụ dị iche iche nke ngalaba na mmemme ọzụzụ mkpakọrịta obibi. Site na ilekwasị anya na mmepe nke ngalaba na ụzọ ọrụ dọkịta na sayensị, n'okpuru nduzi Garcia, ngalaba ahụike nwere mmụba 200% na ọnụ ọgụgụ nke onyinye ọrụ NIH (K-Series). Dabere <ref>{{Cite web|url=https://pritzker.uchicago.edu/resources/bowman-society|title=Bowman society|work=pritzker.uchicago.edu}}</ref> ihe ịga nke ọma nke atụmatụ ndị a, na 2006, e nyere Garcia onyinye Diversity Award site na Bowman Society na Association of Professors of Medicine. N'ịtụ anya ịmanye ọgwụ ziri ezi, Garcia guzobere ngalaba nke Genetic Medicine ma were Nancy Cox, PhD na onye isi ngalaba mbụ wee malite Translational Research Initiative na Ngalaba Ọgwụ (TRIDOM).<ref name="auto1">{{Cite web|url=https://cri.uchicago.edu/portfolio/tridom/|title=TRIDOM}}</ref>, [1] mgbalị nchịkọta ihe nlele buru ibu na-enyere ndị nchọpụta aka ijikọ ozi ahụike na ọnọdụ ọrịa na ihe nlele nke ihe ndị dị ndụ. [2] N'ọnwa Febụwarị afọ 2010, a kpọrọ ya osote onye isi oche maka nyocha na Earl M Bane Prọfesọ nke ọgwụ na Mahadum Illinois na Chicago na-elekọta ihe fọrọ nke nta ka ọ bụrụ nde $ 400 (nchọpụta biomedicinal 70%). Ọ malitere atụmatụ atụmatụ dị ukwuu nke mere ka e mepụta ụlọ ọrụ na ebe ọhụrụ ndị lekwasịrị anya na ọgwụ ziri ezi, ọdịiche ahụike na bioinformatics. <ref>{{Cite web|url=https://www.uillinois.edu/cms/One.aspx?portalId=1324&pageId=136938|title=Interim Vice Presidents Named - University of Illinois System|accessdate=June 7, 2017|archiveurl=https://web.archive.org/web/20170817034456/https://www.uillinois.edu/cms/One.aspx?portalId=1324&pageId=136938|archivedate=August 17, 2017}}</ref>'ọnwa Febụwarị afọ 2011, a kpọrọ Garcia onye isi oche mbụ nke Mahadum Illinois maka ihe gbasara ahụike. N'ịkọwa naanị Onye isi oche nke Mahadum Illinois, ọ na-elekọta ụlọ ọrụ $ 1.5 ijeri na ngụkọta ego na mmefu ego kwa afọ. <ref>{{Cite web|url=https://archive.news.uic.edu/uicnews-1992-2013/15965-university-debuts-new-identity-for-health-care-enterprise.html|title=University debuts new identity for health care enterprise|work=archive.news.uic.edu|accessdate=2023-11-04|archivedate=2019-07-08|archiveurl=https://web.archive.org/web/20190708223424/https://archive.news.uic.edu/uicnews-1992-2013/15965-university-debuts-new-identity-for-health-care-enterprise.html}}</ref><ref>{{Cite web|url=https://archive.news.uic.edu/uicnews-1992-2013/15409-garcia-outlines-strategies-for-universitys-health-care-enterprise.html|title=Garcia outlines strategies for university's health care enterprise|work=archive.news.uic.edu|accessdate=2023-11-04|archivedate=2023-04-07|archiveurl=https://web.archive.org/web/20230407223602/https://archive.news.uic.edu/uicnews-1992-2013/15409-garcia-outlines-strategies-for-universitys-health-care-enterprise.html}}</ref> mere nke ọma n'ịgbanwe aha zuru oke iji guzobe Ụlọ Ọgwụ Illinois na Usoro Sayensị Ahụike, na usoro jikọtara ọnụ nke gụnyere ụlọ ọgwụ Mahadum, ụlọ ọgwụ VA, ihe karịrị ụlọ ọgwụ nlekọta ndị ọrịa 60, ụlọ ọrụ ahụike 12 nke gọọmentị etiti, kọleji sayensị ahụike 7 na ogige mpaghara 4. <ref>{{Cite web|url=http://www.thegatenewspaper.com/2013/02/school-based-health-center-opens-in-brighton-park-photos/|title=School-Based Health Center Opens in Brighton Park|quote=Dr. Joseph Garcia, vice president of Health Affairs|accessdate=March 13, 2014|archivedate=March 14, 2014|archiveurl=https://web.archive.org/web/20140314090118/http://www.thegatenewspaper.com/2013/02/school-based-health-center-opens-in-brighton-park-photos/}}</ref><ref>{{Cite web|url=http://news.uic.edu/open-house-at-new-mile-square-englewood-clinic|title=Open House at New Mile Square Englewood Clinic|quote=Dr. Joe G.N. “Skip” Garcia, vice president for health affairs at the University of Illinois|accessdate=March 13, 2014}}</ref>'okpuru idu ndú ya, e meghere ụlọ ọgwụ nlekọta ahụike ọhụrụ na Englewood [1] na Brighton Park . [2] Ọ rụrụ ọrụ dị ka onye isi nchoputa maka Institute for Personalized Respiratory Medicine nke na-elekwasị anya na ọdịiche dị iche iche nke ahụike. <ref>{{Cite web|url=http://www.aqualungtherapeutics.com/company.html|title=The Company - About Us|date=|accessdate=2014-12-27|quote=Aqualung Therapeutics was founded in December 2010 by Dr. Joe G. N. Garcia ... to develop novel therapeutic agents discovered by his research laboratory team at the University of Illinois at Chicago (UIC) into clinical therapies for treating acute, subacute, and chronic inflammatory lung injury.|publisher=Aqualung Therapeutics|archivedate=2015-02-01|archiveurl=https://web.archive.org/web/20150201120321/http://aqualungtherapeutics.com/company.html}}</ref>'ọnwa Disemba afọ 2010, o guzobere Aqualung Therapeutics, nke e mere iji mepụta usoro ọgwụgwọ ọhụrụ maka ndị na-arịa ọrịa siri ike. N'afọ 2011, a họpụtara ya na Institute of Medicine nke National Academies. (A maara ugbu a dị ka National Academy for Medicine) <ref>{{Cite web|url=http://www.uic.edu/htbin/cgiwrap/bin/uicnews/articledetail.cgi?id=15779|title=Garcia named to Institute of Medicine|date=|accessdate=2014-12-27|quote=Joe G. N. “Skip” Garcia, university vice president for health affairs and UIC vice chancellor for research, was elected a member of the Institute of Medicine of the National Academies, considered one of the highest honors in health and medicine.|publisher=[[University of Illinois at Chicago]]}}</ref> <ref name="auto2">{{Cite web|url=https://uanews.arizona.edu/story/joe-g-n-skip-garcia-appointed-ua-senior-vice-president-for-health-sciences|title=Joe G. N. 'Skip' Garcia Appointed UA Senior Vice President for Health Sciences|first=Arizona Health Sciences|author=Center|work=UANews|date=June 27, 2013}}</ref>'afọ 2013, a nabatara Garcia na Mahadum Arizona dị ka Onye isi osote onye isi oche maka sayensị ahụike na Merlin K. DuVal Endowed Prọfesọ nke Ọgwụ. <ref name="auto2" /> duziri njikọta atụmatụ nke nyocha agụmakwụkwọ, ọrụ na ọrụ ahụike n'etiti kọleji, ụlọ ọrụ na njikọ ahụike nke UA. <ref>{{Cite web|url=https://uahs.arizona.edu/senior-vice-president-health-sciences/staff|title=Executive Team: Office of the Senior Vice President for Health Sciences|date=June 4, 2014|work=The University of Arizona Health Sciences|accessdate=November 4, 2023|archivedate=February 28, 2022|archiveurl=https://web.archive.org/web/20220228164456/https://uahs.arizona.edu/senior-vice-president-health-sciences/staff}}</ref><ref>{{Cite web|url=http://phoenixmed.arizona.edu/about/news/distinguished-cardiologist-and-scientist-dr-guy-reed-named-dean-ua-college-medicine|title=Distinguished Cardiologist and Scientist Dr. Guy Reed Named Dean of the UA College of Medicine – Phoenix|date=April 25, 2017|work=The University of Arizona College of Medicine - Phoenix}}</ref>'ime afọ 3.5, ọ rụrụ ọrụ dị ka onye isi oche, College of Medicine - Tucson (2014 - 2015) ma nata 3 UA Health Science Deans, <ref>{{Cite web|url=https://medicine.arizona.edu/alumni/alumni-slide/dr-charles-b-cairns-named-dean|title=Dr. Charles B. Cairns Named Dean &#124; College of Medicine - Tucson|work=medicine.arizona.edu|accessdate=2023-11-04|archivedate=2023-04-10|archiveurl=https://web.archive.org/web/20230410110825/https://medicine.arizona.edu/alumni/alumni-slide/dr-charles-b-cairns-named-dean}}</ref> <ref>{{Cite web|url=https://uahs.arizona.edu/news/dr-rick-g-schnellmann-appointed-dean-university-arizona-college-pharmacy|title=Dr. Rick G. Schnellmann Appointed Dean of the University of Arizona College of Pharmacy|date=July 20, 2016|work=The University of Arizona Health Sciences}}</ref> 10 isi oche oche ngalaba, 10 osote onye isi oche na ndị nduzi etiti na ndị nduji ngalaba 12 UA yana ọnụ ọgụgụ ndị isi sayensị na nyocha dị elu. <ref>{{Cite web|url=https://cancercenter.arizona.edu/news/ua-cancer-center-retains-status-176m-award|title=News|work=University of Arizona Cancer Center}}</ref><ref>{{Cite web|url=https://tucson.com/news/local/education/college/ua-cancer-center-names-kraft-new-director/article_448800ea-48e7-5f7d-8c3d-0923518ffc74.html|title=UA Cancer Center names Kraft new director|first=Stephanie|author=Innes|work=Arizona Daily Star|access-date=2023-11-04|archive-url=https://web.archive.org/web/20230410063703/https://tucson.com/news/local/education/college/ua-cancer-center-names-kraft-new-director/article_448800ea-48e7-5f7d-8c3d-0923518ffc74.html|archive-date=2023-04-10|url-status=dead}}</ref> kpọtara Andrew S. Kraft, M.D. ka ọ duzie UA NCI-designated Comprehensive Cancer Center [1] ma nwee ihe ịga nke ọma na-eduga n'ịgbanwe nkwado nke UA's NCI Comprehensive cancer Center (July 2016) [2] Garcia duziri re-branding nke Arizona Health Science Center ka ọ bụrụ Mahadum nke Arizona Health Sciences (UAHS) na njikọta nke ọrụ UAHS dị oke mkpa na mmelite na arụmọrụ. Atụmatụ agụmakwụkwọ gụnyere nguzobe nke <ref>{{Cite web|url=http://uahs.arizona.edu/news/new-vision-ahsc-outlined-dec-17-town-hall|title=New Vision for AHSC Outlined at Dec. 17 Town Hall &#124; the University of Arizona Health Sciences|accessdate=June 13, 2017|archiveurl=https://web.archive.org/web/20170723002732/http://uahs.arizona.edu/news/new-vision-ahsc-outlined-dec-17-town-hall|archivedate=July 23, 2017}}</ref> UAHS isiokwu center nke ịdị mma na ọdịiche ahụike, ahụike na nsonaazụ ahụike nke ndị mmadụ, ọgwụ ziri ezi na neuroscience. Okike nke ụlọ ọrụ ọhụrụ ndị <ref>{{Cite web|url=http://www.wildcat.arizona.edu/article/2016/07/ua-and-banner-receive-43-million-research-grant-from-nih|title=UA and Banner receive $43 million research grant from NIH|work=The Daily Wildcat}}</ref> dugara na mmụba nke ego NIH na onyinye nke $ 43.3 nde NIH precision medicine initiative cohort program award. Garcia malitere mgbalị iji mụbaa ọ<ref name="auto">{{Cite web|url=https://diversity.medicine.arizona.edu/news/dr-francisco-moreno-assumes-new-ahsc-leadership-role-advance-diversity-and-inclusion-health|title=Dr. Francisco Moreno Assumes New AHSC Leadership Role to Advance Diversity and Inclusion in Health Care &#124; Diversity and Inclusion in the College of Medicine|work=diversity.medicine.arizona.edu}}</ref> dị n'ime kọleji sayensị ahụike ise na-emepụta Office of Diversity and Inclusion, [1] na ịkwalite mmemme ndị dị ka PRIDE, BLAISER na FRONTERA nke na-elekwasị anya n'ịmepụta ndị ọrụ nlekọta ahụike dị iche iche. [2] Garcia bụ onye isi otu UA Health Science (UAHS) mkparịta ụka, na-enyere aka ime ka njikọta dị n'etiti Mahadum Arizona Health Network na Banner Health System nke dị na Phoenix. Nke <ref>{{Cite web|url=https://medicine.arizona.edu/alumni/alumni-slide/banner-update-relationship-will-make-us-better|title=Banner Update: 'This Relationship Will Make Us Better' &#124; College of Medicine - Tucson|work=medicine.arizona.edu|accessdate=2023-11-04|archivedate=2023-04-10|archiveurl=https://web.archive.org/web/20230410110848/https://medicine.arizona.edu/alumni/alumni-slide/banner-update-relationship-will-make-us-better}}</ref> gụnyere ịmepụta onyinye agụmakwụkwọ $ 300 nde iji mee ihe na UA iji kwado nyocha na nchụso agụmakwụkwọ ndị ọzọ, $ 150 nde iji kpochapụ ụgwọ UAHN na $ 500 nde na mmelite isi obodo karịa afọ ise. Na Jenụwarị 2017, Garcia gbanwere uche ya ka ọ gaa n'ihu na nyocha ọhụrụ ya na nke ntụgharị <ref>{{Cite web|url=https://tucson.com/news/dr-joe-g-n-skip-garcia-resigns-as-head-of/article_432738c2-bd81-11e6-b791-e718c15c1567.html|title=Dr. Joe G.N. "Skip" Garcia resigns as head of UA medical schools|first=Stephanie|author=Innes|work=Arizona Daily Star|access-date=2023-11-04|archive-url=https://web.archive.org/web/20230413070037/https://tucson.com/news/dr-joe-g-n-skip-garcia-resigns-as-head-of/article_432738c2-bd81-11e6-b791-e718c15c1567.html|archive-date=2023-04-13|url-status=dead}}</ref> na ije ozi dị ka onye guzobere na onye isi nke Aqualung Therapeutics na Restore Therapeuics, ụlọ ọrụ ndị lekwasịrị anya na ọnụ ọgụgụ dị elu nke ọnwụ na ọrịa ahụike. <ref>{{Cite web|title=Joe G.N. ‘Skip’ Garcia, M.D., Named to Key UF Health Leadership Position » The Herbert Wertheim UF Scripps Institute for Biomedical Innovation & Technology » Scripps Biomedical Research » University of Florida|url=https://scripps.ufl.edu/2022/11/08/joe-g-n-skip-garcia-m-d-named-to-key-uf-health-leadership-position/|accessdate=2023-03-27|language=en}}</ref> ọ na-erule Jenụwarị 5, 2023, a kpọrọ Garcia dịka osote onye isi oche maka nyocha na UF, ụlọ ọrụ ahụike agụmakwụkwọ na Mahadum Florida. == Ihe ndị dị mkpa ọ rụzuru == Garcia anọgidewo na-enweta ego site na NIH kemgbe 1988 (onye nchọpụta bụ isi nke ọtụtụ mmemme mmemme, R01s, wdg). O dere ma ọ bụ soro dee ihe karịrị akwụkwọ 500 ndị ọgbọ nyochara na ihe karịrị isi akwụkwọ 40. <ref>{{Cite web|url=http://www.nhlbi.nih.gov/meetings/nhlbac/roster.htm|title=National Heart, Lung, and Blood Advisory Council|publisher=Nhlbi.nih.gov|accessdate=October 20, 2011|archive-url=https://web.archive.org/web/20111021153850/http://www.nhlbi.nih.gov/meetings/nhlbac/roster.htm|archive-date=October 21, 2011|url-status=dead}}</ref> bụ onye isi oche gara aga nke Central Society for Clinical Research, onye so na bọọdụ ndị nduzi nke American Thoracic Society na onye otu ma ọ bụ onyeisi oche nke ọtụtụ NIH, kọmitii <ref>{{Cite web|url=http://www.nhlbi.nih.gov/about/factbook-07/chapter6.htm|quote=Joe G. N. Garcia, M.D. (2010) University of Chicago|title=Institute Public Advisory Committees|publisher=Nhlbi.nih.gov|accessdate=October 20, 2011|archive-url=https://web.archive.org/web/20111027165249/http://www.nhlbi.nih.gov/about/factbook-07/chapter6.htm|archive-date=October 27, 2011|url-status=dead}}</ref> na otu ọrụ <ref>{{Cite web|url=http://www.nhlbi.nih.gov/meetings/workshops/lung-transplant.htm|title=NHLBI Working Group Lung Allograft Transplantation|quote=Joe G. N. Garcia, M.D., Johns Hopkins University School of Medicine|publisher=[[NHLBI]]|accessdate=October 20, 2011|archive-url=https://web.archive.org/web/20111027115219/http://www.nhlbi.nih.gov/meetings/workshops/lung-transplant.htm|archive-date=October 27, 2011|url-status=dead}}</ref> gụnyere NHLBI Advisory Council . Ọ rụrụ ọrụ dị ka onye nchịkọta akụkọ ma ọ bụ onye nchịkọta akụkọ maka ọtụtụ akwụkwọ akụkọ. Dịka ọmụmaatụ, Microvascular Research,, Endothelium: Circulation Research, Physiologic Genomics, American Journal of Cellular and Molecular BiologyPulmonary Circulation. A họpụtala ya n'ọtụtụ òtù nsọpụrụ gụnyere American Clinical and Climatological Association (Vice President), American Society for Clinical Investigation, na Association of Academic Professors na National Academy of Medicine. == Nsọpụrụ == Ọ natala ihe karịrị 25 citations na onyinye. Ihe karịrị akwụkwọ 500 ndị ọgbọ nyochara, 40,000 citations, h-index nke 101 na i10-index nke 581.<ref>{{Cite web|url=https://scholar.google.com/citations?user=fzilbbEAAAAJ&hl=en|title=Joe G. N. Garcia, MD - Google Scholar Citations|work=scholar.google.com|accessdate=2023-11-04|archivedate=2023-04-10|archiveurl=https://web.archive.org/web/20230410162146/https://scholar.google.com/citations?user=fzilbbEAAAAJ&hl=en}}</ref> * 2016 Edward Livingston Trudeau Medal site na American Thoracic Society<ref>{{Cite web|url=https://garcialab.uahs.arizona.edu/dr-joe-g-n-skip-garcia-selected-ats-2016-trudeau-medal-recipient|title=Dr. Joe G. N. "Skip" Garcia Selected as ATS 2016 Trudeau Medal Recipient &#124; Garcia Lab|work=garcialab.uahs.arizona.edu|accessdate=2023-11-04|archivedate=2022-02-28|archiveurl=https://web.archive.org/web/20220228225606/https://garcialab.uahs.arizona.edu/dr-joe-g-n-skip-garcia-selected-ats-2016-trudeau-medal-recipient}}</ref> * 2015 Tucson Hispanic Center <ref>{{Cite web|url=https://garcialab.uahs.arizona.edu/dr-joe-gn-skip%E2%80%99-garcia-named-recipient-2015-la-estrella-award-tucson-hispanic-chamber-commerce|title=Dr. Joe G.N. 'Skip' Garcia Named Recipient of 2015 La Estrella Award From Tucson Hispanic Chamber of Commerce &#124; Garcia Lab|work=garcialab.uahs.arizona.edu|accessdate=2023-11-04|archivedate=2022-02-28|archiveurl=https://web.archive.org/web/20220228192403/https://garcialab.uahs.arizona.edu/dr-joe-gn-skip%E2%80%99-garcia-named-recipient-2015-la-estrella-award-tucson-hispanic-chamber-commerce}}</ref> Excellence La Estrella Award [1] * <ref>{{Cite web|url=https://garcialab.uahs.arizona.edu/dr-joe-g-n-skip-garcia-receives-ats-leadership-award|title=Dr. Joe G. N. "Skip" Garcia Receives ATS Leadership Award &#124; Garcia Lab|work=garcialab.uahs.arizona.edu|accessdate=July 8, 2019|archivedate=April 9, 2019|archiveurl=https://web.archive.org/web/20190409234324/https://garcialab.uahs.arizona.edu/dr-joe-g-n-skip-garcia-receives-ats-leadership-award}}</ref> American Thoracic Society Leadership Award for Pulmonary Circulation [1] * 2011 <ref>{{Cite web|url=http://www.iom.edu/Global/News%20Announcements/2011-New-Members.aspx|title=IOM Elects 65 New Members, Five Foreign Associates|date=October 17, 2011|accessdate=2014-12-27|quote=Joe G.N. Garcia, M.D., vice president for health affairs, vice chancellor for research, and Earl M. Bane Professor of Medicine, Pharmacology, and Bioengineering, University of Illinois, Chicago|publisher=[[Institute of Medicine]]|archiveurl=https://web.archive.org/web/20140811010011/http://iom.edu/Global/News%20Announcements/2011-New-Members.aspx|archivedate=August 11, 2014}}</ref> họpụtara ya na Institute of Medicine nke National Academies . [1] * 2009 Diversity Award site Association of Professors in Medicine maka ihe ọhụrụ na ịkwalite ọdịiche dị iche iche na ọgwụ agụmakwụkwọ [1] * 2004 <ref>{{Cite journal|volume=123|journal=Trans Am Clin Climatol Assoc|title=Secretary-Treasurer's Report: The One Hundred Twenty-fourth Meeting held at The Ritz-Carlton, Sarasota, FL, October 20 through October 23, 2011|year=2012|pages=lvi-lxii}}</ref> họpụtara ya na American Clinical and Climatological Association (Vice President) [1] * 2003 American Thoracic Society Distinguished Scientist Award. Ihe nrite a na-amata "onyinye Dr. Garcia nyere na nghọta nke endothelial biology na ọkwa bụ isi", "ụzọ njikọta iji sụgharịa nchọpụta ndị bụ isi na akpa ume na ụdị anụmanụ dum", na "ihe nlereanya maka ndị mmadụ na-achọ ịghọ ndị ọkà mmụta sayensị na-ahụ maka ahụike". * 2002 David M. Levine Excellence in Mentoring Award site na Mahadum Johns Hopkins. * 1999 <ref>{{Cite web|url=http://uacc.arizona.edu/profile/joe-garcia|title=Joe G N "Skip" Garcia, MD &#124; the University of Arizona Cancer Center|accessdate=June 14, 2017|archiveurl=https://web.archive.org/web/20160702200837/http://uacc.arizona.edu/profile/joe-garcia|archivedate=July 2, 2016}}</ref> họpụtara ya na Interurban Clinical Club [1] * 1996 <ref>{{Cite web|url=https://www.the-asci.org/controllers/asci/AsciProfileController.php?pid=160351|title=The American Society for Clinical Investigation}}</ref> họpụtara ya na American Society for Clinical Investigation (ASCI) [1] * 1990 Henry F. Christian Award for Meritorious Research site na American Federation of Medical Research. == Ihe odide == {{Reflist}} [[Òtù:Mmadụ ndi di ndụ]] [[Òtù:Pages with unreviewed translations]] 00em595g5f35qcen92m6dpfzpk95pod Funso Aiyejina 0 34016 736825 730020 2026-10-07T18:53:34Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736825 wikitext text/x-wiki {{Infobox person|name=Funso Aiyejina|image=|caption=|birth_date={{birth date|df=y|1949|01|01}}|birth_place=[[Ososo]], [[Colony and Protectorate of Nigeria]]|death_date={{death date and age|df=y|2024|07|01|1949|01|01}}|death_place=[[Trinidad and Tobago|Trinidad]]|alma_mater=[[Obafemi Awolowo University]], [[Ile-Ife]], Nigeria; <br /> [[Acadia University]], [[Wolfville]], <br /> [[Nova Scotia]], Canada; <br /> [[University of the West Indies]]|occupation=Poet, playwright, short-story writer, academic|years_active=1967–2024|awards=[[Association of Nigerian Authors]]' Poetry Prize, 1989;<br /> Best First Book (Africa), [[Commonwealth Writers' Prize]], 2000;<br />[[Bocas Henry Swanzy Award]], 2022}} '''Funso Aiyejina''' (1 Jenụwarị 1949 - 1 Julaị 2024) bụ onye Naijiria na-ede uri, onye na-ede akụkọ mkpirikpi, onye na'ede egwuregwu na agụmakwụkwọ. Ọ bụ Dean of Humanities and Education (ruo mgbe ọ lara ezumike nká na 2014) na Prọfesọ Emeritus na Mahadum nke West Indies. Nchịkọta akụkọ ifo ya dị mkpirikpi, The Legend of the Rockhills and Other Stories, meriri 2000 Commonwealth Writers' Prize, Best First Book (Africa). == Akụkọ ndụ == A mụrụ Funso Aiyejina na 1949 na Ososo, Edo State, Nigeria. Ọ bụghị onye Yoruba ka ọtụtụ ndị mmadụ na-eche. Ọ gụsịrị akwụkwọ na Mahadum Ife (nke bụzi Obafemi Awolowo University) dị na Nigeria, Mahadum Acadia, Wolfville, Nova Scotia, na Canada, na Mahadum West Indies (UWI), St Augustine, Trinidad.[1] Ọ kụziri ihe karịrị afọ iri na [[Mahadum nke Obafemi Awolowo|Mahadum Obafemi Awolowo]], <ref>{{Cite web|url=http://www.tsarbooks.com/TSARAuthors.htm|title=Tsar Publications.|accessdate=6 June 2011|archiveurl=https://web.archive.org/web/20110716120416/http://www.tsarbooks.com/TSARAuthors.htm|archivedate=16 July 2011}}</ref> na kemgbe 1990 na Mahadum nke West Indies na Trinidad & Tobago. Na UWI, Aiyejina malitere nzere MFA na edemede akụkọ ifo.<ref>{{Cite web|url=https://sta.uwi.edu/uwitoday/archive/december_2009/article9.asp|title=At Home in Exile|work=UWI Today|date=December 2009|accessdate=2 July 2024}}</ref><ref>{{Cite news|url=https://newsday.co.tt/2024/07/02/prof-emeritus-funso-aiyejina-has-died/|title=Prof Emeritus Funso Aiyejina has died|author=Yvonne Webb|work=Newsday|date=2 July 2024|archive-url=https://web.archive.org/web/20260123200756/https://newsday.co.tt/2024/07/02/prof-emeritus-funso-aiyejina-has-died/|archive-date=23 January 2026|access-date=21 May 2025|url-status=dead}}</ref><ref name="Webb 3July24">{{Cite news|url=https://newsday.co.tt/2024/07/03/tributes-flow-in-for-writer-scholar-funso-aiyejina/|title=Tributes flow in for writer, scholar Funso Aiyejina|author=Yvonne Webb|work=Newsday|date=3 July 2024|archive-url=https://web.archive.org/web/20260123205403/https://newsday.co.tt/2024/07/03/tributes-flow-in-for-writer-scholar-funso-aiyejina/|archive-date=23 January 2026|access-date=21 May 2025|url-status=dead}}</ref> N'afọ 1995-96, ọ bụ Fulbright Lecturer na Creative Writing na Mahadum Lincoln na Jefferson City, Missouri. Ọ bụ onye otu ntọala nke NGC Bocas Lit Fest, mgbe e mesịrị ọ rụrụ ọrụ dị ka osote onye nduzi mmemme ya. <ref>{{Cite web|url=https://globalvoices.org/2024/07/02/nigeria-born-writer-and-academic-funso-aiyejina-who-had-a-lasting-impact-on-caribbean-literature-has-died/#|title=Nigeria-born writer and academic Funso Aiyejina, who had a lasting impact on Caribbean literature, has died|author=Janine Mendes-Franco|work=Global Voices|date=2 July 2024|accessdate=3 July 2024}}</ref> N'afọ 2022, Aiyejina na Merle Hodge bụ ndị mmeri jikọrọ aka nke Bocas Henry Swanzy Award for Distinguished Service to Caribbean Letters . <ref>{{Cite web|url=https://www.peepaltreepress.com/blog/news-authors/merle-hodge-and-funso-aiyejina-win-2022-bocas-henry-swanzy-award|title=Merle Hodge and Funso Aiyejina win the 2022 Bocas Henry Swanzy Award|date=4 May 2022|publisher=Peepal Tree Press|accessdate=21 March 2024|archivedate=21 March 2024|archiveurl=https://web.archive.org/web/20240321233246/https://www.peepaltreepress.com/blog/news-authors/merle-hodge-and-funso-aiyejina-win-2022-bocas-henry-swanzy-award}}</ref><ref>{{Cite news|url=https://www.guardian.co.tt/news/uwi-congratulates-the-bocas-henry-swanzy-awardees-6.2.1478670.3107936b63|title=UWI congratulates the Bocas Henry Swanzy Awardees|work=Trinidad and Tobago Guardian|date=13 April 2022}}</ref> Aiyejina nwụrụ n'ụra ya na 1 Julaị 2024, mgbe ọ dị afọ 75. <ref name="PMNews">{{Cite web|url=https://pmnewsnigeria.com/2024/07/02/nigerian-writer-professor-emeritu-funso-aiyejina-dies-at-75/|title=Nigerian writer, Professor Emeritus Funso Aiyejina dies at 75|author=Nehru Odeh|work=PM News|date=2 July 2024}}</ref><ref>{{Cite web|url=https://guardian.ng/tribute-so-long-funso-aiyejina/|title=Tribute: So long, Funso Aiyejina|work=Guardian|date=6 July 2024|accessdate=7 July 2024}}</ref> Ememe ncheta iji kwanyere ndụ ya ùgwù na 10 Julaị, nke ndị ezinụlọ, ndị ọrụ ibe ya na ndị enyi bịara.<ref name="Newsday, memorial celebration">{{Cite news|date=11 July 2024|first=Enrique|author=Rupert|work=Newsday|title=Friends, family celebrate Funso Aiyejina|url=https://newsday.co.tt/2024/07/11/friends-family-celebrate-funso-aiyejina/|archive-url=https://web.archive.org/web/20260206070916/https://newsday.co.tt/2024/07/11/friends-family-celebrate-funso-aiyejina/|archive-date=6 February 2026|access-date=21 May 2025|url-status=dead}}<cite class="citation news cs1" data-ve-ignore="true" id="CITEREFRupert2024">Rupert, Enrique (11 July 2024). . ''Newsday''.</cite></ref> == Ndụ onwe onye == Aiyejina lụrụ Lynda Quamina-Aiyejina, onye ya na ya nwere ụmụ nwoke abụọ.<ref name="Newsday, memorial celebration"/> == Ọrụ edemede na nchịkọta akụkọ == E bipụtara uri na akụkọ mkpirikpi nke Aiyejina n'ọtụtụ akwụkwọ akụkọ mba ụwa na akwụkwọ akụkọ, gụnyere The Anchor Book of African Stories, Literature Without Borders, Kiss and Quarrel: Yoruba/English - Strategies for Mediation, The New African Poetry, na The Penguin Book of Modern African Poetary (1999), nke a kọwara ya dị ka "otu n'ime ndị kacha mma na-eme ihe ọchị na Naịjirịa". A gụrụ akụkọ ya na egwuregwu ya ma mee ya ihe nkiri na redio na Naịjirịa na England. O nwetara ihe nrite nturu ugo abụ nke Association of Nigerian Authors' Poetry Prize na 1989 maka akwụkwọ abụ mbụ ya, A Letter to Lynda and Other Poems (1988). Akwụkwọ akụkọ mbụ ya nke akụkọ ifo, The Legend of the Rockhills and Other Stories (1999), meriri Best First Book (Africa), Commonwealth Writers' Prize, 2000. N'ịtụle nchịkọta uri 2004 ya, I, The Supreme and Other Poems, Jennifer Rahim kwuru, sị: "All of Aiyejina's books to date is his concentrated mmasị na akụkọ ihe mere eme nke Nigeria, identev bụ Africa. Nkwekọrịta na-apụta na ndị mba ọzọ na-agbasawanye nke kọntinent ahụ, n'ikwu ya n'ụzọ ọzọ, na-egosipụta uri ojii na-egbuke egbuke .... Dị ka onye na-abụghị / onye na-ahụ maka ọdịdị ala na omenala Caribbean, ọ na-atụ ya n'anya site na ọrụ ebube nke ịdị ndụ na mgbanwe omenala Africa. "[1] Ọ bụ onye nkatọ n'ọtụtụ ebe na-ebipụta akwụkwọ na omenala ndị Africa na West India. Ọ bụ onye ama ama maka ọrụ ya na ederede Earl Lovelace, ebe ọ bụ onye nchịkọta akụkọ nke Ebe n'ụwa: Essays na Tributes in Honor of Earl Lovelace @ 70 (2008) na nke Earl Lovelace: Growing in the Dark (Selected Essays) (2003), yana onye edemede nke 2017 Love Pịa).[1] Ọ rụrụ ọrụ dị ka onye nchịkọta akụkọ maka UWI Press ruo ọtụtụ afọ.[2] Aiyejina bụkwa onye nchịkọta akụkọ nke Self-Portrait: Interviews with Ten West Indian Writers and Two Critics (2003) na onye nchịkọta akụkọ (ya na Paula Morgan) nke Caribbean Literature in a Global Context (2006). Egwuregwu ya bụ The Character Who Walked Out On His Author emeela na [[Trinidad and Tobago|Trinidad na Tobago]], [[Jamaikạ|Jamaica]] na Nigeria.<ref name="PMNews"/> == Ọrụ == === Abụ uri === * Akwụkwọ ozi nye Lynda na uri ndị ọzọ, Saros International Publishers, 1988 (Association of Nigerian Authors Prize, 1989); Lightning Source Inc, 2006,   * I, The Supreme and Other Poems, Kraft Books Limited, 2004,   * {{Cite book|chapterurl=https://books.google.com/books?id=AR8GAdAxIDUC&q=funso+aiyejina&pg=PT307|chapter=Let Us Remember|title=The Penguin Book of Modern African Poetry|editor=Gerald Moore|publisher=Penguin|year=2007|isbn=978-0-14-042472-0}} * ''Njehie nke Nkwupụta'', Peepal Tree Press Ltd, 2020   * The Legend of the Rockhills na akụkọ ndị ọzọ, TSAR, 1999,   === Egwuregwu === * Onye na-eme ihe nkiri nke na-aga n'ihu n'Onye dere ya, Kraft Books Limited, 2020, <nowiki>ISBN 978-918-604-4</nowiki> === Dị ka onye nchịkọta akụkọ === * A Place in the World: Essays and Tributes in Honour of Earl Lovelace, Lexicon Trinidad Ltd, 2008,   * Earl Lovelace: Na-eto n'ọchịchịrị (Selected Essays), Lexicon Trinidad Ltd, 2003,   * ''Self-Portrait: Ajụjụ ọnụ na ndị edemede iri nke West India na ndị nkatọ abụọ'', Mahadum nke West Indies, 2003,   * Thicker Than Water (New Writing from the Caribbean), Peekash Press, 2018,   * "Sport Matters - Echiche sitere na UWI Faculty of Sport, 2019-2020", University of the West Indies Press, 2021,   === Dị ka onye nchịkọta akụkọ === * (Na Judy Stone) Na-aga n'ụzọ ziri ezi: Caribbean Stories in Honour of John Cropper, Lexicon Trinidad Ltd, 2010,   * (Na Paula Morgan) Caribbean Literature in a Global Context, Lexicon Trinidad Ltd, 2006,   === Akụkọ ndụ === * ''Earl Lovelace'' (Caribbean Biography Series), University of the West Indies Press, 2017,   === Akwụkwọ edemede === "Esu Elegbara: A Source of an Alter/Native Theory of African Literature and Criticism", Centre for Black and African Arts and Civilization, 2010, {{ISBN|978-978-8406-43-3}} == Edensibia == {{Reflist|30em}} == Njikọ mpụga == * Funso Aiyejina, [http://sta.uwi.edu/newspics/2009/Esu%20Elegbara3.pdf "Esu Elegbara: Isi Iyi nke Alter/Native Theory of African Literature and Criticism"] * [https://web.archive.org/web/20231105172648/https://papabois.tripod.com/interface.html Interface: Anson Gonzalez Na mkparịta ụka ya na Funso Aiyejina, 1998.] * [http://my.opera.com/PoetryOutLoud/albums/showpic.dml?album=156100&picture=2286878 HK Baptist University International Writers Workshop - OutLoud Readings.] {{Authority control}}{{DEFAULTSORT:Aiyejina, Funso}} ckj7td4r2p7cg4qb6ioqeimfwrtmvgw Kenza Dahmani 0 39098 736851 735572 2026-10-08T08:04:23Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736851 wikitext text/x-wiki {{databox}} '''Kenza Dahmani Tifahi''' (amụrụ na 18 Nọvemba 1980) bụ onye Algeria na-agba ọsọ ogologo oge nke na-asọ mpi n'okporo ụzọ, n'okporo ụzọ na n'ihe omume gafee mba. Ọ bụ onye sonyere ugboro isii na IAAF World Cross Country Championship. N<nowiki>''</nowiki>egwuregwu Mediterenian ọ meriri ihe nrite ọla abụọ n'afọ 2009 tupu ọ nweta aha 10,000 mita na 2013. O nwetakwara ihe nrite na egwuregwu All-Africa, Plan Arab Games na asọmpi egwuregwu Arab. ==ọrụ== Oge mbụ Dahmani gara mba ụwa bịara site na IAAF World Cross Country Championship. Na-agba ọsọ dị ka onye na-eto eto, ọ bịara nke 58 na 1997, nke 55 na 1998, na nke 43 na 1999. <ref name="iaaf">[https://worldathletics.org/athletes/-/14272839 Kenza Dahmani] at [[World Athletics]] [[File:OOjs_UI_icon_edit-ltr-progressive.svg|link=https://www.wikidata.org/wiki/Q16205667#P1146|text-top|class=noprint|frameless|10x10px|Edit this at Wikidata]]</ref> Ozugbo o toro n'ọkwa ndị okenye, ọ naghị asọmpi na ọkwa dị elu ruo n'afọ 2007. N'afọ ahụ, ọ meriri n'asọmpi Algeria cross country ma bụrụ onye nke abụọ na asọmpi ọkara marathon nke mba ahụ. Ọrụ ọkara marathon <ref name="Tilas">[http://www.tilastopaja.org/db/atw.php?ID=50174&Season=2007&Odd=0 Kenza Dahmani]. Tilastopaja. Retrieved on 2013-07-02.</ref> dugara na nhọpụta mba ụwa mbụ ya: ọ bụ onye nke abụọ na Arab Athletics Championships, Onye nwetara ọla nchara na 2007 All-Africa Games, na Onye nwetara ọlaọcha na 2007 Pan Arab Games. <ref name=Tilas/> Ọ nọchitere anya Algeria na asọmpi mba ụwa nke IAAF nke afọ 2008, na asọmpi mba ụwa nke IAAF nke afọ 2009, na-etinye nke 59 na nke 32 n'otu n'otu.<ref name=iaaf/> O tinyere ihe kacha mma n'egwuregwu marathon site n'ịgba ọsọ nke awa 2:39:38 maka nke atọ na asọmpi ahụ Madrid Marathon.<ref>{{Deprecated archive|url=https://archive.today/20130704011447/http://www.european-athletics.org/youth-athletics-programme-news/496-general/6243-home-star-martz-wins-madrid-marathon-.html|title=Home star Martínez wins Madrid Marathon}}. European Athletics. Retrieved on 2013-07-02.</ref> 2009 Mediterranean Games nyere ya ihe nrite mpaghara karịa, ebe o meriri ọla nchara na asọmpi 10,000 mita na ọkara marathon. Ọ bụ onye mmeri Arab Half Marathon ma meriekwa na Marathon de Toulouse Métropole. Ọ gbara asọmpi ntakịrị n'etiti afọ 2010 na 2012, ihe kacha pụta ìhè n'asọmpi ya bụ nke anọ na asọmpi Arab Half Marathon.<ref name=Tilas/>. Oge 2013 hụrụ Dahmani iru ọkwa ọhụrụ. <ref>[http://www.aps.dz/Athletics-10-000-m-Kenza-Dahmani.html Athletics/10,000 m: Kenza Dahmani wins Algeria’s sixth gold medal ]. Algerian Press Service. Retrieved on 2013-07-02.</ref> weputara nke iri na asatọ na 2013 IAAF World Cross Country Championship ma merie 10,000 m title na Mediterranean Games na nkeji 32:42.47. &nbsp;<ref name="Tilas"/>n'ime ọkara marathon ọ bụ onye nke abụọ na Arab Championships mana o nweghị ike ịkwụsị na Mediterranean Games. Dahmani nwere ụmụ abụọ. Ọ kwụsịrị asọmpi na 2013–2015 wee laghachi na ọzụzụ na Ọktoba 2015.<ref name="nbc">[http://results.nbcolympics.com/athletes/athlete=dahmani-tifahi-kenza-1065487/index.html Kenza Dahmani Tifahi]. nbcolympics.com</ref> Ọ nọ n'ọkwa nke iri ise na 2016 Olympic marathon.<ref name="rio">[https://web.archive.org/web/20160826084314/https://www.rio2016.com/en/athlete/kenza-tifahi-dahmani Kenza Dahmani Tifahi] {{webarchive|url=https://web.archive.org/web/20160826084314/https://www.rio2016.com/en/athlete/kenza-tifahi-dahmani |date=26 August 2016 }}. rio2016.com</ref> == Edensibia == <div class="reflist"> <references group="" responsive="1"> <ref name="iaaf"/> <ref name="rio"/> <ref name="nbc"/> </references> </div> [[Òtù:Mmadụ ndi di ndụ]] 13iuma9wxx2kc5ut3m2uiqr4hffkrfi Iheoma Obibi 0 39683 736829 655811 2026-10-08T00:46:56Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736829 wikitext text/x-wiki {{Databox}}'''Iheoma Kennaya Obibi''' bụ onye ode akwụkwọ gbasara nwanyị Afrịka, onye na-akwado ụmụ nwanyị na onye na-akwado ikike mmadụ, na ọchụnta ego . Obibi hibere ụlọ ahịa mmekọrịta chiri anya n'ịntanetị nke mbụ na Nigeria, Intimate Pleasure. <ref>{{Cite web|title=Interview with Iheoma Obibi, founder of Nigeria's first online sex shop|url=https://www.msafropolitan.com/2013/12/interview-iheoma-obibi.html|accessdate=2020-09-25|work=MsAfropolitan|archivedate=2024-12-04|archiveurl=https://web.archive.org/web/20241204080740/https://msafropolitan.com/2013/12/interview-iheoma-obibi.html}}</ref> <ref>{{Cite web|date=2014-06-03|title=Fearless and Bold: Iheoma Obibi Opens Nigeria's First Online Adult Novelty Store|url=https://awpnetwork.com/2014/06/03/fearless-and-bold-iheoma-obibi-opens-nigerias-first-online-adult-novelty-store/|accessdate=2020-09-25|work=AWP Network|language=en|archivedate=2020-09-29|archiveurl=https://web.archive.org/web/20200929173841/https://awpnetwork.com/2014/06/03/fearless-and-bold-iheoma-obibi-opens-nigerias-first-online-adult-novelty-store/}}</ref> == Akụkọ ndụ == '''Iheoma Kennaya Obibi,''' mụrụ na St Mary's Hospital, Paddington, London na August 7, 1965, nye nne na nna Naijiria, George Chikezie Obibi na Love Celine Obibi. George bụ onye ndụmọdụ nlekọta si Umuoba, Uratta, [[Ọ̀hà Ímò|Imo State]], ebe nwunye ya si Okwu, Uratta, Imo State. N'afọ 2010, Obibi hibere ụlọ ahịa mmekọrịta chiri anya n'ịntanetị nke mbụ Nigeria. <ref>{{Cite web|title=Obibi by Alliance for Africa|url=https://alliancesforafrica.org/obibi/|date=|work=AFA|language=en-GB|accessdate=2020-07-07|archivedate=2025-02-17|archiveurl=https://web.archive.org/web/20250217225526/https://alliancesforafrica.org/obibi/}}</ref> <ref>{{Cite web|title=Many Nigerian Women In Sexual Bondage – Iheoma Obibi by She Maestro|url=https://theinterview.ng/2018/02/28/many-nigerian-women-in-sexual-bondage-iheoma-obibi|date=2018-02-28|work=TheInterview Nigeria|language=en-GB|accessdate=2020-07-07|archive-url=https://web.archive.org/web/20260417224018/https://theinterview.ng/2018/02/28/many-nigerian-women-in-sexual-bondage-iheoma-obibi/|archive-date=2026-04-17|url-status=dead}}</ref> <ref>{{Cite web|date=2016-12-10|title=Nigeria's bedroom revolution - satisfying women's demands by Bola Mosuro|url=https://www.bbc.com/news/world-africa-38262881|accessdate=2020-07-11|work=BBC News Africa|language=en-GB}}</ref> Ọ na-apụtakwa na ihe ngosi redio dị ka ''Madam Butterfly'' . <ref>{{Cite web|title=IHEOMA OBIBI – Her Passion For Flaming Intimate Desires Of The Heart|url=https://woman.ng/2015/06/the-leading-woman-iheoma-obibi-her-passion-for-flaming-intimate-desires-of-the-heart|date=2015-06-04|work=Woman ng|language=en-GB|accessdate=2020-07-11|archivedate=2017-07-15|archiveurl=https://web.archive.org/web/20170715213555/http://woman.ng/2015/06/the-leading-woman-iheoma-obibi-her-passion-for-flaming-intimate-desires-of-the-heart/}}</ref> Obibi gara ụlọ akwụkwọ sekọndrị Clissold Park na London, N16 . O mechara mụọ na Mahadum East London, wee nweta MA na Science Policy Studies na Mahadum City, London . Ọ gụrụ nkuzi na North East London Polytechnic n'etiti 1992 na 1993. Obibi bụ onye dere " ''Pastọ Saul Bottomsup'' " na onye nkwado maka " ''African Women Writing Resistance: Anthology of Contemporary Voices'' . <ref>{{Cite book|editor=Browdy de Hernandez|title=African women writing resistance : an anthology of contemporary voices|date=August 2010|publisher=University of Wisconsin Press|isbn=978-0-299-23664-9|url=https://uwpress.wisc.edu/books/4738.htm|accessdate=2020-07-12|language=English}}</ref> " <ref>{{Cite web|title=Brave Women: Iheoma Obibi is leading a bedroom revolution in Nigeria by|url=https://ynaija.com/brave-women-iheoma-obibi-leading-bedroom-revolution-nigeria/|date=2017-03-07|work=YNaija|language=en-GB|accessdate=2020-07-10}}</ref> == Ime ihe == Obibi anọwo na-arụsi ọrụ ike n'ihe gbasara nwoke na nwanyị na ihe ndị ruuru mmadụ kemgbe 1996, na-eje ozi dịka onye isi ụlọ ọrụ Alliances for Africa (AFA), otu òtù na-abụghị ndị gọọmenti na- edu ụmụ nwanyị na Africa nke dabeere na Nigeria. Ọ na-arụ ọrụ na [[Sierra Leone]], [[Kenya]], [[Liberia]], na [[Naijiria|Nigeria]] na ebumnobi nke ịtọhapụ ụmụ nwanyị Africa, ịzụlite ọchịchị ndị inyom na iwulite òtù ụmụ nwanyị . Ọ rụrụ ọrụ dị ka onye ndụmọdụ maka otu obodo na mba ụwa, gụnyere UN Women, British Council, OECD, DfID na Commonwealth Secretariat . </link><sup class="noprint Inline-Template Template-Fact" style="white-space:nowrap;">&#x5B; ''[[wikipedia:Tinye edensibịa|<span title="This claim needs references to reliable sources. (February 2023)">a chọrọ nkọwa</span>]]'' &#x5D;</sup> A họpụtara Obibi ka ọ bụrụ onye otu Ashoka n'afọ 2005 maka ọrụ ya "na-agbagha ụdị ndị nna ochie nke ndọrọ ndọrọ ọchịchị Naijiria site n'ịgba ume na ịkwado ụmụ nwanyị ịchọ ọkwa ọchịchị n'ọkwa ọchịchị niile na iweta ụmụ nwanyị n'ihu n'ihu ndị na-eme mkpebi". <ref>{{Cite web|title=Iheoma Obibi Ashoka Fellow 2005|url=https://www.ashoka.org/en-ng/fellow/iheoma-obibi|work=Ashoka|accessdate=2020-07-12}}</ref> N'oge [[Olusegun Obasanjo|Obasanjo]] na-achị, Obibi na nwa ya nwoke, Dilim Odinkalu, bụ ndị [[Nigeria Police Force|SSS Naijiria]] nwụchiri ugboro abụọ n'ihe gbasara ihe omume Alliance for Africa ha, yana ọrụ onye Obibi na-arụkọ ọrụ bụ [[Chidi Odinkalu|Chidi Anselm Odinkalu]] na Open Society Justice Initiative . A tọhapụrụ ha site na ntinye aka sitere na UK. <ref>{{Cite web|author=Odinkalu|first=Chidi|title=We Are Not Fugitives, Charles Taylor Is|url=https://www.justiceinitiative.org/voices/we-are-not-fugitives-charles-taylor|work=Open Society Justice Initiative|accessdate=2020-07-09|language=en-gb|date=2005-08-03}}</ref> == Nkwenye == N'afọ 2015, [[YNaija]] depụtara Obibi n'ime ụmụ nwanyị 100 kacha agba ume na Nigeria. <ref>{{Cite web|title=Abike Dabiri, Funke Opeke, Kemi Adetiba, Funmi Iyanda & more! These are Nigeria's 100 Most Inspiring Women – #YWomen100 by Isime Esene|url=https://ynaija.com/abike-dabiri-funke-opeke-kemi-adetiba-funmi-iyanda-more-these-are-nigerias-100-most-inspiring-women-ywomen100|date=2015-03-08|work=Woman ng|language=en-GB|accessdate=2020-07-10}}</ref> == Edensibia == . [[Òtù:Mmadụ ndi di ndụ]] qfrvvv5bjr2u57joho0ucbf60wfzsvs Iwu Njem Njem 1824 0 40445 736833 157873 2026-10-08T02:31:53Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736833 wikitext text/x-wiki The Vagrancy Act 1824 ( 5 Geo. 4. c. 83) bụ iwu nke nzuko omeiwu nke United Kingdom na-eme ka ọ bụrụ mkparị ịrahụ ụra ma ọ bụ eziokwu na England na Wales .  Enyere iwu ahụ na Georgian England iji luso ọnụ ọgụgụ na-elu nke ndị mmadụ na-amanye ibi n'okporo ụzọ ma n'ihi njedebe Agha Napoleon na mmebi iwu na eze nke iwu iwu ihe .  Ndị nkatọ nke iwu ndị agha ndị na onye na-ekpochapụ, William Wilberforce, bụ onye katọrọ Iwu ahụ maka ime ka ọ bụrụ ihe mgbanaka na-eme ka ọ bụrụ ihe mgbanaka na-eme ka ọ bụrụ ihe na-achọghị.  mma maka iko na-iche echiche echiche ihe mere onye ọ chiri nwere ike ịbụ ebe obibi == ndabere == <ref name="pave">{{Cite web|url=https://www.thepavement.org.uk/stories/1029|title=The history of the Vagrancy Act 1824|date=6 June 2010|work=www.thepavement.org.uk|access-date=4 April 2024|archive-url=https://web.archive.org/web/20230418190209/https://www.thepavement.org.uk/stories/1029|archive-date=18 April 2023|url-status=dead}}</ref> Emebere iwu a iji hụ na ọnụ ọgụgụ na-arrị elu nke ndị ogbenye obodo mepere emepe na-achọ ebe obibi na England na Wales.  Mgbe njedebe nke Agha Napoleon na 1815, Mgbanwe Ndị Ọrụ, Mmepụta Iwu Ọka, na nkeji Mkpuchi, a manyere ọtụtụ puku mmadụ n'ala.  Ndị nọ n'ụkọ gbadara n'ime obodo mepere emepe na-enwe mmetụta ọrụ <ref name="pave" />Obodo ndị dị n'England, anyị London, Birmingham na Liverpool juputara na ndị mmadụ na-ebi n'ụzọ siri ike n'okporo ụzọ ma ọ bụ n'ogige ndị ọrụ.  Ihe ngosi nke otu ndị a ọnụ ọgụgụ buru ibu nke ndị agha na ndị ọrụ ụgbọ mmiri bụ ndị a ịchụpụrụ mgbe Agha Waterloo nchebe na 1815. Mgbe Secretary na Agha, The Viscount Palmerston nyere iwu ka a oke mbelata size nke peacetime British Army na  Royal Navy, puku kwuru puku ndị ọrụ mbụ ụgbọala ọrụ ma ọ bụ ebe obibi.  [1] N'otu oge ahụ, nnukwu uche nke ndị na-akwaga akụ na mụrụ si Ireland na Scotland rutere England, na-eji na London, na-achọ ọrụ.  Ndị ụzọndọrọ nhọrọ nọ n'iche omebe iwu na-iche nwebere na ndị otu parish na-aghọ ndị na-adịghị arụ ọrụ n'ịchịkwa "ndị na-akwagharị" ndị a.  Ọzọkwa, iwu ngafe ochie nke nyere ndị njem na-eme njem n'efu ka ha si n'otu mpaghara were were na-adịkwaghị iguzo. == Mmejọ == Emezi iwu nke 1824 ọtụtụ oge, saịtị na Iwu Vagrancy 1838, bụ nke webatara ọtụtụ mmejọ iwu ọha ọhụrụ na-ekpuchi omume ndị e chere n'oge ahụ nwere ike ịhụta iwe.  Ọ nwere ndokwa maka ịgba akwụkwọ nke "Onye ọ lara kpachapụrụ anya ele anya, n'okporo ụzọ ámá ọ llaala. ... ma ọ bụ ebe nsogbu na eze, ihe ọkụ ọkụ nke arụ, Foto, ma ọ bụ ihe ngosi ndị ọzọ.  arụ arụ <ref>HC Deb 25 June 1991 c861.</ref> <ref>https://www.legislation.gov.uk/ukpga/Geo4/5/83/section/4</ref>ịchọ na Iwu nke 1824 በቀላሉ nanị na England na Wales, Nkebi nke 4 nke ahụ, bụ nke okwukwe ọgbaghara na ụgha, gbakwunyekwuru Scotland na Ireland site na ngalaba 15 nke Mgbochi Mpụ 1871. A kagburu nke ngalaba a (na England na  Wales naanị) site na Iwu Mberede Mpụ 1981 . Iwu Vagrancy 1898 ndekọ ma ọ bụ mbubata maka ọdịdị arụ.  N'ịbụ nke e bu n'obi mee ka ọ bụrụ ihe ụmụaka ịgba ịgbana, n'ịlụ, a na-eji iwu ahụ eme ihe iji kpee ụmụ nwoke ikpe nwoke nwera nwoke.<ref name="LaceyBrian">{{Cite book|author=Lacey|first=Brian|year=2008|title=Terrible Queer Creatures: Homosexuality in Irish History|publisher=Dublin: Wordwell|isbn=978-1905569236}}</ref> <ref>The Law Reform Commission (1985). ''Report on Vagrancy and Related Offences'' (Dublin: LRC (Ireland)) p. 6f.</ref>Iwu Ndozi Iwu Mpụ 1912, gbatịpụrụ iwu nke Iwu 1824 na Scotland na Ireland, yana ụlọ ụlọ akwụkwọ == Ọkwa dị ugbu a == Iwu Vagrancy izizi 1824 ka na-arụ ọrụ na England na Wales ruo mgbe emepụtara iwu akụkụ.  N'afọ 1982, iwu ọgwụ Civic (Scotland) kagburu Iwu ahụ dum na Scotland.  E mere ohere na 1981 [1] iji kagbuo Nkebi nke 4 (ya mere, dị ka a isi kwuo ya, kagbuo ihe na-adị ebe obibi) na England na Wales, mananing ahụ (Vgrancy Offenses (Repeal) Bill) mere  akụkụ ụfọdụ akwụkwọ mbụ === Eji oge a === N'afọ 1988, a gbara ihe dị ka mmadụ 573 ikpe na ikpe n'okpuru Iwu England na Wales, gbagoro ruo 1,396 site na 1989. [1] Na May 1990 , National Association of Probation Officers mere nsogbu nke ikpe n'okpuru Iwu.  .  The ahụ MB na e mesilala ikpe 1,250 n’Magiste 14 dị na Central London na 1988, bụ́ nke nọchiri anya dị ukwuu n’ọnụ ndị a gbara akwụkwọ n’okpuru Iwu ahụ, na London. <ref>{{Cite web|date=2021-05-20|title=Ministers under pressure to revoke law which makes it illegal to sleep rough|url=https://inews.co.uk/news/politics/ministers-under-pressure-to-revoke-law-which-makes-it-illegal-to-sleep-rough-as-10-people-a-week-prosecuted-1012306|accessdate=2021-06-15|work=inews.co.uk|language=en}}</ref>N'afọ 2014, ijidere ụmụ nwoke a atọ ma bo ya ebubo n'okpuru ngalaba 4 nke Iwu Vagrancy nke 1824 maka izu ohi nri nri na skips na bins n'iche nnukwu ụlọ Iceland na Kentish Town, North London .  A ga-ekpe Paul May, William James na Jason Chan ikpe mgbe ebubo na ha nara cheese, tomato na ikike ọnụ £33 n'azụ ụlọ ọrụ ahụ.  A Iceland gọnarị ọṅụ aka ọ lụso n'ịkpọtụrụ ndị uwe ojii, na gbụgba ọha, ọ nditọ ihe ቀለም na Crown Prosecution Service (CPS) chere na ọ bụ nsogbu na eze na-ahụso ikpe na-ahụ atọ ahụ.  [1] Ndị ikom atọ ahụ, ha niile akara adreesị a kapịrị ọnụ, ga-aga n'ilo ikpe na Highbury Magistrates' Court na 3 February 2014. ngosi, tupu ụbọchị ahụ, CPS elele ya nyere ikpe, ahụ na- malite  na ọ chere na o nye ihe oke ruru eru maka nsogbu na eze na-egosi ikpe.  [2] Na 2020, mmadụ 573 gbara akwụkwọ n'okpuru iwu ahụ N'April 2022, ndị uwe ojii, mpụ, ikpe ikpe na ụlọ ikpe 2022 ka etinyere wee nye Royal Assent.  O nwere ndokwa nke ga-akagbu Iwu Vagrancy 1824, mana onye nwe nke steeti ga-eme akwụkwọ ndokwa a.  Gọọmenti ihe ebu n'obi ibido usoro nbibi a ruo mgbe emechara iwu mkpa <ref>[https://www.gov.uk/government/publications/police-crime-sentencing-and-courts-bill-2021-factsheets/repeal-of-the-vagrancy-act-1824-police-crime-sentencing-and-courts-act-2022-factsheet Policy paper - Repeal of the Vagrancy Act 1824: Police, Crime, Sentencing and Courts Act 2022 factsheet]</ref> <ref>{{Cite web|url=https://www.gov.uk/government/consultations/review-of-the-vagrancy-act-consultation-on-effective-replacement/review-of-the-vagrancy-act-consultation-on-effective-replacement|title=Review of the Vagrancy Act: Consultation on effective replacement}}</ref> == Ntụaka == {{Reflist|2}} [[Òtù:Ịda ogbenye]] j9b0duc7esj4u0oiihjy0egbaiu0ql8 Eva Hamlin Miller 0 46037 736815 730011 2026-10-07T16:23:44Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736815 wikitext text/x-wiki Eva Katherine Hamlin Miller ( Prof. 1911 na Brooklyn, New York - 1991) bụ onye omenkà sitere na Greensboro, North Carolina .  O tolitere na New York City wee gbanwee na Pratt Institute na Brooklyn, New York ;  Mahadum Columbia, akwụkwọ Gụsịrị akwụkwọ nke Fine Art na Florence na Mahadum Ibadan dị na Nigeria tupuga North Carolina. <ref name=":0"/> Isi onye nkuzi nka na-amụ Bennett na 1937, wee nwee ogologo ọrụ dịka onye nkuzi n'amụma mahadum na ụlọ akwụkwọ obodo Greensboro<ref>{{Cite web|url=http://www.bennett.edu/news/congresswoman-alma-adams-at-bennett-for-opening-of-exhibit-featuring-works-of-eva-hamlin-miller/|title=Congresswoman Alma Adams at Bennett for opening of exhibit featuring works of Eva Hamlin Miller|author=Willis|first=Laurie D.|date=2018-04-04|work=Bennett College|language=en-US|accessdate=2019-03-01}}</ref> Tinyere onye bụbu nwa akwụkwọ na Greensboro Congresswoman, Alma Adams, Miller nyere aka African American Atelier na 1990. [1] Ọ ọrụ dị ka onye nyere ya ruo mgbe ọ nwụrụ na 1991.. == Ndụ mbido == <ref name=":5"/>Mkparịta ụka Miller na Brooklyn, New York ma mara ọkwa na New York City.  Ọ bụ ada Floyd na Katherine Hamlin.  Ọ gara ụlọ akwụkwọ Pratt ma akara akara ugo akara BFA ya na nka nka ebe ahụ, wee gaa n'ihu akwụkwọ MA ya na nzere nka na Mahadum Columbia == Ọkwa ọkachamara == <ref name=":3"/>Hamlin jere ozi dị ka osote prọfesọ nka na North Carolina A&T State University, ebe o hibere ma nwee Z Gallery.  [1] Na mgbakwunye, Miller duru ngalaba nka na Bennett College, Tuskegee Institute, na Winston-Salem State University .  [2] Ọ bụ prọfesọ na North Carolina A&T State University.  N'ebe ahụ ntọala ntọala HC Taylor Art Gallery.  [3] Ọ jere ozi afọ 8 dị ka onye ndụ nka maka ụlọ akwụkwọ ọha na Greensboro == Ndụ onwe onye == <ref name=":5">{{Cite web|title=EVA MILLER, FORMER CURATOR AT A&T, DIES|url=https://greensboro.com/eva-miller-former-curator-at-a-t-dies/article_9ba18486-4f85-59d8-9899-4197e44e5072.html|accessdate=2020-12-16|work=Greensboro News and Record|date=27 December 1991|language=en}}<cite class="citation web cs1" data-ve-ignore="true">[https://greensboro.com/eva-miller-former-curator-at-a-t-dies/article_9ba18486-4f85-59d8-9899-4197e44e5072.html "EVA MILLER, FORMER CURATOR AT A&T, DIES"]. ''Greensboro News and Record''. 27 December 1991<span class="reference-accessdate">. Retrieved <span class="nowrap">2020-12-16</span></span>.</cite></ref>Miller fim Dr. W. Lloyd T. Miller ma ụmụ nwoke abụọ, Floyd T. Miller na Tyrone Miller.  Miller ụmụ ụmụ anọ == Na-arụ ọrụ == Miller ekepụtala ọtụtụ ihe osise. Ọrụ nka ya nwere nka enyo nwere ntụpọ yana ihe osise ya nke isiokwu na okwu ndị Africa. Edepụtara n'okpuru ebe a bụ ndepụta ihe osise ya. A na-ahazi ya site n'afọ na mkpụrụedemede. ''Ihe mgbagwoju anya nke Madonna,'' 1964 <ref name=":3">{{Cite web|author=Barber|first=Lauren|date=2018-08-09|title=Aunt Jemima no more: Black artists emerge at the Delta Arts Center|url=https://triad-city-beat.com/aunt-jemima-no-more-black-artists-emerge-delta-arts-center/|accessdate=2020-08-19|work=The NC Triad's altweekly|language=en-US}}<cite class="citation web cs1" data-ve-ignore="true" id="CITEREFBarber2018">Barber, Lauren (2018-08-09). [https://triad-city-beat.com/aunt-jemima-no-more-black-artists-emerge-delta-arts-center/ "Aunt Jemima no more: Black artists emerge at the Delta Arts Center"]. ''The NC Triad's altweekly''<span class="reference-accessdate">. Retrieved <span class="nowrap">2020-08-19</span></span>.</cite></ref> ''Ụda n'ime'' ''Sight'' ''-'' ''A Rhapsody,'' 1964 <ref name=":4"/> ''Nkpuchi Luba,'' 1968 <ref name=":4"/> ''Oge ịpụ,'' 1975 <ref name=":4">{{Cite web|title=Eva Hamlin Miller {{!}} artnet|url=http://www.artnet.com/artists/eva-hamlin-miller/|accessdate=2020-08-19|work=www.artnet.com}}<cite class="citation web cs1" data-ve-ignore="true">[http://www.artnet.com/artists/eva-hamlin-miller/ "Eva Hamlin Miller | artnet"]. ''www.artnet.com''<span class="reference-accessdate">. Retrieved <span class="nowrap">2020-08-19</span></span>.</cite></ref> ''Abụ nke Mozambique #2,'' 1975 <ref name=":4"/> ''Nefertiti,'' 1991 <ref name=":3"/> ''Ntụnye akpụkpọ anụ II'' <ref>{{Cite web|author=Auctions|first=Leland Little|title=Eva Hamlin Miller (NC, 1911-1992), Skinny Dipping|url=https://www.lelandlittle.com/items/171223/eva-hamlin-miller-nc-1911-1992-skinny-dipping/|accessdate=2023-05-22|work=www.lelandlittle.com|language=en}}</ref> <ref name=":4"/> ... O mekwara windo ugogbe anya dị na Bennett College, Saint James Presbyterian Church, Saint Matthews Methodist Church, na Shaịlo Baptist Church. <ref name=":2"/> Miller nwere ọtụtụ ndị na-ese ihe na-ele ya anya.  John Rogers, onye bụ "onye na-ese ihe, onye na-ese ihe na onye na-ahụ ihe" [1] akwụkwọ n'ime ya, nke mere ka ya na ya rụkọọ ọrụ ọtụtụ oge.  Ọ bụghị nanị Rogers mụrụ ya dị ka onye onye, ​​ọtụtụ n'ime ụmụ akwụkwọ ya kwuru na ọ pịa ha ịbụ ndị na-ese ihe na ndị mmadụ ka mma. <ref name=":0">{{Cite web|url=https://www.greensboro.com/eva-hamlin-miller-leaves-behind-strong-imprint-by-creating-art/article_19f8df6e-a497-58fc-b8e2-657e5d6a40a7.html|title=EVA HAMLIN MILLER LEAVES BEHIND STRONG IMPRINT BY CREATING ART, TEACHING AND ESTABLISHING GALLERIES|author=ABE D. JONES JR|work=Greensboro News and Record|date=February 1994|language=en|accessdate=2019-03-01|archive-url=https://web.archive.org/web/20240529223703/https://greensboro.com/eva-hamlin-miller-leaves-behind-strong-imprint-by-creating-art/article_19f8df6e-a497-58fc-b8e2-657e5d6a40a7.html|archive-date=2024-05-29|url-status=dead}}<cite class="citation web cs1" data-ve-ignore="true" id="CITEREFABE_D._JONES_JR1994">ABE D. JONES JR (February 1994). . ''Greensboro News and Record''<span class="reference-accessdate">. Retrieved <span class="nowrap">2019-03-01</span></span>.</cite></ref> == Ọnwụ == Miller nwụrụ na Disemba 26, 1991, na New York City. E mere olili ozu ya na St. James Presbyterian Church ma e liri ya n'ili Maplewood. <ref name=":5"/> == Mmezu == Miller nwetara ọtụtụ ihe ọ rụzuru n'oge ndụ ya niile. N'akwụkwọ ''Greensboro North Carolina'', Otis Hairston na-ede, "otu n'ime ihe ndị dị mkpa nke ọrụ ya gụnyere òkù nke President na Oriakụ Carter na White House maka nkwenye ya dị ka onye isi na-ese ihe nke Africa-American." <ref name=":2">{{Cite book|author=Hairston|first=Otis L.|url=https://books.google.com/books?id=thln5h9G2t4C&q=%22Eva+Hamlin+Miller%22+-wikipedia&pg=PA15|title=Greensboro North Carolina|date=2003|publisher=Arcadia Publishing|isbn=978-0-7385-1525-0|language=en}}<cite class="citation book cs1" data-ve-ignore="true" id="CITEREFHairston2003">Hairston, Otis L. (2003). [https://books.google.com/books?id=thln5h9G2t4C&q=%22Eva+Hamlin+Miller%22+-wikipedia&pg=PA15 ''Greensboro North Carolina'']. Arcadia Publishing. [[ISBN]]&nbsp;[[Ọpụrụiche:Isi akwụkwọ/978-0-7385-1525-0|<bdi>978-0-7385-1525-0</bdi>]].</cite></ref> Ọ bụ onye nlekọta nke African American Atelier ruo mgbe ọ nwụrụ. <ref name=":1">{{Cite book|title=Women and politics : a quest for political equality in an age of economic inequality|author=Burrell|first=Barbara C.|authorlink=Barbara Burrell|year=2018|isbn=9781138856554|location=New York, NY|pages=174|oclc=994287501}}</ref> == Ntụaka == {{Reflist}} o0ivvam2hfq4s05nq2kx99ao5a02qsx Jamila Afghani 0 46468 736834 707481 2026-10-08T03:42:55Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736834 wikitext text/x-wiki [[File:Jamila Afghani 2020 in Cologne -3294.jpg|thumb|Jamila Afghani]]'''Jamila Afghani''' (Persian: amuru ya na 1976 na Kabul) o bu onwe na ekwuchitere umunwaanyi na akuziri ha Ihe n'obodo Afghanistan. O bu choputara na burukwa onye ndozi nke Noor Educational na Capacity Development Organization (NECDO). O bukwa ezigbo onye otu ndi umbrella organization, Afghan Women's Network(AWN). Na 2022, Jamila Afghani e nyere ya onyinye na Ihe seventh annual Aurora Prize Maka malite Humanity.<ref>{{Cite book|title=Peacemakers in action : profiles in religious peacebuilding|author=Dubensky|first=Joyce S.|publisher=Tanenbaum Center for Interreligious Understanding|year=2007|isbn=978-1-107-15296-0|location=New York|pages=250}}</ref> == Akụkọ ndụ == Dị ka nwatakịrị, Afghani nwere Ọrịa polio ma n'ihi nsogbu sitere na ọrịa ahụ, ọ ghaghị iji eriri na-aga ije.<ref name=":7">{{Cite web|url=http://n-peace.net/candidate/candidate-107|title=Jamila Afghani|accessdate=8 September 2015|work=N-Peace Awards|publisher=N-Peace Network|archivedate=5 September 2013|archiveurl=https://web.archive.org/web/20130905144618/http://n-peace.net/candidate/candidate-107}}</ref> Mgbe ọ dị afọ iri na anọ, a gbagburu ya n'isi n'oge Agha Soviet.<ref name=":7" /> Afghani gbapụrụ na Kabul n'afọ ndị 1990 n'oge Agha obodo Afghanistan, biri na Peshawar.<ref name=":4">{{Cite journal|url=http://search.ebscohost.com/login.aspx?direct=true&db=a9h&AN=17277778&site=ehost-live|title=Catalyst For Change: Jamila Afghani|author=Oates|first=Lauryn|date=2005|journal=Herizons|accessdate=8 September 2015|volume=18}}</ref> Afghani nwetara nzere bachelọ na masta na Mahadum nke Peshawar.<ref name=":5">{{Cite journal|url=https://kb.osu.edu/dspace/bitstream/handle/1811/30223/Afghan%20Women%20Leaders%20Speak%20conference%20website%2011-17-05.pdf?sequence=5|title=Afghan Women Leaders Speak|date=November 2005|accessdate=8 September 2015|author=Mills|first=Margaret|archive-url=https://web.archive.org/web/20160305011338/https://kb.osu.edu/dspace/bitstream/handle/1811/30223/Afghan%20Women%20Leaders%20Speak%20conference%20website%2011-17-05.pdf?sequence=5|archive-date=5 March 2016|url-status=dead}}</ref> Ọrụ mbụ Afghani bụ dị ka onye ọrụ mmekọrịta ọha na eze maka Ogige ndị gbara ọsọ ndụ Afghanistan na Pakistan.<ref name=":3">{{Cite web|url=https://tanenbaum.org/peacemakers-in-action-network/meet-the-peacemakers/jamila-afghani/|title=Jamila Afghani|accessdate=7 September 2015|work=Tanenbaum's Peacemakers in Action|archivedate=4 March 2016|archiveurl=https://web.archive.org/web/20160304083407/https://tanenbaum.org/peacemakers-in-action-network/meet-the-peacemakers/jamila-afghani/}}</ref> O nyekwara ụmụ nwanyị nọ n'ogige ahụ aka ịmara ihe site na klas agụmakwụkwọ kor'an.<ref name=":3" /> Afghani ekwuola na otu n'ime ihe mgbochi kachasị ukwuu maka ụmụ nwanyị inweta agụmakwụkwọ bụ enweghị ndị nkuzi nwanyị.<ref name=":6" /> N'afọ 2001, Afghani guzobere NECDO, na ebumnuche nke inyere ụmụ nwanyị na ụmụaka aka inweta ohere agụmakwụkwọ.<ref name=":5" /> NECDO na-akụzi Asụsụ ndị ogbi, ma nwee klas gbasara Ngwọta esemokwu na nsogbu nwoke na nwanyị.<ref name=":7" /> A maara NECDO maka ịmepụta ụzọ ọhụrụ iji rute ụmụ nwanyị na ụmụ agbọghọ. Dịka ọmụmaatụ, NECDO mepụtara ọbá akwụkwọ maka ụmụ agbọghọ, mana ha kpọtara ụmụ nwoke ka ha kpọta ụmụ agbọghọ ahụ ileta ọbá akwụkwọ ahụ, na-enye ụmụ nwoke ihe nrite maka ụmụ agbọghọ ise ọ bụla ha wetara.<ref name=":4" /> Nzukọ ya na-ejere ihe dị ka ụmụ nwanyị 50,000 ozi na mpaghara 22.<ref name=":8">{{Cite news|url=https://foreignpolicy.com/2015/06/03/how-to-promote-womens-rights-in-afghanistan-and-around-the-world/|title=How to Promote Women's Rights, in Afghanistan and Around the World|author=Weingarten|first=Elizabeth|date=3 June 2015|work=Foreign Policy|accessdate=8 September 2015}}</ref> Ọrụ Afghani na-agbagha echiche na-ezighi ezi na Islam na-akwado ime ihe ike megide ụmụ nwanyị.<ref name=":0">{{Cite web|url=https://www.refinery29.com/en-us/2015/06/88771/afghanistan-feminism-womens-rights-jamila-afghani|title=How One Amazing Afghan Woman Is Making Huge Strides for Equality|author=Clark|first=Meredith|date=11 June 2015|work=Refinery 29|accessdate=2020-01-06}}</ref> O kere nke mbụ"Nkuzi na-emetụta nwoke na nwanyị na Afghanistan maka Ndị Imam. " Ọ malitere ọrụ ahụ site n'ịchọta ndị Imam nwere mmasị ileba anya na ozi ya na ndị ọzọ kwadebere.<ref name=":1" /> Ndị Imam malitere ikwusa ihe ọhụrụ, nke na-ekpuchi ikike ụmụ nwanyị site n'echiche Alakụba, ozugbo.[2] N'afọ 2015, o nwere ihe dị ka ndị Imam 6,000 na-arụ ọrụ na mmemme ahụ.<ref name=":8" /> Na Kabul, mmemme ya "mepụtara usoro khutbas (ozizi Fraịdee) na iri abụọ n'ime ụlọ alakụba ndị nwere mmetụta n'obodo ahụ. Afghani achọpụtala site n'ọrụ ya na "ọnụ ụmụ nwanyị na-emechi mgbe ha na-enweghị ihe ziri ezi nke ndị Alakụba" n'ihi na ọdịbendị Afghanistan bụ nke okpukpe na nke na nke na-agbaso omenala. Ọzụzụ okike ya nwere mmetụta siri ike na ụmụ nwoke na-amaghị na Islam nyere ụmụ nwanyị ohere ime ka ụmụ nwoke bụrụ ndị na-akwado ụmụ nwanyị.<ref>{{Cite web|url=http://www.wisemuslimwomen.org/muslimwomen/bio/jamila_afghani/|title=Jamila Afghani|accessdate=8 September 2015|work=Women's Islamic Initiative in Spirituality and Equality|archivedate=28 September 2015|archiveurl=https://web.archive.org/web/20150928152017/http://www.wisemuslimwomen.org/muslimwomen/bio/jamila_afghani/}}</ref><ref name=":2" /><ref name=":8" /> "<ref>{{Cite news|url=http://www.cnn.com/2013/01/22/world/iyw-educating-girls-muslim-countries/|title=Altering Perceptions of Women in Muslim Countries|author=Khalid|first=Kiran|date=23 October 2013|work=CNN|accessdate=8 September 2015}}</ref> Ọ na-arụkwa ọrụ iji maa usoro ọchịchị agbụrụ aka na Afghanistan aka.<ref name=":0" /> O kwenyere na otu n'ime nsogbu ya na Afghanistan bụ na ụmụ amaala enweghị ike ịmata ọdịiche dị n'etiti "Islam, ọdịbendị na ndọrọ ndọrọ ọchịchị. " Ọ na-ekwu na ụfọdụ ndị Afghanistan na-emegide nkuzi ya na ịkwalite nkọwa udo nke Islam na-eyi ya egwu. <ref name=":6">{{Cite book|title=Contested Terrain: Reflections with Afghan Women Leaders|url=https://archive.org/details/contestedterrain0000kitc|author=Kitch|first=Sally L.|publisher=University of Illinois Press|year=2014|isbn=978-0252038709|pages=[https://archive.org/details/contestedterrain0000kitc/page/26 26]}}<cite class="citation book cs1" data-ve-ignore="true" id="CITEREFKitch2014">Kitch, Sally L. (2014). ''Contested Terrain: Reflections with Afghan Women Leaders''. University of Illinois Press. p.&nbsp;26. [[ISBN]]&nbsp;[[Ihe pụrụ iche:BookSources/978-0252038709|<bdi>978-0252038709</bdi>]].</cite></ref><ref name=":1">{{Cite news|url=http://womensenews.org/story/the-world/150612/in-afghanistan-danger-stalks-gender-imam-training|title=In Afghanistan, Danger Stalks Gender Imam Training|author=Nalli|first=Hajer|date=12 June 2015|work=Women's eNews|accessdate=7 September 2015}}<cite class="citation news cs1" data-ve-ignore="true" id="CITEREFNalli2015">Nalli, Hajer (12 June 2015). [http://womensenews.org/story/the-world/150612/in-afghanistan-danger-stalks-gender-imam-training "In Afghanistan, Danger Stalks Gender Imam Training"]. ''Women's eNews''<span class="reference-accessdate">. Retrieved <span class="nowrap">7 September</span> 2015</span>.</cite></ref> E nyere Afghani onyinye Tanenbaum Peacemaker in Action Award na 2008. <ref name=":2">{{Cite news|url=http://www.huffingtonpost.com/shahnaz-taplinchinoy/muslim-women-movers-and-s_b_4546673.html|title=Muslim Women: Movers and Shakers Fight for Women's Rights|author=Taplin-Chinoy|first=Shahnaz|date=5 January 2014|work=Huffington Post|accessdate=7 September 2015}}<cite class="citation news cs1" data-ve-ignore="true" id="CITEREFTaplin-Chinoy2014">Taplin-Chinoy, Shahnaz (5 January 2014). [http://www.huffingtonpost.com/shahnaz-taplinchinoy/muslim-women-movers-and-s_b_4546673.html "Muslim Women: Movers and Shakers Fight for Women's Rights"]. ''Huffington Post''<span class="reference-accessdate">. Retrieved <span class="nowrap">7 September</span> 2015</span>.</cite></ref> N'afọ 2017, ọ so na ndị ikpeazụ a họpụtara maka Aurora Prize for Awakening Humanity . <ref name="aurora">[https://auroraprize.com/en/aurora/detail/11242/2017-aurora-prize-finalists- Aurora Prize.] 2017 finalists.</ref> N'afọ 2021, a họpụtara Jamila Afghani maka Aurora Prize nke ugboro abụọ wee gaa n'ihu bụrụ 2022 Aurora Prize Laureate. == Edensibịa == [[Òtù:Mmadụ ndi di ndụ]] [[Otú:Ndị amụrụ n'afọ 1976]] s3envqbrt70rippyg7cvwdjm2q3gfgd John Dodgson Barrow 0 47486 736842 730078 2026-10-08T05:10:33Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736842 wikitext text/x-wiki John Dodgson Barrow (November 24, 1824 - Disemba 7, 1906), [1] bụ nke ama ama maka usoro ya na ụzọ ala ya, ka a na-ahụta dị ka nke ụgbọ nke abụọ nke Schoollọ akwụkwọ osisi Hudson .  Ihe ndị ọ na-achị na- ihe nkiri Central New York, mkpuchi gburugburu Skaneateles, New York, ebe o bi ma onye ọrụ ruo mgbe ọ kwagara New York City .  A na-etinye ụlọ ihe ngosi na- ike uru n'ahụ ya n'ime ụlọ akwụkwọ dị n'ime obodo Skaneateles. <ref name="westlakeconservators">{{Cite journal|author=Blakney|first=Susan S.|title=A Conservation Strategy For a Static Non-funded Collection: The John D. Barrow Art Gallery|url=https://westlakeconservators.com/wp-content/uploads/2017/03/A-Conservation-Strategy-for-a-Static-Non-Funded-Collection_The-John-D.-Barrow-Art-Gallery_Susan-Blakney.pdf|journal=The Abbey Newsletter|date=September 1988|volume=12|accessdate=25 November 2020}}</ref> [[Usòrò:Skaneateles_Library_and_John_D._Barrow_Art_Gallery.jpg|thumb| Ụlọ ihe ngosi nka nke John D. Barrow dị n'ọbá akwụkwọ Skaneatles.]] == Ndụ mmalite na agụmakwụkwọ == Akwụkwọ akụkọ Barrow na New York City na 24 November 1824 nye John Barrow III na Elizabeth Moode Tupu Barrow.  Eziniche ya nwanne nwanne Rebecca Haydock Barrow, mgba anọ - William, Charles Henry, Edmund Prior Barrow, George na na- George, Caroline Tyler Barrow.  [1] [2] Ọ bụ ya bụ ọkpara n'ime ihe iri ahụ.  [3] Ezin mmetụta ya kwagara Skaneateles na 1839. [4] Mgbe ọ dị afọ 15, ọ gara biri na ndị ikwu ya na North East England ma akwụkwọ nkuzi n'ihe ọrụ.  Mgbe ọ dị afọ 19, ọ la n'iche ya na Skaneateles, NY wee gaa n'ihu na-ese ihe.  [5] Barrow alụ di <ref name="estate">{{Cite news|title=Sisters Get the Estate of John Dodgson Barrow; Brother Not Named in Will|url=https://www.newspapers.com/clip/64056490/|accessdate=26 November 2020|work=The Post-Standard|date=12 January 1907|page=12}}</ref> == Ọrụ == Ma Ụlọ Akwụkwọ Hudson River nke ndị na-ese ihe na ndị na-ede uri New England na-enwe mmetụta nke Barrow mgbe ọ dị obere. <ref name="westlakeconservators" /> Mgbe ọ gụsịrị akwụkwọ na England, ọ laghachiri na Skaneateles na ha kwagara New York City ịmalite ọrụ ya. Barrow sonyeere American Art-Union na 1850 ma isi mbụ ya na National Academy of Design na 1852. Barrow mepere ụlọ ihe nkiri New York City na 1856, mgbe ọ dị afọ 32, na Greenwich Village, na nso nke Charles Loring Elliott [1  ] na ndị ọzọ na-ese ihe nkiri ụlọ akwụkwọ Hudson Valley.  [2] George Inness isi ya mgbe ọ bi na New York City. N'agbata 1852 na 1879, ndị na-ekiri ihe ngosi na Union League Club nke New York City, Pennsylvania Academy of the Fine Arts na Philadelphia, Boston Athens, na 19 Annual Exhibitions nke National Academy.  [1] obi, Barrow na-ese Abraham Lincoln n'ihu adreesị Cooper Union na New York City na February 1860 <ref name="auburnpub">{{Cite news|author=Monfiletto|first=Jonathan|title=Artist at work: John D. Barrow's portraits represent how Skaneateles painter made living|url=https://auburnpub.com/wocjournal/lifestyles/artist-at-work-john-d-barrows-portraits-represent-how-skaneateles-painter-made-living/article_1df65640-eb60-5e13-89b1-3db6da2cf670.html|accessdate=25 November 2020|work=Auburn Citizen|date=January 10, 2017|language=en|archive-url=https://web.archive.org/web/20240609161914/https://auburnpub.com/wocjournal/lifestyles/artist-at-work-john-d-barrows-portraits-represent-how-skaneateles-painter-made-living/article_1df65640-eb60-5e13-89b1-3db6da2cf670.html|archive-date=9 June 2024|url-status=dead}}</ref> <ref>{{Cite web|title=About the artist|url=https://barrowgallery.org/about/|work=Barrow Gallery|accessdate=25 November 2020}}</ref>   Ọ bụ ebe na ihe ka ukwuu n'ihe na-akpata ya sitere na foto ndị a na-ahụ anya, Barrow serekwa ebe dị iche iche na-ekpuchi ndụ ọrụ.  Ọtụtụ n'ime ihe ndị na-akpata ndị a lekwasịrị anya na ihe nkiri gburugburu ɔdɔ mmiri Skaneateles na gburugburu ebe Barrow bi n'oge mmetụta <ref name="inspiration">{{Cite news|author=Craig|first=Gwendolyn|title=Echoes of Barrow: Indianapolis artist finds inspiration in Skaneateles Lake|url=https://auburnpub.com/lifestyles/echoes-of-barrow-indianapolis-artist-finds-inspiration-in-skaneateles-lake/article_f0767930-b26a-5fa0-b2e5-3a35d23bc145.html|accessdate=26 November 2020|work=Auburn Citizen|date=September 19, 2017|language=en|archive-url=https://web.archive.org/web/20171125232019/http://auburnpub.com/lifestyles/echoes-of-barrow-indianapolis-artist-finds-inspiration-in-skaneateles-lake/article_f0767930-b26a-5fa0-b2e5-3a35d23bc145.html|archive-date=25 November 2017|url-status=dead}}</ref> <ref name="gallery-fundraiser">{{Cite news|author=Monfiletto|first=Jonathan|title=Art gallery looks toward annual fund drive|url=https://auburnpub.com/art-gallery-looks-toward-annual-fund-drive/article_1d33c313-4505-5623-b64c-4c66fe7cf052.html|accessdate=26 November 2020|work=Auburn Citizen|date=September 18, 2013|language=en|archive-url=https://web.archive.org/web/20190718053422/https://auburnpub.com/art-gallery-looks-toward-annual-fund-drive/article_1d33c313-4505-5623-b64c-4c66fe7cf052.html|archive-date=18 July 2019|url-status=dead}}</ref> <ref>{{Cite news|author=Monfiletto|first=Jonathan|title='Little piece of heaven': John D. Barrow's landscapes preserve Skaneateles of long ago|url=https://auburnpub.com/wocjournal/lifestyles/little-piece-of-heaven-john-d-barrows-landscapes-preserve-skaneateles-of-long-ago/article_94dd5556-8348-50cf-bbee-f811f590fa6e.html|accessdate=26 November 2020|work=Auburn Citizen|date=January 28, 2017|language=en}}</ref> <ref>{{Cite news|title=The Art Association: Sunset on Lake Ontario" painting|url=https://www.newspapers.com/clip/64055206/|accessdate=26 November 2020|work=The Brooklyn Daily Eagle|date=16 November 1868|pages=2}}</ref> <ref>{{Cite news|title=Landscapes: View on the Ammonoosuc River, N. H.|url=https://www.newspapers.com/clip/64055746/|accessdate=26 November 2020|work=The Brooklyn Daily Eagle|date=1 May 1876|pages=2}}</ref> Barrow sekwara ihe osise nke ụmụ amaala ama na mpaghara Skaneateles.  [1] O nyere ụfọdụ n'ime ihe ọrụ ya n'ọbá akwụkwọ ọha na eze Syracuse.  [2] [3] : 303 [4] Ọ haziri ihe izi ndị agha Skaneateles na ndị ọrụ ụgbọ mmiri (1895) na ebe ili ozu Lake View.  O mekwara ihe mgbakwunye n'ọbá akwụkwọ ọha nke obodo ahụ nke nwere ụlọ ihe osise ya. <ref name="westlakeconservators" /> Na 8 October 1900, Barrow nyere gallery ya n'ọbá akwụkwọ Skaneateles yana enyemaka ego maka iwu ụlọ. <ref name="westlakeconservators" /> <ref name="Onondaga past & present">{{Cite book|author=Beauchamp|first=William Martin|title=Past and Present of Syracuse and Onondaga County, New York: From Prehistoric Times to the Beginning of 1908|date=1908|publisher=S.J. Clarke Publishing Company|location=Onondaga County (N.Y.)|url=https://books.google.com/books?id=wcopAQAAMAAJ|accessdate=25 November 2020|language=en}}</ref> : 9 Taa, gallery nwere eserese 426, ọtụtụ n'ime okpokolo agba mbụ, nke ihe dị ka 300 na-egosipụta n'otu oge. <ref name="visit-gallery">{{Cite news|author=Long|first=Dorothy|title=Artist John D. Barrow wanted folks to enjoy his work|url=https://www.syracuse.com/news/2013/02/john_d_barrow_art_gallery_in_s.html|accessdate=25 November 2020|work=Syracuse Post-Standard|date=14 February 2013|language=en}}</ref> <ref name="gallery-fundraiser" /> === Ihe omume ndị ọzọ === Barrow lara ezumike nká n'oge wee wepụ na Skaneateles na 1877. [1] N'otu afã ahụ, a na-achọpụta na ngalaba nke Mahadum Syracuse dị ka onye prọfesọ nke ndị na-amụ nke nkà ihe nkiri.  [2] [3] O jere ozi afọ. <ref>{{Cite book|editor=Smalley|title=Alumni Record and General Catalogue of Syracuse University (1872-1910), including Genesee college (1852-1871) and Geneva medical college (1835-1872)|date=1911|publisher=Alumni Association of Syracuse University|location=Syracuse, N.Y.|url=https://books.google.com/books?id=RLINAQAAMAAJ|accessdate=25 November 2020|language=en}}</ref> Ọ rụkwara ọrụ dịka onye isi oche nke Skaneateles Savings Bank [1] : 423 na onye isi otu Onondaga Historical Association ruo mgbe ọ nwụrụ.  [1] : 542.  <ref>{{Cite news|title=Onondaga Historical Association to Name Directors|url=https://www.newspapers.com/clip/64055575/|accessdate=26 November 2020|work=The Post-Standard|date=9 January 1907|page=4}}</ref> Na Julaị 4, 1876, John D. Barrow kwuru okwu mkpa awụ na Skaneateles na-akọ njikọ obodo ahụ ruo mgbe ahụ.  [1] : 288 Na 1891, o mere ka e bipụta ya na Syracuse dị ka akwụkwọ nwere peeji 20 <ref>{{Cite web|author=Barrow, John D.|title=Centennial Address by John D. Barrow|url=https://cdm16694.contentdm.oclc.org/digital/collection/srr_skanlib/id/3|publisher=Masters & Stone Printers|accessdate=25 November 2020|date=July 4, 1876}}</ref>  Tupu ọrịa, o mkpokọta uri iri aụfụ Around Skaneateles Lake nke William Martin Beauchamp deziri.  [1] : 288 == Ọnwụ == Barrow nwụrụ na Skaneateles na Disemba 7, 1906 mgbe ọ dị afọ 83. <ref name="Obit">Obituary, ''The Democrat'', December 13, 1906.</ref> <ref name="Onondaga past & present" /> : 288 <ref>{{Cite news|title=Death Notice|url=https://www.newspapers.com/clip/64052517/|accessdate=26 November 2020|work=New-York Tribune|date=8 December 1906|pages=7}}</ref> Ọ hapụrụ ala ya nye ụmụnne ya ndị nwanyị abụọ. <ref name="estate" /> == Ntụaka == {{Reflist}} == Ọgụgụ ọzọ == *   == Njikọ mpụga == * [https://barrowgallery.org/about/ Ụlọ ihe ngosi nka nke John D. Barrow] * [http://www.askart.com/AskART/artists/biography.aspx?artist=86456 John Dodgson Barrow] sitere na AskArt. 2r5r1jfqrqc84sftojse3e86mqwalht John Willard Clawson 0 48136 736843 735661 2026-10-08T05:35:20Z InternetArchiveBot 11600 Rescuing 2 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736843 wikitext text/x-wiki   [[File:John Willard Clawson (1858-1936).jpg|thumb|John Willard Clawson]] John Willard “Will” Clawson (January 18, 1858 – isi 6, 1936) bụ onye omenkà dabere na America, Utah, na-achọ-19th na ịhụ afọ nke 20 <ref name="The University of Utah">{{Cite web|title=John W. Clawson|url=http://www.lib.utah.edu/collections/utah-artists/UAP-John-Clawson.php|publisher=The University of Utah|accessdate=5 February 2014}}</ref> == Akụkọ ndụ == A mụrụ Clawson nye Hiram B. Clawson na na-enye, onye bụbu Alice Young.  Alice bụ ada Brigham Young, na Clawson ụlọ n'ime ọnụ ụlọ na-acha na-agbara nke ndị Beehive, nke Brigham Young wuru maka ndị ozi ya na ebe ha. <ref name="Springfield Museum of Art"/> Clawson akwụkwọ akwụkwọ na Mahadum Deseret, n'ime ndị nkuzi ya a ma bụ George M. Ottinger .  [1] Ọ ngosi Mary Clark na LDS Church Endowment House obere oge tupu ọ gawa New York City ịgụ akwụkwọ na National Academy of Design .  [2] Ọ la mfe na Salt Lake City ebe ọ na-etinye aka na ike n'agbanyeghị na ọ masịrị ya ime ala.  Na 1891 Clawson gara Paris ebe ọ akwụkwọ akwụkwọ na Académie Julian wee bụrụ École des Beaux-Arts .  [1] Mgbe ọ nọ na ụlọ akwụkwọ mechara, ọ nwetara site n'aka Claude Monet na Édouard Manet .  [2] Ọ na-egosi na Vienne na-agụ akwụkwọ n'okpuru Julius Stewart .  Tupu ọ jụrụ na United States ọ gakwara mba Briten ebe o mere ihe onyonyo ọtụtụ ndị omeiwu. Ọ la dị iche na Utah na 1896 ebe o guzobe ụlọ studio wee jee ozi dị ka ụlọ mbụ nke Society of Utah Artists .  [1] ndekọ, o mechara kwaga San Francisco.  Ebibiri ụlọ ihe nkiri ya na ihe nka $ 80,000 na ala ọma jijiji 1906, mgbe nke ahụ ihuenyo, ọ kwagara Los Angeles omume ya.  [1] Site na 1909 ruo 1919 Clawson mere nka na New York City wee n'afọ ọzọ ọ la ọzọ Los Angeles.  Na Los Angeles Clawson na-esekarị ihe osise nke ihe nkiri na ihe nkiri ihe nkiri, nke na-achọkarị site na New York City. Na 1933 Clawson lara ezumike nká na Utah.  [1] O wee nwee ike ile isi anya na ụzọ odida, na ike nke ndị ndu ndị na-eso achụ-Ikpe a, ihe nkiri nke Joseph Smith, Jr. ọ Manuel ọrụ n’ụbọchị ọ ya. <ref name="Springfield Museum of Art">{{Cite web|title=Clawson, John Willard|url=http://www.springvilleartmuseum.org/collections/browse.html?x=artist&artist_id=593|publisher=Springfield Museum of Art|accessdate=5 February 2014|archiveurl=https://web.archive.org/web/20140222155719/http://www.springvilleartmuseum.org/collections/browse.html?x=artist&artist_id=593|archivedate=22 February 2014|url-status=dead}}<cite class="citation web cs1" data-ve-ignore="true">. Springfield Museum of Art. Archived from [https://web.archive.org/web/20140222155719/http://www.springvilleartmuseum.org/collections/browse.html?x=artist&artist_id=593 the original] on 22 February 2014<span class="reference-accessdate">. Retrieved <span class="nowrap">5 February</span> 2014</span>.</cite></ref> == Nchịkọta == Ngalaba nka nke Mahadum Brigham Young nwere nnukwu nchịkọta akụkọ ya, ihe ngosi 155. Ndị nwe ihe ngosi nka Utah nke Fine Arts na-ejidekwa ụfọdụ ọrụ ya. == Mbipụta == *   == Ntụaka == {{Reflist}} ; Akwụkwọ akụkọ *   *   *   ; Online * [https://web.archive.org/web/20110827194710/http://springvilleartmuseum.org/collections/browse.html?x=artist&artist_id=593 Clawson, John Willard (1858-1936)], ihe ngosi nka nke Springville * [http://www.lib.utah.edu/collections/utah-artists/UAP-John-Clawson.php John W. Clawson], Utah Artists Collection, J. Willard Marriott Library, Mahadum Utah * [http://www.askart.com/askart/c/john_willard_clawson/john_willard_clawson.aspx Bio of Clawson] na askart.com == Ọgụgụ ọzọ == *   == Njikọ mpụga == Media related to John W. Clawson at Wikimedia Commons{{Authority control}} hjhj1a4okkcelqm8vl6ang3xql0c2bh Aandhi 0 52752 736816 719607 2026-10-07T16:33:38Z IgboRefBot 66663 /* Ịse ihe nkiri */ 736816 wikitext text/x-wiki   Aandhi ( transl. 'Storm' ) bụ ihe nkiri ịnya ụzọ India na 1975 nke Sanjeev Kumar na Suchitra Sen na-eduzi, nke Gulzar duziri ya.  N'oge ahụ, a na-ebo ebubo na ihe nkiri nkiri ahụ na ndụ nke onye isi ala Indira Gandhi mgbe ahụ na-egosi ya na di ya dịpụrụ iche, ma n'eziokwu, ọ bụ naanị ohu ahụ n'aka onye ikike.  ụzọ Tarkeshwari Sinha na Indira Gandhi .  [1] Akụkọ ahụ gosiri na ihe ngosi nke na-egosi na-ahụta di na safọn mgbe ọtụtụ awụ ofufe, mgbe egosi Aarti Devi, ogbugbu a onye mgba ọkụ na-eduga na-anọ n'ahụ nkwari akụ nke di ya na  -agba n'oge egwu aka.  [2] A na-ahụ ihe nkiri a maka egwu nke Rahul Dev Burman dere, nke Gulzar dere ma bụrụ Kishore Kumar na Lata Mangeshkar. E kweghị ka ewepụtara ihe nkiri ahụ nke ọma Oriakụ Gandhi nọ n'agwa.  Akwụkwọ ihe nkiri ahụ iwu n'oge ihe mba nke 1975 ụnwa na ole ka ewepụtara ya.  Amachibidoro ihe nkiri a na ebubo ebubo, , akụkụ omume aka nke Model, na-ekwu na ọ nwere ike ibugharị aha ndị otu Congress.  Ya mere, Commission nke mbụ aka ike ịwepụta ihe nkiri ahụ.  Mma iwu a gbakwụnyere na njem nke Mberede mba.  bụrụ ihe iwu ahụ mere fim ahụ ihu mba.  [3] Mgbe e meri ya na mbụ aka mba 1977, ndị Janata Party na-achị achị esiri ya ma mee ka ọ asụsụ na ọwa mgbochi steeti.  [1] Ọ dị na ọ bụ ihe nkiri mkpa na ọrụ Sen, yana ihe nkiri Hindi ikpeazụ ya, ka ọ lara ezumike na fim kpamkpam na 1978. [3] Na 23rd Filmfare Awards, a chọpụtara ya maka Filmfare Award for Best  Actress ebe Sanjeev Kumar meri Filmfare Award for Best Actor .  Ihe nkiri ahụ n'onwe ya meri Filmfare Award for Best Film (Critics) . JK ( Sanjeev Kumar na-akpọ ) bụ onye njikwa ụlọ oriri na ọṅụṅụ.  Otu ụbọchị ọ na-eji obi obi ụtọ na-ahụ napụta nwa amụrụ onye ụgbọ USB na-ahụbiga ókè, Aarti ( Suchitra Sen ).  Aarti egwu JK n'anya ma ha abụọ na obere emume.  Mgbe afɔ ole na ole gachara, di na nke ahụ na-enwe ọtụtụ ọnwa n'ihi na ha ma ikewa.  Ọtụtụ afụ ka e ịhụ, JK na Aarti zutere ọzọ mgbe ọ bụ onye ụgbọ okporo ígwè guzosie ike.  N'agbanyeghị nkewa ahụ, ha abụọ na-eche na ha dị nso mana na-atụ egwu na aha ya nwere ike ike ozi aha ya na ọrụ ya nwere ike ikike, Aarti achọghị ịga n'ihu.  Ma n'ikpeazụ mgbe ndị ọzọ na-enwe nrịanrịa iji kwutọọ Aarti Devi na ịhụrị ya, ọ rutere ebe ahụ ma anụra ọha na eze na-amalite aka na ọ na-adị ya na ya ije obodo a ozi.  Ndị mmadụ kweere ya, okwu ya na àjà ya na-atọkwa ya ụtọ.  JK rutere ebe ahụ ma kwado ya, obi dị ya ụtọ nke ukwuu wee hapụ ebe ahụ, na-amalite na ọ ga-enye n'ike ma hapụ ike.  Ma JK kwuziri na ya na-enwe ka o nwee obi ụtọ ma nwee ihe ịga nke ọma n'ụdị ọ la ọ lịka.  Ọ na-alụ ọhụrụ aka wee merie ya.  N'ikpeazụ, JK nabatara dị n'etiti ya na Aarti ma tụba ya na helikopta nke na-ebuga ya na họtel ahụ. == Nkedo == === Mmepe === Gulzar kwuru na ihe nkiri ahụ akara ihe mmụta ya na ndụ onwe onye nke Prime Minister mgbe ahụ, Indira Gandhi .  Ọ mmetụta ime ihe nkiri onye ụkwụ ndị India nke oge a, ya mere ọ kpụrụ ike na ahụ na Indira Gandhi na ruo n'ókè ụfọdụ na onye omeiwu ama sitere na Bihar, Tarkeshwari Sinha. . <ref name="hin">{{Cite news|url=http://www.hinduonnet.com/2001/07/20/stories/09200221.htm|title=Where is reality?|author=V.Gangadhar|work=[[The Hindu]]|date=20 July 2001|accessdate=27 January 2012|archive-date=2 September 2010|archive-url=https://web.archive.org/web/20100902131655/http://www.hinduonnet.com/2001/07/20/stories/09200221.htm|url-status=dead}}</ref> === Ederede === Edemede mbụ nke ihe nkiri nkiri ahụ site n'aka onye na-ese ihe nkiri Sachin Bhowmick, mana ọ dabaraghị nke ọma na Gulzar.  O nwere echiche nke di na-egosi na-azụ na na-eso na-ezukọ n'otu ụlọ oriri na-eme mgbe ọtụtụ afụfụ, wee jiri nne ya.  Onye edemede Hindi bụ Kamleshwar sonyeere dị ka ndị ọrụ na-ede ihe, ka ihe nkiri ahụ egwu ịgba égbè.  O mechara dee akwụkwọ zuru oke, Kali Aandhi (Black Storm), nke dị nnọọ iche na ihe nkiri ahụ.  [1] N'ikpeazụ, e dere ihe nkiri ahụ n'otu oge yana ihe nkiri Gulzar ọzọ, Mausam (1975), nke Bhushan Banmali na Gulzar dekwara.  [2] [3] Tinyere Khushboo, Aandhi weputara n'otu afụ ahụ;  1975 na-egosi na ọ bụ ihe kacha pụta ìhè maka onye nduzi-screenwriter Gulzar. <ref name="hindu13">{{Cite web|title=Blast From The Past: Khushboo (1975)|url=http://www.thehindu.com/features/cinema/cinema-columns/khushboo-1975/article4810769.ece|work=The Hindu|date=13 June 2013|accessdate=14 June 2013|archivedate=22 September 2022|archiveurl=https://web.archive.org/web/20220922114727/https://www.thehindu.com/features/cinema/cinema-columns/khushboo-1975/article4810769.ece}}</ref> === Nkedo === Enyere onye ndu nke Aarti Devi onye na-eme ihe nkiri Vyjayanthimala, bụ onye akwụkwọ n'ihi na ọ mụrụ ya n'anya site na na-aja ya na Indira Gandhi.  Mgbe e ịhụ na 2011, ọ kọrọ Aandhi dị ka otu n'ime ihe nkiri ole na ole ọ kwara ụta na ọ naghị eme ma e wezụga Mr na Mrs 55 (1955) nke Guru Dutt na Bandini (1963) nke Bimal Roy dere,  "Enwere m ike na Indiraji (Gandhi) nke mere na oyi gwụ m. Ụkwụ mgbe ọrụ e nyere m." <ref>{{Cite news|url=http://www.tribuneindia.com/2011/20111127/spectrum/book5.htm|title=From Naagin to nritya|author=Nonika Singh|work=[[The Tribune (Chandigarh)|The Tribune]]|date=27 November 2011|accessdate=24 March 2012}}</ref> <ref>{{Cite news|url=http://www.indianexpress.com/news/down-memory-lane/874591/0|title=Down Memory Lane|work=[[The Indian Express]]|date=12 November 2011|accessdate=24 March 2012}}</ref> Na mmalite 1960s, onye nduzi Gulzar gakwuuru Suchitra Sen, ya na ihe nkiri maka ihe nkiri nke Sohanlal Kanwar ga-emepụta, agbanyeghị mgbe ọ tụrụ aro mgbanwe ụfọdụ nke Gulzar ekwenyeghị na ya, emebeghị ihe nkiri ahụ. Maka onye na-emepụta ihe nkiri ''Aandhi'' J. Om Prakash siri ọnwụ na Gulzar ka ọ gakwuru Sen ọzọ na onye na-eme ihe nkiri Sanjeev Kumar nwekwara mmasị na ya na Sen. N'oge a ka emechara edemede ọhụrụ ahụ, Gulzar gara izute ya na Kolkata, o kwetara n'enweghị nsogbu edemede ọ bụla., na-ebutere ''ọchịchị nkedo'' . N'ezie, Sen ugbu a kwere Gulzar nkwa na ọ gaghị atụ aro mgbanwe ọ bụla, na ọ rapaara na nkwa ya niile na fim ahụ. <ref name="hindu">{{Cite web|title=Mausam (1975)|url=http://www.thehindu.com/features/cinema/mausam-1975/article4766190.ece|work=The Hindu|date=30 May 2013|accessdate=13 June 2013|archivedate=14 June 2013|archiveurl=https://web.archive.org/web/20130614051336/http://www.thehindu.com/features/cinema/mausam-1975/article4766190.ece}}</ref> <ref name="toi121">{{Cite web|title='Sir' wouldn't lose her sleep over awards|url=http://timesofindia.indiatimes.com/entertainment/hindi/bollywood/news-interviews/Sir-wouldnt-lose-her-sleep-over-awards/articleshow/28981326.cms|date=18 January 2014|accessdate=2014-03-24|work=The Times of India|archivedate=25 January 2014|archiveurl=https://web.archive.org/web/20140125214314/http://timesofindia.indiatimes.com/entertainment/hindi/bollywood/news-interviews/Sir-wouldnt-lose-her-sleep-over-awards/articleshow/28981326.cms}}</ref> Maka ọrụ Aarti Devi di kewapụrụ onwe ya bụ Sanjeev Kumar, onye rụburu ọrụ na Gulzar's ''Koshish'' (1973), ọzọ dịka okenye. Kumar, otu n'ime ndị na-eme ihe nkiri kachasị mma nke ọgbọ ya, gara n'ihu na-arụkọ ọrụ na Gulzar n'ọtụtụ ihe nkiri, dị ka ''Mausam'' (1975), ''Angoor'' (1981) na ''Namkeen'' (1982). [11] === Ịse ihe nkiri === Dị ka ọtụtụ n'ime ihe nkiri Gulzar, gụnyere ''Mausam'' na ''Ijaazat'', akụkọ banyere Aandhi na-apụtakwa site na mgbanaka dị iche iche. [12] <ref name="RahejaKothari1996">{{Cite book|url=https://books.google.com/books?id=HixlAAAAMAAJ|title=The Hundred Luminaries of Hindi Cinema|publisher=India Book House Publishers|year=1996|isbn=978-81-7508-007-2|author=Dinesh Raheja|authorlink=Dinesh Raheja|accessdate=10 October 2016}}</ref> Ọ fọrọ nke nta ka a gbaa ihe nkiri ahụ na ''Mausam'', ebe Sanjeev Kumar na-egwu onye isi otu agadi nwoke na fim abụọ ahụ. Ọ bụ ezie na a tọhapụrụ Aandhi na mbụ, ọ gbabara n'esemokwu ndọrọ ndọrọ ọchịchị na akụkụ ya ga-emegharị ya, ebe ọ bụ na Mausam agwụla ma hapụ ya. <ref name="hindu"/> A na-agbapụ egwu nke ihe nkiri ahụ n'ebe dị iche iche na steeti Jammu na Kashmir, dị ka "Tum Aa Gaye Ho" gbara gburugburu ogige Pari Mahal na Srinagar, "Tere Bina Zindagi Se" nke kpochapụrụ na narị afọ nke 7-8 nke Martand Sun Temple., nso Anantnag, mgbe "Is Mod Se Jaate Hai" gbagburu na Pahalgam . <ref>{{Cite web|title=Movie > Aandhi Locations|publisher=Filmapia|url=http://www.filmapia.com/published/movies/a/aandhi|accessdate=2014-03-24|archivedate=24 March 2014|archiveurl=https://web.archive.org/web/20140324155526/http://www.filmapia.com/published/movies/a/aandhi}}</ref> <ref>{{Cite web|title=Chasing Aandhi: Kashmir sets the background|publisher=India Today|url=http://indiatoday.intoday.in/story/Chasing+Aandhi:+Kashmir+sets+the+background/1/95240.html|date=29 April 2010|accessdate=2014-03-24|archivedate=24 March 2014|archiveurl=https://web.archive.org/web/20140324172332/http://indiatoday.intoday.in/story/Chasing+Aandhi:+Kashmir+sets+the+background/1/95240.html}}</ref> Ọtụtụ n'ime egwu ndị ahụ nwere mkpọmkpọ ebe dị ka ihe ndabere, na-egosi nbiji. Ezinụlọ Gulzar, nwunye onye na-eme ihe nkiri Raakhee na nwa nwanyị Meghna Gulzar so ya na-agbapụ na Kashmir, agbanyeghị na nlọghachi Rakhe na Gulzar kewapụrụ. [16] == Gburugburu na mmetụta == N'ime ncheta ya, ada Meghna kwuru na nwunye Gulzar Rakhee gwara ya otu oge, "Agar aap shayar na hote, to bade hi common hote" (Ọ bụrụ na ị bụghị onye na-ede uri, ị gaara abụ onye nkịtị), ahịrị a bụ. Ntughari ma kwuo Aarti Devi na di ya na fim ahụ. [17] Ihe nkiri a na-eleba anya na ndụ nwanyị na-arụ ọrụ na ndọrọ ndọrọ ọchịchị, bụ nke ụmụ nwoke na-achị. Aarti na-eketa ihe nketa nke nna ndọrọ ndọrọ ọchịchị na-achọsi ike, ma na-emegide ọrụ ya dị ka nwunye na-arụsi ọrụ ike. N'oge na-adịghị anya ọ ga-eme nhọrọ iji dozie esemokwu ahụ, ma kewapụ onwe ya na di ya, na-enye ọrụ dịka nwa nwanyị ụzọ karịa ndụ onwe ya. Mgbe ha zutere ọzọ ka afọ itoolu nke nkewa gasịrị, àgwà na-achị achị nke e kere n'okpuru nduzi nke nna ya ejirila nwayọọ na amamihe bilie wee hụ ihe ọ tụfuru. N'agbanyeghị nke ahụ ọ chọtara onwe ya n'ọnọdụ nhọrọ ọzọ, ọ bụrụ na ọ hapụ ọrụ ndọrọ ndọrọ ọchịchị ya ma ọ bụ kwado maka ndụ alụmdi na nwunye. <ref name="Madangarli">{{Cite book|author=Bhawana Somaaya|authorlink=Bhawana Somaaya|title=Mother Maiden Mistress|date=17 April 2012|url=https://books.google.com/books?id=Dtec0Ykfo1sC&pg=PA1973-IA1|publisher=HarperCollins Publishers|isbn=978-93-5029-485-7|pages=1973}}</ref> <ref>{{Cite web|url=https://indianexpress.com/article/entertainment/bollywood/gulzar-aandhi-not-just-that-film-on-indira-gandhi-sanjeev-kumar-suchitra-sen-explore-relationships-8017379/|title=Gulzar's Aandhi is not just 'that film on Indira Gandhi', Sanjeev Kumar-Suchitra Sen explore how lack of ambition can ruin relationships|date=9 July 2022|accessdate=10 July 2022|archivedate=10 July 2022|archiveurl=https://web.archive.org/web/20220710005431/https://indianexpress.com/article/entertainment/bollywood/gulzar-aandhi-not-just-that-film-on-indira-gandhi-sanjeev-kumar-suchitra-sen-explore-relationships-8017379/}}</ref> Aandhi na-ewere isiokwu nwanyị, nke ewegoro na Ray's ''Mahanagar'' tupu, n'ihi na ọ na-ajụ ọnụ ahịa ụmụ nwanyị ga-akwụkarị maka ebumnuche ndọrọ ndọrọ ọchịchị ma ọ bụ ebumnuche ọrụ maka okwu ahụ, mgbe onye njikwa ụlọ oriri na ọṅụṅụ na-enweghị mmasị jụrụ ịkwado. <ref>{{Cite book|title=Sûrya India|url=https://books.google.com/books?id=7Vo8AAAAMAAJ|year=1989|publisher=A. Anand.}}</ref> == Ụda ụda == <ref name="Vittal2012">{{Cite book|author=Anirudha Bhattacharjee Balaji Vittal|title=R. D. Burman: The Man, The Music|url=https://books.google.com/books?id=tg49WV0j0IAC&pg=PT87|date=2012|publisher=HarperCollins Publishers|isbn=978-93-5029-236-5|pages=85–87}}</ref> Ndị otu RD-Gulzar izi maka ihe nkiri ahụ, abụ ndị a ma na abụ ndị ama nke awụ iri.  [1] Abụ dị ka "Tere Bina Zindagi", "Tum Aa Gaye Ho" na "Is Mod Se Jate Hain" ka a na-ewere dị ka oge ochie na sinima India.  Ede egwu "Tere Bina Zindagi Se" na "Is Mod Se Jate Hain" 5th na 14th n'otu n'otu na ndepụta Binaca Geetmala kwa afọ 1975 .  Dị ka ndepụta Planet Bollywood si dị, "Tere Bina Zindagi Se" nọmba 2 n'ime egwu 10 Bollywood mgbasa elu nke 1970s.. <ref name="Morcom2007">{{Cite book|author=Anna Morcom|title=Hindi Film Songs and the Cinema|url=https://books.google.com/books?id=kfVdxiSm-aYC&pg=PA253|date=2007|publisher=Ashgate Publishing|isbn=978-0-7546-5198-7}}</ref> == Hapụ, machibido ma wepụtaghachi == Ihe nkiri ahụ ahụ na February 1975 n'etiti ụdị, dị ka asịrị na-ahụ na ọ na-egosi na ndụ Prime Minister Indira Gandhi .  Ụfọdụ akwụkwọ mmado ihe nkiri gosikwara myirịta ahụ, nke nwere nke ahụ nwere ndị dị ka, "Lee Prime Minister gị na ihuenyo" na "Ụka nke ihe onye ndu ndú ndị na India mgbe akwụkwọ onwe nwechara", bụ nke nwoke na magazin ihe nkiri  .  N'ikpeazụ, e nyere ihe nkiri ahụ n'ihu mgbe ndị ọrụ abụọ hụchara ya na ozi mgbasa ozi mgbasa ozi mgbasa ozi, IK Gujral .  Mgbe ahapụchara ya, a ọpụpụ myirịta na uwe na iwu nke onye ndu Aarti Devi, nke Suchitra Sen na Oriakụ Gandhi na-ahụ egwu, sere sarees na ogologo ntutu isi.  N'oge ọchịchị aka ndị omebe iwu nke June na Gujarat, ụfọdụ ndị agha ndị na-egosi ihe nkiri nke ihe nkiri ahụ, na-egosi Aarti Devi ise siga na m Mugabe.  Ka ihe nkiri ahụ na-aga n'ihu, ụfọdụ ndị na-eme ihe ngosi na-achọsi ike agha iji ahịrị, "Lee Indira Gandhi na Aandhi" kwalite ihe nkiri ahụ, ugbu a ihe nkiri na-ese okwu n'ihu.  nsogbu, n'agbanyeghị na ọ bụ naanị ndị nwere ike so na-akwa emo.  Emechara machibido ihe nkiri a ka izu iri abụọ na isii gachara ka ewepụtara ya.  [1] [2] [3] Na June State nke Mberede e elele na India site Oriakụ Gandhi na 12 July n'agbanyeghị mgbasa ozi censorship, The Statesman jisiri na-ebu isiokwu na ya n'ihu page, "Screening on Aandhi  akwụkwọ".  [4] Gulzar bụ onye weghaara ihe nkiri ahụ na Moscow International Film Festival polio igbochi iwu tupu ikiri ya.  A gwakwara ya na a ga- akwụkwọ akwụkwọ mmado mgbasa ozi ihe nkiri ma zighachi ya akara. [28] [29] N'ikpeazụ, mgbe a na-eme Mausam na Disemba 1975, a na-akpa nke Aandhi.  [30] Ọ ndị na-ezo na-ese okwu na iji gosi na ọ bụghị biopic, ihe nkiri na Aarti Devi na-ele anya na ihe nke Indira Gandhi na-agwa nna ya na ọ na-ejere India ozi dị ka Oriakụ Gandhi, "  Woh meri ideal thi" ( She is my ideal) itinye ya.  [1] [2] [32] Mgbe Indira Gandhi merisịrị aka mmalite izugbe nke 1977 na Janata Party bịarutere n'ahụ, ewepụtara ya ụzọ ma gosikwa ya na ebe nke steeti steeti.  [3] [2] Ihe nkiri ahụ gara n'ihu bụ nnukwu ihe egwu na ọrụ Sen's Bollywood, nke Aandhi bụ ihe nkiri ikpeazụ, n'agbanyeghị na ọ mere ihe nkiri Bengali abụọ tupu ọ lara ezumike nka na 1978. [33] == Nnabata dị mkpa == Ụfọdụ ndị nkatọ, asị Subhash KJha serela myirịta dị n'etiti Indira Gandhi na nna ya Jawaharlal Nehru dị ka egosiri na fim ahụ na-ezo aka na ndụ onwe ha.  Ọzọkwa ọrụ nke Sanjeev Kumar, nwere shades nke Oriakụ Gandhi di.  [1] [2] N'ime ndị ahụ niile, Gulzar gọnara njikọ ọ lara na Indira Gandhi, ọ bụ naanị mgbe ọ akara aka mba na 1977 na Janata Party wee họrọ, ọ onye, ​​sị, "Ee, e jiri  Indira Gandhi n'uche mee ihe nkiri ahụ".  Sanjeev Kumar n'olu kwuru na ọ bụ nnwere nke ọrụ ya na-egosi na Feroze Gandhi . == Ntụaka == {{Reflist}} == Akwụkwọ akụkọ == [[Òtù:Ụmụ nwanyị]] [[Òtù:Pages with unreviewed translations]] odjepkkp1uo0r2l617wrz8bug0p4plt Karen Darbasie 0 53425 736848 580777 2026-10-08T07:27:13Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736848 wikitext text/x-wiki {{Databox}}'''Karen Darbasie''' bụ onye ọrụ ụlọ akụ na nwanyị ọchụnta ego si [[Trinidad and Tobago|Trinidad na Tobago]] . Ọ bụ otu onye isi oche nke First Citizens Bank <ref name=":0">{{Cite web|title=First Citizens Group Holdings Ltd.|url=https://www.wsj.com/market-data/quotes/TT/XTRN/FCGFH/company-people/executive-profile/133784021|accessdate=2022-01-25|work=The Wall Street Journal (WSJ)|language=en}}<cite class="citation web cs1" data-ve-ignore="true">[https://www.wsj.com/market-data/quotes/TT/XTRN/FCGFH/company-people/executive-profile/133784021 "First Citizens Group Holdings Ltd"]. ''The Wall Street Journal (WSJ)''<span class="reference-accessdate">. Retrieved <span class="nowrap">2022-01-25</span></span>.</cite></ref> <ref>{{Cite web|title=FCB: Very good gain from Barita investment|url=https://trinidadexpress.com/business/local/fcb-very-good-gain-from-barita-investment/article_0cf34b4a-da02-11eb-8b3f-773a3d70c231.html|accessdate=2022-01-25|work=Trinidad Express|language=en}}</ref> na onye isi oche oche mbụ na American Chamber of Commerce of Trinidad na Tobago. <ref>{{Cite web|title=Karen Darbasie|url=https://energynow.tt/karen-darbasie|accessdate=2022-04-26|work=Energy Chamber of Trinidad and Tobago|language=en-GB}}</ref> Ọ bụbu onye isi oche nke Bankers Association of Trinidad and Tobago <ref>{{Cite web|title=Downie appointed Bankers Association president|url=https://newsday.co.tt/2021/09/10/downie-appointed-bankers-association-president/|accessdate=2022-01-25|work=Trinidad and Tobago Newsday|language=en}}</ref> na Onye isi oche nke Trinidad Nitrogen Company. <ref name=":1">{{Cite web|title=Executive and Senior Management.|url=https://www.firstcitizensgroup.com/tt/executive-and-senior-management/|accessdate=2022-01-25|work=First Citizens Group|language=en}}</ref> == Agụmakwụkwọ == Karen Darbasie nwetara akara ugo mmụta dị ala na Injinia Eletriki sitere na Mahadum West Indies, nzere Master of Business Administration (MBA) na Mahadum Warwick na nzere masta na Mahadum Essex . <ref name=":0" />{{Cite web|title=First Citizens Group Holdings Ltd.|url=https://www.wsj.com/market-data/quotes/TT/XTRN/FCGFH/company-people/executive-profile/133784021|accessdate=2022-01-25|work=The Wall Street Journal (WSJ)|language=en}}</ref> <ref>{{Cite web|title=Karen Darbasie|url=https://www.bloomberg.com/profile/person/19081464|accessdate=2022-01-25|work=Bloomberg|language=en}}</ref> Nhọrọ Darbasie dị ka onye isi oche nke ụmụ amaala mbụ bụ ụlọ ọrụ mara ọkwa na March 2015. N'oge ahụ, ọ bụ onye isi nke ego a kapịrị ọnụ, ego na ngwa ahịa maka Citibank Trinidad & Tobago. Mgbe oge ezumike gasịrị, <ref>{{Cite web|date=1 March 2015|title=First Citizens gets new CEO|url=https://trinidadexpress.com/news/local/first-citizens-gets-new-ceo/article_eaa1ea60-ca78-5628-9ee4-9e00ca1a8600.html|accessdate=2022-01-31|work=Trinidad Express Newspapers|language=en}}</ref> ọ malitere ọrụ ya na 7 Eprel. <ref>{{Cite web|author=Wayow|first=Sue Ann|date=2015-06-15|title=New FCB CEO to speak at TTCSI function|url=https://trinidadexpress.com/news/local/new-fcb-ceo-to-speak-at-ttcsi-function/article_c4ecbbf1-0aa4-584e-9215-ffcaefac1b57.html|accessdate=2022-01-31|work=Trinidad Express Newspapers|language=en|archive-url=https://web.archive.org/web/20220131084310/https://trinidadexpress.com/news/local/new-fcb-ceo-to-speak-at-ttcsi-function/article_c4ecbbf1-0aa4-584e-9215-ffcaefac1b57.html|archive-date=2022-01-31|url-status=dead}}</ref> == Ntụaka == {{Reflist}} [[Òtù:Mmadụ ndi di ndụ]] n77likoskrk9pl40gq7e5jb4s9zeqc8 Jennie Chua 0 53600 736836 735327 2026-10-08T04:21:06Z InternetArchiveBot 11600 Rescuing 2 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736836 wikitext text/x-wiki '''Jennie Chua Kheng Yeng''' ( Chinese ) bụ nwanyị ọchụnta ego nke Singapore bụ onye na-arụkọ ọrụ nke Beeworks, Inc. Akpọrọ ya aha otu n'ime Forbes Asia 's "50 Women In the Mix" na 2013. <ref name="Forbes1">{{Cite web|title=Forbes Asia's 50 Women In the Mix|url=https://www.forbes.com/pictures/fdgk45ehfi/jennie-chua/|archiveurl=https://web.archive.org/web/20130305042640/http://www.forbes.com/pictures/fdgk45ehfi/jennie-chua/|archivedate=March 5, 2013|work=[[Forbes Asia]]|accessdate=4 March 2013}}</ref> A na-akpọ ya "Singapore's Grande Dame". <ref name="Sevilla">{{Cite web|author=Sevilla|first=Jan|title=What's cooking? Jennie Chua and Jollibee|url=http://www.eturbonews.com/32879/what-s-cooking-jennie-chua-and-jollibee|publisher=Global Travel Industry News|accessdate=5 March 2013}}</ref> == Ndụ mmalite na agụmakwụkwọ == A mụrụ Jennie Chua na Batam, Indonesia wee zụlite ya na mpaghara Tanglin na Singapore . <ref name=":0"/> Ọ bụ ọkpara n'ime ụmụ iri na abụọ. Nna ya, Chua Kok Kuan, bụ onye ọchụnta ego bara ọgaranya nke na-ere cloves na nutmeg, mana ọ tụfuru azụmahịa ya mgbe ọ dị afọ 10. <ref name=":0" /> Chua gụrụ akwụkwọ na Singapore Chinese Girls' School <ref name=":1"/> wee malite ịrụ ọrụ dị ka onye ntorobịa, dị ka onye na-ede akwụkwọ na onye nkuzi . <ref>{{Cite web|url=http://www.swhf.sg/the-inductees/12-business-enterprise/34-jennie-chua|title=SINGAPORE WOMEN'S HALL OF FAME - Jennie Chua|author=SWHF|work=www.swhf.sg|language=en-gb|accessdate=2017-09-02}}</ref> Mgbe ọ gụchara A Level na Anglo-Chinese School, e nyere ya akwụkwọ mmụta ịga Mahadum Singapore (ugbu a bụ National University of Singapore ), ebe ọ kwụsịrị mgbe otu afọ gasịrị. <ref name=":0">{{Cite news|title=Nothing keeps Jennie Chua down|date=12 August 2012|work=The Straits Times}}<cite class="citation news cs1" data-ve-ignore="true">"Nothing keeps Jennie Chua down". ''The Straits Times''. 12 August 2012.</cite></ref> Mgbe ọ gụsịrị akwụkwọ, ọ rụrụ ọrụ dị ka onye nkụzi. == Ndụ onwe onye == Ọ zutere Goh Kian Chee, nwa Goh Keng Swee, mgbe ọ dị afọ 16. Di na nwunye ahụ lụrụ afọ asatọ ka e mesịrị na 1968. Ka Goh gara Mahadum Cornell, Chua kwagara ebe ahụ wee gaa Cornell maka njikwa ụlọ oriri na ọṅụṅụ . Di na nwunye a nwere ụmụ abụọ, <ref name=":1">{{Cite web|url=http://womanoftheyear.herworldplus.com/1999-jennie-chua|title=1999 Jennie Chua – Her World Woman of The Year|work=womanoftheyear.herworldplus.com|language=en-US|accessdate=2017-09-02|archivedate=2017-09-02|archiveurl=https://web.archive.org/web/20170902143801/http://womanoftheyear.herworldplus.com/1999-jennie-chua|url-status=dead}}<cite class="citation web cs1" data-ve-ignore="true">. ''womanoftheyear.herworldplus.com''. Archived from [https://web.archive.org/web/20170902143801/http://womanoftheyear.herworldplus.com/1999-jennie-chua the original] on 2017-09-02<span class="reference-accessdate">. Retrieved <span class="nowrap">2017-09-02</span></span>.</cite></ref> mana ha gbara alụkwaghịm na 1977 wee nọgide na-adị n'udo. <ref name="Forbes2">{{Cite web|title=Hotelier Jennie Chua's New Challenge: Bringing Jollibee Fast Food to Singapore|url=https://www.forbes.com/sites/forbesasia/2012/11/28/hotelier-jennie-chuas-new-challenge-bringing-jollibee-fast-food-to-singapore/2/|work=[[Forbes Asia]]|accessdate=4 March 2013}}</ref> == Ntụaka == dị afọ 16. Di na nwunye ahụ lụrụ afọ asatọ ka e mesịrị na 1968. Ka Goh gara Mahadum{{Reflist}} [[Òtù:Mmadụ ndi di ndụ]] a6uiyyj2lq8kptvhq189zy7apfqrhrc Liz Kelly 0 53629 736855 722263 2026-10-08T11:23:50Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736855 wikitext text/x-wiki [[File:Dessin représentant la sociologue britannique Liz Kelly.jpg|thumb|Liz Kelly]] '''Elizabeth A. Kelly ''' CBE (amụrụ 1951) [1] bụ onye prọfesọ Britain na onye isi ngalaba na-ahụ maka ime ihe ike ụmụaka na nwanyị (CWASU), Mahadum London Metropolitan, [2] onye bụbu onye isi nke ụlọ ọrụ, onye akwụ ụgwọ ugbu a, National Women's National Commission. 3] na onye isi oche, yana Marai Larasi, nke ngwụcha ime ihe ike megide njikọta ụmụ nwanyị. == Ọrụ == Kelly edeela ọtụtụ akwụkwọ na isiokwu metụtara ime ihe ike megide ụmụ nwanyị na ụmụaka, ọ bụkwa onye nchịkọta akụkọ na akwụkwọ akụkọ Child Abuse Review . <ref>{{Cite journal|author=Kelly|first=Liz (guest editor)|title=Editorial: Gender and child harm|journal=Child Abuse Review|volume=18|issue=6|pages=367–371|doi=10.1002/car.1097|date=November 2009}}</ref> Ntụle ya nke ihe kpatara ọtụtụ ndị eboro ebubo n'ike n'ike na-aga n'enweghị ikpe na enweghị ikpe, nke o duziri maka Ụlọ Ọrụ Na-ahụ Maka Ndị Ikpe Na-ahụ Maka Ndị Ikpe, kwuru, "na n'oge ọ bụla nke usoro iwu, echiche na-ezighị ezi na ajọ mbunobi na-ekere òkè na ime mkpebi". N'akwụkwọ ya "The Hidden Gender of Law", Kelly na-ekwu na "enweghi ọdịiche doro anya n'etiti mmekọahụ na ndina n'ike, kama ọ bụ nrụgide, iyi egwu, nrụgide na ike". Ọ na-ekwu na ụmụ nwanyị niile na-enwe ihe ike mmekọahụ n'oge ụfọdụ na ndụ ha.<ref>{{Cite book|url=https://books.google.com/books?id=xo0gTQg5oi8C&pg=PA44|title=Masculinities and Crime: Critique and Reconceptualization of Theory|first=James W.|author=Messerschmidt|date=27 September 1993|publisher=Rowman & Littlefield|isbn=9780847678693}}</ref> Akwụkwọ Kelly "Ịlanahụ Ime Ihe Ike Mmekọahụ" na-akọwa ime ihe ike mmekọahụ dịka gụnyere "omume anụ ahụ, anya, okwu ọnụ ma ọ bụ mmekọahụ nke nwanyị ma ọ bụ nwa agbọghọ na-enwe, n'oge ma ọ bụ mgbe e mesịrị, dị ka iyi egwu, mbuso agha ma ọ bụ mbuso agha, nke nwere mmetụta nke na-emerụ ya ahụ ma ọ bụ na-eweda ya ala na / ma ọ bụ na-ewepụ ikike ya ịchịkwa." Wendy McElroy katọrọ nkọwa dị otú ahụ, na-akọwa ya dị ka "ihe na-akpata ọdachi" na-ekwupụtakwa "akwa ụta abụghị ihe nrịbama nke nkwenye". E nyere Kelly [[Order of the British Empire|CBE]] na 2000 New Years Honours, maka ọrụ iji lụso ime ihe ike megide ụmụ nwanyị na ụmụaka ọgụ. == Nkwado == A matara ya dị ka otu n'ime ụmụ nwanyị 100 nke BBC nke afọ 2017. <ref>{{Cite news|date=2017-09-27|title=BBC 100 Women 2017: Who is on the list?|language=en-GB|work=BBC News|url=https://www.bbc.com/news/world-41380265|accessdate=2022-12-17}}</ref> == Akwụkwọ == === Akwụkwọ === * {{Cite book|author=Kelly|first=Liz|title=Surviving sexual violence|url=https://archive.org/details/survivingsexualv0000kell|publisher=University of Minnesota Press|location=Minneapolis|series=Feminist Perspectives Series|year=1988|isbn=9780816617531}} * {{Cite book|author=Kelly|first=Elizabeth|title=Surviving sexual abuse|publisher=Gore & Osment|location=Rushcutters Bay, New South Wales|year=1995|series=Health Books Series|isbn=9781875531783}} * {{Cite book|author=Kelly|first=Elizabeth A.|title=Education, democracy, and public knowledge|publisher=Westview Press|location=Boulder Colorado|year=1995|isbn=9780813316345|url=https://archive.org/details/educationdemocra0000kell}} * {{Cite book|author=Liz|first=Kelly|title=Women, violence, and male power: feminist activism, research, and practice|url=https://archive.org/details/bwb_O7-CKA-759|publisher=Open University Press|location=Buckingham Philadelphia|year=1996|isbn=9780335195060}} * {{Cite book|author=Liz|first=Kelly|title=Supporting women and challenging men: lessons from the Domestic Violence Intervention Project|publisher=Policy Press|location=Bristol|year=1998|isbn=9781861340689}} * {{Cite book|author=Liz|first=Kelly|title=Challenging violence against women: the Canadian experience|url=https://archive.org/details/challengingviole0000hagu|publisher=Policy Press|location=Bristol, UK|year=2001|isbn=9781861342782}} * {{Cite book|author=Liz|first=Kelly|title=Children's perspectives on domestic violence|url=https://archive.org/details/childrensperspec0000unse|publisher=[[SAGE Publications|SAGE]]|location=London|year=2002|isbn=9780761971061}} * {{Cite book|author=Liz|first=Kelly|title=Moving in the shadows: violence in the lives of minority women and children|publisher=Ashgate|location=Farnham, Surrey Burlington, Vermont|year=2013|isbn=9781409433170}} === Isiakwụkwọ dị n'akwụkwọ === *   *   *   *   *   *   *   * [http://web.mit.edu/end_violence/Articles/Wars%20Against%20Women.pdf Pdf.]  *   *   *   *   === Akụkọ ndị a na-ede na akwụkwọ akụkọ === * {{Cite journal|author=Kelly|first=Liz|title='Nothing really happened': the invalidation of women's experiences of sexual violence|journal=[[Critical Social Policy]]|volume=10|issue=30|pages=39–53|doi=10.1177/026101839001003003|date=December 1990}} * [http://www.troubleandstrife.org/issues/Issue21_FullScan.pdf Pdf.]{{Cite journal|author=Kelly|first=Liz|title=Unspeakable acts: women who abuse|journal=Trouble & Strife|volume=21|pages=13–20|date=Summer 1991|url=http://www.troubleandstrife.org/articles/issue-21/}} * {{Cite journal|author=Kelly|first=Liz (guest editor)|title=Inclusion not exclusion|url=https://archive.org/details/sim_child-abuse-review_1992-12_1_3/page/147|journal=[[Child Abuse Review]]|volume=1|issue=3|pages=147–149|doi=10.1002/car.2380010303|date=December 1992}} * {{Cite journal|author=Kelly|first=Liz|title=The connections between disability and child abuse: a review of the research evidence|url=https://archive.org/details/sim_child-abuse-review_1992-12_1_3/page/157|journal=[[Child Abuse Review]]|volume=1|issue=3|pages=157–167|doi=10.1002/car.2380010305|date=December 1992}} * {{Cite journal|author=Kelly|first=Liz|title=Can't hear or won't hear? — the evidential experience of children with disabilities|url=https://archive.org/details/sim_child-abuse-review_1992-12_1_3/page/188|journal=[[Child Abuse Review]]|volume=1|issue=3|pages=188–190|doi=10.1002/car.2380010311|date=December 1992}} * [http://www.troubleandstrife.org/issues/Issue33_FullScan.pdf Pdf.]{{Cite journal|author=Kelly|first=Liz|title=Weasel words: pedophiles and the cycle of abuse|journal=Trouble & Strife|volume=33|pages=44–49|date=Summer 1996|url=http://www.troubleandstrife.org/articles/issue-33/weasel-words-paedophiles-and-the-cycle-of-abuse/}} * {{Cite journal|author=Kelly|first=Liz|title=Sexual exploitation of children in Europe: Child pornography|journal=[[Journal of Sexual Aggression]]|volume=6|issue=1–2|pages=6–28|doi=10.1080/13552600008413307|date=January 2000}} * {{Cite journal|author=Liz|first=Kelly|title=How do children understand and cope with domestic violence?|url=https://archive.org/details/practice-basw_2002_14_1/page/17|journal=Practice|volume=14|issue=1|pages=17–26|doi=10.1080/09503150208414289|date=January 2002}} * {{Cite journal|author=Kelly|first=Liz|title=The wrong debate: reflections on why force is not the key issue with respect to trafficking in women for sexual exploitation|journal=Feminist Review|volume=73|issue=1|pages=139–144|doi=10.1057/palgrave.fr.9400086|date=January 2003}} * {{Cite journal|author=Kelly|first=Liz|title=The perils of inclusion and exclusion: international debates on the status of trafficked women as victims|journal=[[International Review of Victimology]]|volume=11|issue=1|pages=33–47|doi=10.1177/026975800401100103|date=September 2004}} * {{Cite journal|author=Kelly|first=Liz|title="You can find anything you want": a critical reflection on research on trafficking in persons within and into Europe|journal=[[International Migration (journal)|International Migration]]|volume=43|issue=1–2|pages=235–265|doi=10.1111/j.0020-7985.2005.00319.x|date=January 2005}} * {{Cite journal|author=Kelly|first=Liz|title=Inside outsiders: Mainstreaming violence against women into human rights discourse and practice|journal=International Feminist Journal of Politics|volume=7|issue=4|pages=471–495|doi=10.1080/14616740500284391|date=December 2005}} * {{Cite journal|author=Kelly|first=Liz|title=Multiple perpetrator rape: Naming an offence and initial research findings|journal=[[Journal of Sexual Aggression]]|volume=15|issue=1|pages=83–96|doi=10.1080/13552600802653818|date=March 2009}} * {{Cite journal|author=Kelly|first=Liz (guest editor)|title=Editorial: Gender and child harm|journal=Child Abuse Review|volume=18|issue=6|pages=367–371|doi=10.1002/car.1097|date=November 2009}} * {{Cite journal|author=Kelly|first=Liz|title=Roads to nowhere? Mapping specialised violence against women services|journal=[[Violence Against Women (journal)|Violence Against Women]]|volume=17|issue=3|pages=404–425|doi=10.1177/1077801211398637|pmid=26086982|date=March 2011}} * {{Cite journal|author=Kelly|first=Liz|title=Reconstructing and sequencing behaviours in multiple perpetrator rape|journal=Psychology, Crime & Law|volume=19|issue=3|pages=253–275|doi=10.1080/1068316X.2011.631537|date=April 2013}} * {{Cite journal|author=Kelly|first=Liz|title=Why extending measurements of 'success' in domestic violence perpetrator programmes matters for social work|url=https://archive.org/details/sim_british-journal-of-social-work_2013-09_43_6/page/1092|journal=[[The British Journal of Social Work]]|volume=43|issue=6|pages=1092–1110|doi=10.1093/bjsw/bcs049|date=September 2013}} === Akwụkwọ === ==== Maka CWASU ==== * {{Cite book|author=Kelly|first=Liz|title="What support?": an exploratory study of Council policy and practice, and local support services in the area of domestic violence within Hammersmith and Fulham: final report|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University|location=London|year=1989|oclc=779176979}} * [https://web.archive.org/web/20180417041702/http://www.barnardos.org.uk/splintered_lives_report.pdf Pdf.] E debere ya na Wayback MachineArchived-date":{"wt":"26 October 2019"},"archive-url":{"wt":"<nowiki>https://web.archive.org/web/20191026131159/http://www.barnardos.org.uk/resources/research_and_publications/splintered-lives-sexual-exploitation-of-children-in-the-context-of-childrens-rights-and-child-protection/publication-view.jsp?pid=PUB-1374</nowiki>"},"url-status":{"wt":"dead"}},"i":0}}]}" data-ve-no-generated-contents="true" id="mwtg" typeof="mw:Transclusion">  * {{Cite book|author=Kelly|first=Liz|title=Children, domestic violence and refuges: a study of needs and responses|publisher=Women's Aid Federation England Ltd|location=London|year=1996|isbn=9780907817659}} * [https://web.archive.org/web/20130709225657/http://www.jrf.org.uk/publications/lessons-domestic-violence-intervention-project N'ịntanetị.] E debere ya na Wayback Machine [https://web.archive.org/web/20120526161057/http://www.jrf.org.uk/sites/files/jrf/spr338.pdf Pdf.] E debere ya na Wayback Machine{{Cite book|author=Kelly|first=Liz|others=With [[Julie Bindel]], Sheila Burton, Dianne Butterworth, Kate Cook and Linda Regan|title=Supporting women and challenging men: lessons from the Domestic Violence Intervention Project|publisher=Joseph Rowntree Foundation|location=Bristol|year=1998|isbn=9781861340689}} * [http://www.vawpreventionscotland.org.uk/sites/www.vawpreventionscotland.org.uk/files/1998YPattitudes%20research.pdf Pdf sitere na Zero Tolerance.]{{Cite book|author=Kelly|first=Liz|title=Young people's attitudes towards violence, sex and relationships: a survey and focus group study|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University with the Media Research Unit, University of Glasgow|location=London|year=1998|url=http://www.cwasu.org/project_display.asp?pageid=PROJECTS&type=11&pagekey=55&year=1997|accessdate=27 July 2021|archive-date=12 August 2016|archive-url=https://web.archive.org/web/20160812202300/http://www.cwasu.org/project_display.asp?pageid=PROJECTS&type=11&pagekey=55&year=1997|url-status=dead}} * [https://web.archive.org/web/20160305090014/http://www.womenssupportproject.co.uk/vawtraining/content/childhoodsexualabuseincest/275/userfiles/file/resources/nationalresources/ExpStudyPrevSexualAbuse(4).pdf Pdf.] E debere ya na Wayback Machine{{Cite book|author=Kelly|first=Liz|title=An exploratory study of the prevalence of sexual abuse in a sample of 16-21 year olds|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University|location=London|year=1998|oclc=59908155}} * Ọgwụgwụ nke akụkọ onyinye nye [[Kansụl Nnyocha Akụnụba na Ọha|ESRC]].{{Cite book|author=Kelly|first=Liz|title=Legacies of abuse - 'Its more complicated than that': a qualitative study of the meaning and impacts of sexual abuse in childhood|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University|location=London|year=1998|isbn=9781853772535}} * [https://web.archive.org/web/20151201011339/http://www.womensaid.ie/campaigns/ourpubawarecamp.html Nkọwa n'ịntanetị.] E debere ya na Wayback Machine{{Cite book|author=Kelly|first=Liz|title=Teenage tolerance: the hidden lives of young Irish people: a study of young peoples experience and responses to violence and abuse|publisher=Dublin Women's Aid and the Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University|location=Dublin|year=1999|oclc=779127847}} * {{Cite book|author=Kelly|first=Liz|title=Children's needs coping strategies and understanding of woman abuse|publisher=[[ESRC|ESRC Full Research Report]]|location=Swindon|id=L129251037|year=1999|url=http://www.esrc.ac.uk/my-esrc/grants/L129251037/read|oclc=779177788|accessdate=27 July 2021}} * [https://web.archive.org/web/20130709190946/http://www.jrf.org.uk/publications/working-with-families-where-there-domestic-violence N'ịntanetị.] [https://web.archive.org/web/20140710162718/http://www.jrf.org.uk/sites/files/jrf/jr087-families-services-violence.pdf Pdf.]{{Cite book|author=Kelly|first=Liz|title=From good intentions to good practice: mapping services working with families where there is domestic violence|url=https://archive.org/details/fromgoodintentio0000unse|publisher=Joseph Rowntree Foundation|location=Bristol|year=2000|isbn=9781861342454}} * {{Cite book|author=Kelly|first=Liz|title=Rhetorics and realities: sexual exploitation of children in Europe|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University|location=London|year=2000|isbn=9781853773105}} * {{Cite book|author=Kelly|first=Liz|title=Challenging violence against women: the Canadian experience|url=https://archive.org/details/challengingviole0000hagu|publisher=Policy Press|location=Bristol, UK|year=2001|isbn=9781861342782}} * {{Cite book|author=Kelly|first=Liz|title=Good practice in medical responses to recently reported rape, especially forensic examinations: a briefing paper for the Daphne Strengthening the Linkages Project|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University for Rape Crisis Network Europe|location=London|year=2003|isbn=9780954480325}} * {{Cite book|author=Kelly|first=Liz|title=Achievements against the grain: self-defence training for women and girls in Europe|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University for Rape Crisis Network Europe|location=London|year=2003|isbn=9780954480301}} * {{Cite book|author=Kelly|first=Liz|title=Rape: still a forgotten issue: briefing document for strengthening the linkages - consolidating the European Network Project|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University for Rape Crisis Network Europe|location=London|year=2003|isbn=9780954480332}} * {{Cite book|author=Kelly|first=Liz|title=Worth less or worth more? An evaluation of the Maze Marigold Project|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University for YWCA|location=London|year=2003|isbn=9780954480318}} * [https://web.archive.org/web/20160304120749/http://www.popcenter.org/problems/street_prostitution/PDFs/Bindel%26Kelly_2003.pdf Pdf.] E debere ya na Wayback Machine{{Cite book|author=Kelly|first=Liz|title=A critical examination of responses to prostitution in four countries: Victoria; Australia; Ireland; the Netherlands; Sweden|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University for Routes Out Partnership Board|location=London|year=2003|oclc=779173242}} * [https://web.archive.org/web/20160305184803/http://embracedignity.org/uploads/DemandReportREAD.PDF Pdf.]{{Cite book|author=Kelly|first=Liz|title='It's just like going to the supermarket': men buying sex in East London: report for Safe Exit Tower Hamlets|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University for Rape Crisis Network Europe|location=London|year=2007|isbn=9780954480356}} * [https://web.archive.org/web/20151002165005/http://www.esds.ac.uk/doc/5827%5Cmrdoc%5Cpdf%5C5827userguide.pdf Pdf.] ESRC kwadoro ya.{{Cite book|author=Liz|first=Kelly|title=Rape in the 21st Century; old behaviours, new contexts and emerging powers|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University for Rape Crisis Network Europe|location=London|date=January 2007|url=http://www.esrc.ac.uk/my-esrc/grants/RES-000-22-1679/read|accessdate=30 September 2015}} * Ọ bụ Equal Opportunities Commission na Roddick Foundation kwadoro ya.{{Cite book|author=Kelly|first=Liz|title=From the outset: why violence should be a priority for the Commission for Equality and Human Rights|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University|location=London|date=June 2007|url=}} * [https://web.archive.org/web/20151002040001/http://www.aafda.org.uk/Resources/if_only_we%27d_known.pdf Pdf.] E debere ya na Wayback Machine{{Cite book|author=Kelly|first=Liz|title='If only we'd known': an exploratory study of seven intimate partner homicides in Engleshire – final report to the Engleshire Domestic Violence Homicide Review Group|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University|location=London|date=July 2007|url=http://www.ccinform.co.uk/research/if-only-wed-known-an-exploratory-study-of-seven-intimate-partner-homicides-in-engleshire-final-report-to-the-engleshire-domestic-violence-homicide-review-group/|accessdate=30 September 2015|archive-date=1 October 2015|archive-url=https://web.archive.org/web/20151001150755/http://www.ccinform.co.uk/research/if-only-wed-known-an-exploratory-study-of-seven-intimate-partner-homicides-in-engleshire-final-report-to-the-engleshire-domestic-violence-homicide-review-group/|url-status=dead}} * [http://www2.ohchr.org/english/bodies/cedaw/docs/ngos/UKThematicReportVAW41.pdf Pdf.]{{Cite book|author=Kelly|first=Liz|title=CEDAW thematic shadow report: violence against women in the UK: 2007|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University for CEDAW|location=London|year=2008|isbn=9780954480370}} * {{Cite book|author=Liz|first=Kelly|title=Nordic Baltic pilot project for the support, protection, safe return and rehabilitation of women victims of trafficking for sexual exploitation: Evaluation report|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University|location=London|date=September 2008}} * [http://www.sccjr.ac.uk/wp-content/uploads/2012/11/Daphne_Scotland_Briefing-__Different_Systems,_similar_outcomes%283%29.pdf Pdf.] [http://kunskapsbanken.nck.uu.se/nckkb/nck/publik/fil/visa/197/different Akụkọ ikpeazụ, pdf.] Ọ bụ European Commission Daphne II Programme kwadoro ya.{{Cite book|author=Kelly|first=Liz|title=Different systems, similar outcomes? Tracking attrition in reported rape cases in eleven European countries (Country briefing: Scotland)|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University|location=London|date=May 2009|url=http://www.sccjr.ac.uk/publications/different-systems-similar-outcomes-tracking-attrition-in-reported-rape-cases-in-eleven-countries/|archive-date=2021-09-17|access-date=2024-10-17|archive-url=https://web.archive.org/web/20210917041443/https://www.sccjr.ac.uk/publications/different-systems-similar-outcomes-tracking-attrition-in-reported-rape-cases-in-eleven-countries/|url-status=dead}}  * {{Cite book|author=Kelly|first=Liz|title=A missing link? An exploratory study of the connections between non-consensual sex and teenage pregnancy|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University|location=London|date=July 2010|url=http://www.ccinform.co.uk/research/a-missing-link-an-exploratory-study-of-the-connections-between-non-consensual-sex-and-teenage-pregnancy/|accessdate=30 September 2015|archive-date=1 October 2015|archive-url=https://web.archive.org/web/20151001155011/http://www.ccinform.co.uk/research/a-missing-link-an-exploratory-study-of-the-connections-between-non-consensual-sex-and-teenage-pregnancy/|url-status=dead}} * [https://web.archive.org/web/20160305010330/https://www.tilburguniversity.edu/upload/0669e981-140a-4b05-acc2-5a2428743222_apRRS.pdf Pdf.] E debere ya na Wayback Machine{{Cite book|author=Kelly|first=Liz|title=Realising rights: case studies on state responses to violence against women and children in Europe|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University|location=London|year=2011|isbn=9780954480387}} * [https://web.archive.org/web/20210727063333/http://www.ccrm.org.uk/images/docs/10.2ainto%20the%20foreground%20-%20jacana%20evaluation%20report.pdf Pdf.]{{Cite book|author=Kelly|first=Liz|title=Into the foreground: an evaluation of the Jacana Parenting Programme|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University|location=London|year=2011|url=http://www.ccrm.org.uk/index.php?option=com_content&view=article&id=258&Itemid=323|archive-url=https://web.archive.org/web/20210727063331/http://www.ccrm.org.uk/index.php?option=com_content&view=article&id=258&Itemid=323|archive-date=2021-07-27|access-date=2024-10-17|url-status=dead}} * Akụkọ a na-ebipụtaghị, akụkụ ya ka e hotara na [https://web.archive.org/web/20160817083633/http://henrysmithcharity.org.uk/documents/IslandsintheStreammainreport2011.pdf pdf a.]{{Cite book|author=Kelly|first=Liz|title=Everywhere and anywhere: a focus group study on domestic violence information and awareness raising|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University for the Trust for London and the Henry Smith Charity|location=London|year=2011}} * [https://web.archive.org/web/20160305001403/http://www.niaendingviolence.org.uk/perch/resources/boys-think-girls-are-toys-nia-project-evaluation-report.pdf Pdf.] E debere ya na Wayback Machine{{Cite book|author=Kelly|first=Liz|title=Boys think girls are toys?: An evaluation of the NIA Project Prevention Programme on sexual exploitation|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University|location=London|date=May 2011|url=http://www.ccinform.co.uk/research/boys-think-girls-are-toys-an-evaluation-of-the-nia-project-prevention-programme-on-sexual-exploitation/|accessdate=2015-09-30|archive-date=2015-10-01|archive-url=https://web.archive.org/web/20151001152001/http://www.ccinform.co.uk/research/boys-think-girls-are-toys-an-evaluation-of-the-nia-project-prevention-programme-on-sexual-exploitation/|url-status=dead}} * [https://web.archive.org/web/20151002010238/http://www.childrenscommissioner.gov.uk/sites/default/files/publications/Sex_without_consent_I_suppose_that_is_rape_newprint.pdf Pdf.] Akụkọ e nyere iwu maka Office of the Children's Commissioner's Inquiry into Child Sexual Exploitation in Gangs and Groups.{{Cite book|author=Kelly|first=Liz|title="Sex without consent, I suppose that is rape": How young people in England understand sexual consent|publisher=Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University|location=London|date=November 2013|url=http://www.childrenscommissioner.gov.uk/publications/sex-without-consent-i-suppose-rape-how-young-people-england-understand-sexual-consent|accessdate=2015-09-30|archive-date=2015-10-02|archive-url=https://web.archive.org/web/20151002011004/http://www.childrenscommissioner.gov.uk/publications/sex-without-consent-i-suppose-rape-how-young-people-england-understand-sexual-consent|url-status=dead}} * [https://web.archive.org/web/20160929025935/http://solacewomensaid.org/wp-content/uploads/2014/06/SWA-Finding-Costs-of-Freedom-Report.pdf Pdf.] E debere ya na Wayback Machine{{Cite book|author=Kelly|first=Liz|title=Finding the cost of freedom|publisher=Solace Women's Aid / Child and Woman Abuse Studies Unit (CWASU), London Metropolitan University|location=London|year=2014|url=http://solacewomensaid.org/press-release-finding-the-costs-of-freedom/|accessdate=30 September 2015|archive-date=17 June 2016|archive-url=https://web.archive.org/web/20160617212438/http://solacewomensaid.org/press-release-finding-the-costs-of-freedom/|url-status=dead}} ==== Ụlọ Ọrụ ==== * [http://webarchive.nationalarchives.gov.uk/20110218135832/rds.homeoffice.gov.uk/rds/pdfs/hors193.pdf Pdf.]{{Cite book|author=Kelly|first=Liz|title=Domestic violence matters: an evaluation of a development project|url=https://archive.org/details/domesticviolence0000kell_t0a6|publisher=Home Office, Research Studies|location=London|id=193|year=1999|isbn=9781840821376}} * [https://web.archive.org/web/20160304083147/http://www.ieei.com.pt/traficodepessoas/images/documentos/stopping.pdf Pdf.] E debere ya na Wayback Machine{{Cite book|author=Kelly|first=Liz|title=Stopping traffic: exploring the extent of, and responses to trafficking in women for sexual exploitation in the UK|publisher=Home Office, Policing and Reducing Crime Unit|location=London|id=125|year=2000|isbn=9781840824667}} * [http://webarchive.nationalarchives.gov.uk/20110218135832/http://rds.homeoffice.gov.uk/rds/pdfs04/hors285.pdf Pdf.]{{Cite book|author=Kelly|first=Liz|title=Sexual Assault Referral Centres: developing good practice and maximising potentials|publisher=Home Office Research Study|location=London|id=285|year=2004|isbn=9781844732869}} * [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.183.8948&rep=rep1&type=pdf Pdf.]{{Cite book|author=Kelly|first=Liz|title=Forensic nursing an option for improving responses to reported rape and sexual assault|publisher=Home Office Development and Practice|location=London|id=31|year=2004|isbn=9781844733187}} * [http://webarchive.nationalarchives.gov.uk/20110218135832/rds.homeoffice.gov.uk/rds/pdfs05/hors293.pdf Pdf.]{{Cite book|author=Kelly|first=Liz|title=A gap or a chasm?: Attrition in reported rape cases|publisher=Home Office Research, Development and Statistics Directorate|location=London|id=293|year=2005|isbn=9781844735556}} * [http://webarchive.nationalarchives.gov.uk/20130128103514/http://www.homeoffice.gov.uk/rds/abstracts/rdsolr2006.html N'ịntanetị.] [http://webarchive.nationalarchives.gov.uk/20130128103514/http://rds.homeoffice.gov.uk/rds/pdfs06/rdsolr2006.pdf Pdf.]{{Cite book|author=Kelly|first=Liz|title=Section 41 an evaluation of new legislation limiting sexual history evidence in rape trials|publisher=Home Office Online Reports|location=London|id=OLR 20/06|year=2006|isbn=9781844739264}} * [https://www.gov.uk/government/publications/evaluation-of-the-pilot-of-domestic-violence-protection-orders N'ịntanetị.] [https://www.gov.uk/government/uploads/system/uploads/attachment_data/file/260897/horr76.pdf Pdf.] Nnyocha nke Iwu Nchebe Ime Ihe Ike n'Ụlọ (DVPOs) maka Nzukọ Mpụ na Ndị Uwe Ojii nke Mba Nile 2015.{{Cite book|author=Kelly|first=Liz|others=Joanna R. Adler; Miranda A.H. Horvarth; Jo Lovett; Mark Coulson; David Kernohan; and Mark Gray|title=Evaluation of the pilot of domestic violence protection orders|publisher=Home Office, Crime research and analysis|location=London|id=76|year=2013|isbn=9781782462620}} ==== Akwụkwọ ndị ọzọ ==== * [Ihe e dere n'ala ala peeji] Ụzọ ndị na-eduga na ikpe ziri ezi: nyocha nyocha na akụkọ, nyocha na ikpe ikpe nke ikpe ndina n'ike. London: HM Crown Prosecution Service Inspectorate (HMCPSI). OCLC 224119621. Nnyocha akwụkwọ n'ihu akụkọ nke HMCPSI nyere iwu ma bipụta n'afọ sochirinụ. [https://web.archive.org/web/20240117232738/https://www.justiceinspectorates.gov.uk/cjji/wp-content/uploads/sites/2/2014/04/Rapelitrev.pdf Pdf.]{{Cite book|author=Kelly|first=Liz|title=Routes to (in)justice: a research review on the reporting, investigation and prosecution of rape cases|publisher=[[Crown Prosecution Service#Inspection|HM Crown Prosecution Service Inspectorate (HMCPSI)]]|location=London|date=October 2001|oclc=224119621}} * [Ihe e dere n'ala ala peeji] Nnyocha nyocha banyere akụkọ, nyocha na ikpe nke ikpe ndina n'ike. London: HM Crown Prosecution Service Inspectorate (HMCPSI). OCLC 50329254. HMCPSI nyere iwu ka ha mee ka ha mara nyocha ha banyere nyocha na ikpe ikpe gbasara ebubo ndina n'ike.{{Cite book|author=Kelly|first=Liz|title=A research review on the reporting, investigation and prosecution of rape cases|publisher=[[Crown Prosecution Service#Inspection|HM Crown Prosecution Service Inspectorate (HMCPSI)]]|location=London|year=2002|oclc=50329254}} * [https://web.archive.org/web/20151002000418/http://www.ieei.com.pt/traficodepessoas/images/documentos/womenandchildren.pdf Pdf.]{{Cite book|author=Kelly|first=Liz|title=Journeys of jeopardy: a review of research on trafficking in women and children in Europe|publisher=International Organization for Migration|location=Vienna, Austria|year=2002|series=IOM migration research series|id=no. 11|oclc=51758037}} * {{Cite book|author=Kelly|first=Liz|title=Violence against women and children: Vision, Innovation and Professionalism in policing (VIP Guide)|url=https://archive.org/details/violenceagainstw0000lizk|publisher=Council of Europe Publishing (Editions du Conseil de l'Europe)|location=Strasbourg|year=2003|isbn=9789287151216}} * [http://eige.europa.eu/gender-based-violence/resources/united-kingdom/cedaw-thematic-shadow-report-2003-violence-against-women-uk N'ịntanetị.] E debere ya na Wayback Machine{{Cite book|author=Kelly|first=Liz|title=CEDAW thematic shadow report: violence against women in the UK: 2003|publisher=Women’s National Commission, Amnesty International and Indigo Trust|location=London|year=2004|oclc=779148189}} * [https://web.archive.org/web/20160304193511/http://www.endviolenceagainstwomen.org.uk/data/files/resources/18/what-a-waste-2004.pdf Pdf.]{{Cite book|author=Kelly|first=Liz|title=What a waste: the case for an integrated violence against women strategy|publisher=[[Department of Trade and Industry (United Kingdom)|Department of Trade and Industry]]|location=London|date=February 2005|url=http://www.endviolenceagainstwomen.org.uk/resources/18/what-a-waste-january-2005|oclc=59352200|accessdate=2015-09-30|archive-date=2015-10-01|archive-url=https://web.archive.org/web/20151001222706/http://www.endviolenceagainstwomen.org.uk/resources/18/what-a-waste-january-2005|url-status=dead}} * [https://web.archive.org/web/20151001164429/http://publications.iom.int/bookstore/free/Fertile_Fields.pdf Pdf.] E debere ya na Wayback Machine{{Cite book|author=Kelly|first=Liz|title=Fertile fields: trafficking in persons in Central Asia: a report|url=https://archive.org/details/fertilefieldstra0000kell|publisher=International Organization for Migration|location=Vienna, Austria|year=2005|isbn=9789290682431}} * [https://web.archive.org/web/20151002044432/http://www.endviolenceagainstwomen.org.uk/data/files/resources/33/map_of_gapsNov07.pdf Pdf.]{{Cite book|author=Kelly|first=Liz|title=Map of gaps: the postcode lottery of violence against women support services|publisher=[[End Violence Against Women Coalition|End Violence Against Women]]|location=London|year=2007|url=http://www.endviolenceagainstwomen.org.uk/resources/33/map-of-gaps-november-2007|accessdate=2015-09-30|archive-date=2015-10-02|archive-url=https://web.archive.org/web/20151002030527/http://www.endviolenceagainstwomen.org.uk/resources/33/map-of-gaps-november-2007|url-status=dead}}  * [https://web.archive.org/web/20140530052543/http://www.endviolenceagainstwomen.org.uk/data/files/resources/38/realising_rights-jul-08.pdf Pdf.]{{Cite book|author=Kelly|first=Liz|title=Realising rights, fulfilling obligations: a template for an integrated strategy on violence against women for the UK|publisher=[[End Violence Against Women Coalition|End Violence Against Women]]|location=London|year=2008|url=http://www.endviolenceagainstwomen.org.uk/resources/38/realising-rights-fulfilling-obligations-july-2008|accessdate=2015-10-06|archive-date=2016-03-04|archive-url=https://web.archive.org/web/20160304191941/http://www.endviolenceagainstwomen.org.uk/resources/38/realising-rights-fulfilling-obligations-july-2008|url-status=dead}}  * [https://www.dur.ac.uk/resources/sass/BrownHorvathKellyandWestmarland2010Connectionsanddisconnectionsassessingevidenceknowledgeandpracticeinresponsestorape.pdf Pdf.]{{Cite book|author=Kelly|first=Liz|title=Connections and disconnections: assessing evidence, knowledge and practice in responses to rape|publisher=[[Government Equalities Office]]|location=London|date=April 2010|oclc=785808273}} * [https://www.dur.ac.uk/resources/sass/BrownHorvathKellyandWestmarland2010bHasanythingchanged.pdf Pdf.]{{Cite book|author=Kelly|first=Liz|title=Has anything changed? Results of a comparative study (1977-2010) on opinions on rape|publisher=[[Government Equalities Office]]|location=London|date=April 2010|oclc=912957804}} == Edensibia == {{Reflist|30em}} == Njikọ mpụga == * [https://web.archive.org/web/20150322012517/https://metranet.londonmet.ac.uk/research-units/hrsj/staff-and-associates/liz-kelly.cfm Liz Kelly], London Metropolitan University [[Òtù:Mmadụ ndi di ndụ]] k089k6b6ypp7jw4kj1md1e0wj2lonqa Ihe niile na-aga 0 54116 736828 727800 2026-10-08T00:23:31Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736828 wikitext text/x-wiki "Ihe niile na-aga" bụ egwu Trinidadian-American rapper na onye na-agụ egwú Nicki Minaj sitere na album studio nke atọ ya, The Pinkprint (2014). Ewepụtara ya na Disemba 3, 2014, site na Young Money, Cash Money, na Republic Records dị ka egwu nkwalite mbụ na egwu mmeghe sitere na ọba ahụ. Egwu a eruola elu na nọmba 38 na chaatị US Billboard Hot R&B/Hip-Hop. <ref>{{Cite web|url=http://www.billboard.com/artist/312259/Nicki+Minaj/chart?f=367|title=Nicki Minaj|work=billboard.com|access-date=2024-10-23|archive-date=2013-07-05|archive-url=https://web.archive.org/web/20130705014936/http://www.billboard.com/artist/312259/nicki%2Bminaj/chart?f=367|url-status=dead}}</ref> == Ihe ndị mejupụtara ya == Maka onye na-enye onyinye oge Eliza Berman, "All Things Go" na-egosi egwu ndị na-atụle ọtụtụ nsogbu onwe onye Minaj chere ihu, sitere na mmekọrịta na-adịghị mma ya na ezinụlọ ya ruo na igbu ọchụ nke nwa nwanne nna ya Nicholas Telemaque na 2011. Egwu meghere na Minaj na-atụgharị uche na ya. ama na ọsọ nke ndụ ya gara; "Ndụ bụ ihe nkiri, a gaghị enwe ihe na-esote.. N'amaokwu na-esonụ, Minaj na-abụ abụ banyere ọnwụ nwa nwanne ya na otu o si enyere ya aka ma ọ bụrụ na ọ hapụrụ ya ka ya na ya nọrọ na-ekwu; "M ga-aṅụ ọgwụ ma cheta anya n'anya ya n'ụbọchị ikpeazụ ọ hụrụ m. " Amaokwu ikpeazụ ahụ na-ahụ Minaj ka ọ na-ekwu maka ịbụ nne, site na mmekọrịta ya na nne ya na nwanne ya nwoke, ruo n'ihe gbasara ite ime. <ref name="Time">{{cite magazine|last1=Berman|first1=Eliza|title=Listen to "All Things Go," an Emotional Track from Nicki Minaj's The Pinkprint|url=https://time.com/3616141/all-things-go-nicki-minaj/|magazine=Time|access-date=31 December 2014|date=December 3, 2014|archive-date=18 December 2014|archive-url=https://web.archive.org/web/20141218022704/http://time.com/3616141/all-things-go-nicki-minaj/|url-status=dead}}</ref> == Mmeghachi omume == Niki McGloster nke ''Billboard'' kwuru na egwu ahụ bụ "nke kachasị mma n'ụzọ mmetụta uche na nke kachasị mma, ọ bụ nnukwu ihe na-egosi ntozu oke egwu ọhụrụ ya". == Egwuregwu na-eme ihe nkiri == Na Disemba 6, 2014, Minaj mere egwu ahụ na Saturday Night Live . <ref>{{Cite web|url=http://www.rap-up.com/2014/12/06/video-nicki-minaj-snl-performance//|title=NICKI MINAJ PERFORMS ON 'SNL'|date=December 7, 2014|accessdate=December 7, 2014|publisher=Rap-Up|archive-url=https://web.archive.org/web/20141209192747/http://www.rap-up.com/2014/12/06/video-nicki-minaj-snl-performance/|archive-date=December 9, 2014|url-status=dead}}</ref> E tinyere egwu ahụ na setlist nke The Pinkprint Tour nke malitere na Machị 16, 2015, wee gwụ na Ọgọst 23, 2015. Na 2022 MTV Video Music Awards, Minaj gosipụtara egwu ahụ dị ka akụkụ nke Michael Jackson Video Vanguard Award Medley. == Ihe odide == {{Reflist|2}} ajud71njy5xu7e8ydvqvljpsvovmmyj Farida Rahman 0 54757 736818 193446 2026-10-07T17:02:45Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736818 wikitext text/x-wiki {{Infobox officeholder|office=Member of Bangladesh Parliament - Reserved Women's Seat-17|termstart=22 March 2009|termend=20 November 2013|predecessor=[[Shamsunnahar Khwaja Ahsanullah]]|successor=[[Monowara Begum]]|party=[[Bangladesh Awami League]]}} '''Farida Rahman''' (16 Ọgọst 1945 – 18 Mee 2021) <ref>{{Cite web|title=Constituency 317|url=http://www.parliament.gov.bd/index.php/en/get-involved/contact-an-mp/110-mps-category/mps-of-9th-parliament/1220-constituency-317?csrt=2044781506234693365|work=Bangladesh Parliament|accessdate=2 April 2020|archiveurl=https://web.archive.org/web/20230528093119/http://www.parliament.gov.bd/index.php/en/get-involved/contact-an-mp/110-mps-category/mps-of-9th-parliament/1220-constituency-317?csrt=2044781506234693365|archivedate=28 May 2023}}</ref> <ref>{{Cite news|date=2021-05-19|title=Ex MP Farida Rahman passes away|url=https://www.dhakatribune.com/bangladesh/2021/05/19/ex-mp-farida-rahman-passes-away|accessdate=2021-05-20|work=Dhaka Tribune}}</ref> <ref>{{Cite news|author=Hossain|first=Mosharrof|title=PM mourns death of Mohila AL VP Farida Rahman|work=Bangladesh Sangbad Sangstha (BSS)|url=http://www.bssnews.net/?p=580616|accessdate=2021-05-20|language=en-US|archive-url=https://web.archive.org/web/20210520051950/http://www.bssnews.net/?p=580616|archive-date=2021-05-20|url-status=dead}}</ref> bụ onye ndọrọ ndọrọ ọchịchị Bangladesh Awami na onye otu Jatiya Sangsad sitere na oche ụmụ nwanyị edobere-17 site na 2009 ruo 2013. <ref>{{Cite news|title=45 woman MPs elected|url=https://www.thedailystar.net/news-detail-80498|accessdate=2 April 2020|work=The Daily Star|date=20 March 2009|language=en}}</ref> Mmụta: Nzụlite Ezinụlọ : == Ntụaka == nwanyị echekwabar na oche{{Reflist}} czlewbqk1j9man0g6smh01tdg7wrnf3 Francis Wodié 0 55533 736824 735255 2026-10-07T18:17:41Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736824 wikitext text/x-wiki {{Databox}} Francis Vangah Romain Wodié (25 February 1936 - 3 Julaị 2023) bụ onye ndọrọ ndọrọ ọchịchị, ọkàiwu na onye na-akwado ikike mmadụ. O duuru otu ndị ọrụ Ivorian Workers' Party (PIT) site na 1990 ruo 2011. N'oge ahụ, Wodié jere ozi dị ka osote na National Assembly of Côte d'Ivoire site 1990 ruo 1995 na dị ka Minister nke Higher Education site 1998 ruo 1999. Ọ bụ ya. Onye isi oche nke Council Constitutional nke Côte d'Ivoire site na 2011 ruo 2015. == Akụkọ ndụ == === 1936–1990 === A mụrụ Wodié na Abidjan na 25 Febụwarị 1936.<ref name="Abidjan">{{Cite web|url=http://www.abidjan.net/elections2000/candidats/wodie.asp|title=Candidate profile|language=fr|accessdate=17 November 2008|archiveurl=https://web.archive.org/web/20041019125025/http://www.abidjan.net/elections2000/candidats/wodie.asp|archivedate=19 October 2004|publisher=abidjan.net}}</ref> Ọ gara ụlọ akwụkwọ praịmarị na M'Bahiakro na ụlọ akwụkwọ sekọndrị na Abidjan. Mgbe nke ahụ gasịrị, ọ gụrụ akwụkwọ iwu na Dakar, Senegal, na France na Poitiers na Caen. Mgbe ọ nọ na France, ọ bụ onye otu Executive Bureau nke Association of Ivorian Students na France. N'ọnwa Julaị afọ 1961, e jidere ya "maka itinye nchekwa nke steeti Côte d'Ivoire na France n'ihe ize ndụ", chụpụ ya na France, ma tinye ya n'ụlọ mkpọrọ na Abidjan. Mgbe a tọhapụrụ ya na Jenụwarị 1962, ọ gara n'ihu na ọmụmụ ya na France. Mgbe ọ gụsịrị akwụkwọ ya, ọ laghachiri Côte d'Ivoire, ebe ọ malitere ịkụzi na Mahadum Abidjan. Ọ bụ onye guzobere [[National Union for Research and Higher Education]] (SYNARES) ma bụrụkwa odeakwụkwọ ukwu ya. N'ọnwa Machị n'afọ 1971, e boro ya ebubo na ọ na-arụ ọrụ "na-eme ngagharị iwe", n'ihi ya, ọ biri na Algiers ruo n'ọnwa Ọgọstụ n'afọ 1973. Wodié bụ dean nke ngalaba iwu na Mahadum Abidjan site na 1980 ruo 1986. Ọ bụkwa onye guzobere Ivorian League of Human Rights, ma site na 1985 ruo 1989, ọ bụ onye isi oche nke ngalaba Ivorian nke Amnesty International.<ref name="Abidjan"/> Ọ bụ onye guzobere otu ndị ọrụ Ivorian (PIT) n'ọnwa Eprel afọ 1990 ma duzie otu ahụ site n'oge e guzobere ya dị ka odeakwụkwọ mba mbụ ya.<ref name=PIT>N'ọnwa Mee afọ 1990, na-ezo aka na mgbasa nke ndọrọ ndọrọ ọchịchị dị iche iche n'Africa, nke otu ọchịchị na-achịkwa n'oge gara aga, Wodié kwuru na "ịmepụta usoro dị iche iche bụ naanị nzọụkwụ n'ụzọ ọchịchị onye kwuo uche ya, ọ bụghị njedebe n'onwe ya". === 1990–2023 === Wodié bụ naanị onye PIT na-azọ ọkwa onyeisiala na ntuli aka ndị omeiwu na Nọvemba 1990. <ref name="Abidjan"/> O meriri oche maka mpaghara Cocody na Abidjan, na-emeri ndị ndọrọndọrọ ọchịchị abụọ sitere na Democratic Party of Côte d'Ivoire (PDCI) na onye na-azọ ọkwa site na ndị na-emegide Ivorian Popular Front (FPI). Mgbe a mara ọkwa nsonaazụ ntuli aka ahụ, na-egosi na PDCI enwetala mmeri n'ọtụtụ ndị omeiwu, Wodié kwuru na ọ hụrụ nsonaazụ ahụ "na-esiri ike ikwere", n'ihi na ha tụrụ aro na ndị mmegide ahụ anaghị ewu ewu karịa ka ọ chere; iji kọwaa nsonaazụ ya, ọ gosipụtara ọnụ ọgụgụ dị ala n'etiti ndị na-eme ntụli aka, na-arụ ụka na ọtụtụ ndị mmadụ enweghị ike ịtụ vootu na nkwenye na PDC I ga-emeri site na aghụghọ. Wodié jere ozi na Mgbakọ Mba ruo mgbe ọ tụfuru oche ya na ntuli aka ndị omeiwu 1995.[1] Dị ka naanị onye ndọrọ ndọrọ ọchịchị megide Onye isi ala Henri Konan Bédié na ntuli aka onye isi ala October 1995, nke ndị otu mmegide ndị ọzọ wepụrụ, [2] [3] Wodié meriri 3.52% nke votu ahụ.<ref name="DB">[https://web.archive.org/web/20110514094239/http://africanelections.tripod.com/ci.html Elections in Côte d'Ivoire], African Elections Database.</ref> N'ime gọọmentị akpọrọ na 11 Ọgọst 1998, a họpụtara Wodié onye minista nke agụmakwụkwọ ka elu na nyocha sayensị.[1] N'ịkọwa mkpebi ya ịbanye na gọọmentị, Wodié kwuru na, n'agbanyeghị na PIT bụ otu mmegide, ọ kwadoro ndụmọdụ na-eme ka otu ahụ nwee ike itinye aka na mmepe mba.[2]. Ọ nọgidere n'ọkwa ozi ya ruo mgbe a chụrụ Bédié n'ọchịchị ndị agha nke 24 Disemba 1999. Ya na ndị ozi ndị ọzọ, a kpọchiri Wodié mgbe ọchịchị ahụ gasịrị, ma a tọhapụrụ ya na 28 December.[3] Na February 2000, Wodié kwupụtara ọkwa ya maka ntuli aka onye isi ala October 2000.[4] Na ntuli aka a, Wodié debere nke atọ na 5.7% nke votu.[5] N'oge ntuli aka nke 2000, ndị Associated Press kọwara ya dị ka "onye ọgụgụ isi na-enweghị onye mba siri ike na-eso ya.. Ebe ọ bụ na ọ rụrụ ọrụ dị ka odeakwụkwọ mba mbụ nke PIT kemgbe oge nke Constitutive Congress, a họpụtara Wodié dị ka onye isi oche nke PIT na 3rd Ordinary Congress nke pati ahụ n'ọnwa Ọgọstụ afọ 2004. Wodié guzoro ọzọ dị ka onye ndoro-ndoro PIT na ntuli aka onye isi ala nke Ọktoba 2010, mana ọ dọtara obere nkwado. Ya na ndị otu ya kwadoro Alassane Ouattara na agba nke abụọ nke ntuli aka onye isi ala. Nhoputa ndi ochichi weputara esemokwu di ogologo na nke ime ihe ike maka nchoputa; Ouattara mechara merie mgbe ndị agha na-eguzosi ike n'ihe nye ya weghaara Abidjan n'April 2011. Wodié rituru dị ka onye isi nke PIT na 2011, ma Ouattara mechara họpụta ya dị ka onyeisi oche nke Council Constitutional na 25 July 2011; A họpụtara Wodié ka ọ nọchie Paul Yao N'Dre, onye na-eguzosi ike n'ihe nke onye iro Ouattara chụpụrụ Laurent Gbagbo.. Wodié gbara arụkwaghịm dị ka onye isi oche nke Kansụl Iwu na 28 Jenụwarị 2015. [[Mamadou Koné (judge)|Mamadou Koné]] nọchiri ya na 20 Febụwarị. Francis Wodié nwụrụ na 3 Julaị 2023, mgbe ọ dị afọ 87. <ref>{{Cite web|author=Info|first=R. T. I.|date=3 July 2023|title=Décès du Professeur Francis Wodié ce lundi 03 juillet 2023 à 87 ans|url=https://www.rti.info/depeches/2023/7/3/deces-du-professeur-francis-wodie-ce-lundi-03-juillet-2023-a-87-ans|accessdate=3 July 2023|work=RTI Info|language=fr|archivedate=3 July 2023|archiveurl=https://web.archive.org/web/20230703113552/https://www.rti.info/depeches/2023/7/3/deces-du-professeur-francis-wodie-ce-lundi-03-juillet-2023-a-87-ans}}</ref> == Ihe odide == {{Reflist}} 45m0lsk12hlgoj9onnhqa177s61spxv Jennifer Kewley Draskau 0 57484 736837 735333 2026-10-08T04:21:51Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736837 wikitext text/x-wiki [[Faịlụ:Margaret Jennifer Kewley Draskau in the video 'Lady Derby – The Great Whore of Babylon'.png|thumb|Jennifer Kewley Draskau ]]   Margaret Jennifer Kewley Draskau (nwụrụ n'onyinye iri abụọ na otu n'n arịa Ọtoba n'afọ 2024) bụ onye Manx na-akọ ihe mere eme, akwụkwọ ozi, onye nkuzi, onye ike agbara na onye ama na Isle of Man.[1]   O feed ọtụtụ akwụkwọ, ọrụ ya mgbasa ama bụ akwụkwọ ntụle, ,pụta okwu napụta nke okwu 2008 na Asụsụ Manx Gaelic, Practical Manx .Ezigbo Manx. == Ndụ == A match Draskau na Isle of Man, ebe nna ya bụ onye bụ onye nwe ndị uwe ojii na Isle nke Man.[1]  Ọ gara Akwụkwọ Buchan dị na Castletown, ma ngwaọrụ oge sum ya na ụmụ nwanne nne na-asụ Welsh na Wales.[2]  Ọ mara mara nke ọma, ọkpụkpọ Bekee, Danish, French, German na Manx, ma mara ọtụtụ ndị ọzọ nke ọma.  Ọ gara n'ihu na nkwado ya na Mahadum Manchester . <ref name=":1"/> Draskau mụrụ nwoke Danish.[1]  Ọ biri na Denmark ruo afọ iri abụọ, ebe ọ pịari na Mahadum Copenhagen na Mahadim Aarhus .  [2] N'afọ 1987, ọ nzere nzere doctorate na Mahadum Copenhagen maka edemede The Quest for Equivalence: On Translating Villon .  [3] Ahụ ya dị ka Honorary Senior Research Fellow na Ngalaba Bekee na Mahadum Liverpool na dị ka Senior Research Fello na Mahadum nke Center for Manx Studies.[2]  Ọ bụ ọrụ nwa oge dị ka onye nkuzi edemede maka mpaghara eze na Thailand.<ref name=":0"/> Mgbe ọ la mfe Man, Draskau nhọrọ German na Ramsey Grammar School na Ramsey ma webata Manx Studies na usoro.[1]  N'afọ 1996, ọ guzoro maka ibu aka na ụlọ omebe iwu nke ngosi ahụ, House of Keys, na Michael sheading.  Okari 33.65% nke votu, mana David Cannan meri ya.[2]  Ọ na-abụkwa abụ na ndị ukwe Manx Cliogaree Twoaie, bungee wụliri elu ma mara na ọ na-egwu mmiri n'Oké Sirish..<ref name=":1">{{Cite web|date=25 October 2024|title=Jennifer Kewley Draskau - a tribute|url=https://culturevannin.im/news/jennifer-kewley-draskau---a-tribute-878153/|accessdate=12 January 2025|work=Culture Vannin}}<cite class="citation web cs1" data-ve-ignore="true">[https://culturevannin.im/news/jennifer-kewley-draskau---a-tribute-878153/ "Jennifer Kewley Draskau - a tribute"]. ''Culture Vannin''. 25 October 2024<span class="reference-accessdate">. Retrieved <span class="nowrap">12 January</span> 2025</span>.</cite></ref> N'afọ 2004, o kwuru okwu na Mahadum Harvard Celtic Colloquium, na-ekwu Okwu Ikwu "Language death and mbilite n'ọnwụ in the Isle of Man: the continuity of Manx Gaelic exlified by the use of inflected verb tenes".<ref>{{Cite web|title=Kewley Draskau (Jennifer)|url=https://codecs.vanhamel.nl/Kewley_Draskau_(Jennifer)|accessdate=2025-01-23|work=CODECS: Online Database and e-Resources for Celtic Studies}}</ref> N'afọ 2006, o bipụtara nsụgharị ọhụrụ nke uri An Account of the Isle of Man in Song, ederede kachasị ochie e dere na Manx Gaelic (n'etiti ihe dị ka 1490 na 1530) nke a makwaara dị ka ''Manannan Ballad'' ma ọ bụ Manx Traditionary Ballad . <ref>{{Cite book|author=Matthews|first=Jodie|url=https://books.google.com/books?id=RyssBwAAQBAJ&dq=Jennifer+Kewley+Draskau&pg=PA177|title=Islands and Britishness: A Global Perspective|date=2011-11-15|publisher=Cambridge Scholars Publishing|isbn=978-1-4438-3543-5|pages=164|language=en}}</ref> N'afọ 2008, Draskau akwụkwọ ntụaka akwụkwọ Manx Practical Manx, [1] nke ihe na mmemme na Manx Museum, Douglas.  [2] Ka ọ na-ede Practical Manx, Draskau amụola ihe odide ndị na-abụ afọ nke 15 na mbụ awụ de 18 nke Manx nke Bible, yana mmegide olu na-ahụ olu nke ahụ site n'ige ntĩ na nwunye ụka n'etiti ndị na-asụ asụsụ ahụ nke ọma.  [3] [3] [4] Mgbe e nyere akwụkwọ ahụ, o kwuru na: "Enwere m ike na akwụkwọ m nwere ike ịbụ nke usoro a site na n'inye ụgwọ nhọrọ nke Asụsụ Manx, ihe atụ maka ndị ọrụ ma ọ bụ ewereere akwụkwọ ahụ.  anwụ.". <ref name=":4">{{Cite web|date=4 February 2009|title=The melody of Manx|url=https://www.bbc.co.uk/isleofman/content/articles/2009/02/03/manxmelody_feature.shtml|accessdate=2025-01-17|work=BBC Isle of Man|language=en-gb}}</ref><ref>{{Cite news|date=2009-02-20|title=UN declares Manx Gaelic 'extinct'|url=http://news.bbc.co.uk/2/hi/europe/isle_of_man/7901763.stm|accessdate=2025-01-17|work=BBC News|language=en-GB}}</ref> N'A 2019, ọ akara akwụkwọ Bekee nke Jon Leirfall's 1979 Norwegian view of the History of the Isle of Man, Tusen år på Man (A Thousand Years in Man), maka Culture Vannin .  [1] O biputara aha aha Manx n'azịaka akwụkwọ, Journal of Terminology Science and Research, Journal of Celtic Linguistics [2] na "Contemporary Issues in Manx Culture" nke nwere isiokwu, iche iche nke Celtic Cultural Studies..<ref>{{Cite journal|author=Draskau|first=Jennifer Kewley|date=2009|title=Role of Joshua Fishman's Yians in Xish Revitalization: The Case of Manx Gaelic';|journal=Celtic Cultural Studies}}</ref> Draskau sitere n'agbụrụ nna nke onye na-ahụ maka mba Manx na apụ nke iri na asaa bụ Illiam Dhone.[1][2]  Ihe ndị metụtara ndụ ya nke ịhụnanya Illiam Dhone: Patriot or Traitor?  na 2012 ma kwuo na akwụkwọ ahụ na "ihe ọ blea ndị na-agụ akwụkwọ na-ekwu maka ikike ya dị ka onye nwụrụ n'ihi akwụkwọ ya, Associate ya na-aga n'ihu na-ejide ụgbọ..<ref>{{Cite web|title=Landmark nationalist tribute to Illiam Dhone|url=https://www.manxradio.com/news/isle-of-man-news/landmark-nationalist-tribute-to-illiam-dhone/|accessdate=2025-01-12|work=Manx Radio|language=en}}</ref><ref>{{Cite web|date=6 December 2012|title=Biography presented to President of Tynwald|url=https://www.tynwald.org.im/news/biography-presented-to-president-of-tynwald|accessdate=12 January 2025|work=Tynwald}}</ref><ref name=":1"/><ref>{{Cite web|author=Clague|first=Lynsey|date=2013-08-02|title=Illiam Dhone and the Sheep under the Snow Dr. Jennifer Kewley Draskau|url=https://manxnationalheritage.im/news/illiam-dhone-and-the-sheep-under-the-snow-dr-jennifer-kewley-draskau/|accessdate=2025-01-23|work=Manx National Heritage|language=en}}</ref> meta ihe mere eme ya ndị ọzọ ajụjụ ndị agha ụwa nke mbụ na Isle of Man .  [1] Onye ọrụ na akwụkwọ ozi site na Douglas Internment Camp [2] ma ime ihe nkiri nke ọrụ ojii.  [3]][4] O weputara echiche na ndị inyom na-eme ihe ngosi n' nwaetiti ahụ "rụrụ ọrụ dị mkpa na ndị mmadụ na ibe ya na iwu nke ụmụ nwoke niile dị n'ime ụzọ ndị watch.  Lusitania anɔwo na-ebu ihe ụlọ 25,000 "ndị iro" ndị na-eje ije n'ogige abụọ na Man.<ref name=":3"/> Tinyere nyocha na-abụghị akụkọ ifo, Draskau dekwara egwuregwu na akwụkwọ akụkọ na-enweta ihe nrite. Nnyocha ya banyere ''Lusitania'' kpaliri egwuregwu The Sinking of Immaculate O"Shea . <ref name=":3">{{Cite news|author=Morgan|first=Janis|date=7 September 2010|title=Isle of Man research inspires historical play|url=https://news.liverpool.ac.uk/2010/09/07/isle-of-man-research-inspires-historical-play/|accessdate=12 January 2025|work=University of Liverpool News|language=en-GB|archive-url=https://web.archive.org/web/20230930035404/https://news.liverpool.ac.uk/2010/09/07/isle-of-man-research-inspires-historical-play/|archive-date=30 September 2023|url-status=bot: unknown}}<cite class="citation news cs1" data-ve-ignore="true" id="CITEREFMorgan2010">Morgan, Janis (7 September 2010). . ''University of Liverpool News''. Archived from [https://news.liverpool.ac.uk/2010/09/07/isle-of-man-research-inspires-historical-play/ the original] on 30 September 2023<span class="reference-accessdate">. Retrieved <span class="nowrap">12 January</span> 2025</span>.</cite></ref> Emere ya na Isle of Man na New Zealand . <ref name=":1"/> Ọrụ akụkọ ifo ya nke afọ 2020 bụ Transportee bu n'uche ime ka nsogbu nke ndị ikom na ndị inyom Manx bụ ndị e si n'àgwàetiti ahụ bubata ịrụ ọrụ na ndị Britain na-achị n'oge narị afọ nke iri na asaa.<ref>{{Cite news|date=10 March 2021|title=Transported away|url=https://www.iomtoday.co.im/news/transported-away-239985|accessdate=12 January 2025|work=Isle of Man Today}}</ref> Ọ nwụrụ na 2024.<ref name=":0">{{Cite news|author=Curphey|first=Tom|date=28 October 2024|title=Tributes paid to renowned Manx historian and linguist Dr Jennifer Kewley Draskau|url=https://www.iomtoday.co.im/news/tributes-paid-to-renowned-manx-historian-and-linguist-dr-jennifer-kewley-draskau-733969|accessdate=12 January 2025|work=Isle of Man Today}}<cite class="citation news cs1" data-ve-ignore="true" id="CITEREFCurphey2024">Curphey, Tom (28 October 2024). [https://www.iomtoday.co.im/news/tributes-paid-to-renowned-manx-historian-and-linguist-dr-jennifer-kewley-draskau-733969 "Tributes paid to renowned Manx historian and linguist Dr Jennifer Kewley Draskau"]. ''Isle of Man Today''<span class="reference-accessdate">. Retrieved <span class="nowrap">12 January</span> 2025</span>.</cite></ref> == Akwụkwọ ndị ọzọ == * ''Margaid nke Baldhoon'' (2000) * Ezigbo Manx (2008) * ''Agụ ojii'' (2013) * ''[https://books.google.co.uk/books?id=lVsrEkIlXIkC&dq=Jennifer+Draskau&lr=&source=gbs_navlinks_s Illiam Dhone: Onye hụrụ mba n'anya ma ọ bụ onye sabo?]'' (2012) * Tudor Rose: Princess Mary, Henry's Sister (2013) * ''Lusitania: Ọdachi Ka Ọdachi Ka Ojii Agha?'' (2015) * ''Lady Derby, Nnukwu Nwanyị akwụna nke Babilọn'' (2020) <ref>{{Cite news|author=Wade|first=Mike|date=21 November 2020|title=Jennifer sheds new light on the 'Great Whore of Babylon'|url=https://www.iomtoday.co.im/news/jennifer-sheds-new-light-on-the-great-whore-of-babylon-238333|accessdate=12 January 2025|work=Isle of Man Today}}</ref> * ''Onye na-ebugharị'' (2020) <ref name=":1"/> == Ihe odide == {{Reflist}} np6g7lry7ebjxaopg3mp695swb8we07 Joséphine Guidy Wandja 0 58247 736846 735447 2026-10-08T06:08:50Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736846 wikitext text/x-wiki {{Databox}} {{Reflist}} Joséphine Guidy Wandja (amụrụ 1945, bụkwakwa Guidy-Wandja) bụ onye mgbakọ na mwepụ nke Ivory Coast.[1] Ọ bụ nwanyị Africa mbụ nwere PhD na mgbakọ na mwepụ. == Oge ọ malitere == Ọ kwagara France mgbe ọ dị afọ 14.[1] Ọ gara Lycée Jules-Ferry na Paris, ma mesịa gaa Mahadum Pierre na Marie Curie.[1] Ngụsị akwụkwọ nzere nna ya ukwu bụ Sous les courbes fermées convexes du plan et le théorème des quatre sommets (N'okpuru convex curves n'ime ụgbọ elu na theorem nke ugwu anọ).[2] Mgbe ọ na-arụ ọrụ na Paris na njedebe 1960, René Thom, Henri Cartan na Paulette Liberman nyere ya ndụmọdụ.[3] Ọ gụrụ akwụkwọ maka PhD na Mahadum Abidjan, wee bụrụ nwanyị Afrịka mbụ nwetara PhD na mgbakọ na mwepụ. <ref name="AC">{{Cite web|url=http://africultures.com/les-femmes-peinent-a-percer-les-bulles-7367/|title=Les femmes peinent à percer les bulles|language=fr|author=Cassiau-Haurie|first=Christophe|publisher=Africultures|date=20 February 2008|accessdate=16 March 2019}}<cite class="citation web cs1 cs1-prop-foreign-lang-source" data-ve-ignore="true" id="CITEREFCassiau-Haurie2008">Cassiau-Haurie, Christophe (20 February 2008). [http://africultures.com/les-femmes-peinent-a-percer-les-bulles-7367/ "Les femmes peinent à percer les bulles"] (in French). Africultures<span class="reference-accessdate">. Retrieved <span class="nowrap">16 March</span> 2019</span>.</cite> [[Category:CS1 French-language sources (fr)]]</ref><ref name="CWM">{{Cite web|url=https://www.mathunion.org/cwm/people/gallery/josephine-guidy-wandja|title=Joséphine Guidy-Wandja|publisher=Committee for Women in Mathematics|accessdate=16 March 2019}}<cite class="citation web cs1" data-ve-ignore="true">[https://www.mathunion.org/cwm/people/gallery/josephine-guidy-wandja "Joséphine Guidy-Wandja"]. Committee for Women in Mathematics<span class="reference-accessdate">. Retrieved <span class="nowrap">16 March</span> 2019</span>.</cite></ref> == Ọrụ == N'afọ 1969, ọ rụrụ ọrụ na Lycée Jacques Amyot na Melun, tupu ọ rụọ ọrụ otu afọ na Mahadum Paris Diderot . <ref name="Amina"/> N'afọ 1971, ọ sonyeere Mahadum Abidjan, dị ka onye nkuzi [[Ọmúmú-ónúọgụgụ|mgbakọ na mwepụ]].<ref name="Amina" /> N'ime nke a, ọ ghọrọ prọfesọ mgbakọ na mwepụ nke nwanyị mbụ n'Afrịka.<ref name="CWM"/> N'afọ 1983, a họpụtara ya dịka onye isi oche nke Kọmitii Mba Nile na mgbakọ na mwepụ na mba ndị na-emepe emepe (ICOMIDC). E guzobere nzukọ ahụ n'oge nzukọ International Mathematical Union (IMU) na Warsaw, Poland, mana na-enweghị ihe ọmụma IMU.<ref name="Lehto">{{Cite book|url=https://books.google.com/books?id=YxTSBwAAQBAJ&dq=Jos%C3%A9phine+Guidy+Wandja|title=Mathematics Without Borders: A History of the International Mathematical Union|author=Lehto|first=Olli|date=6 December 2012|publisher=[[Springer Science+Business Media]]|isbn=9781461206132|accessdate=16 March 2019}}</ref> N'afọ 1986, o dere akwụkwọ na-atọ ọchị nke dị peeji 24 Yao crack en maths . <ref name="AC"/><ref>{{Cite news|url=http://news.abidjan.net/h/581959.html|title=Littérature pour enfant : "Yao crack en math", une bande dessinée qui démystifie les maths|language=fr|work=Abidijan.net|date=10 February 2016|accessdate=16 March 2018}}</ref> N'afọ 1985, ọ haziri nzukọ ICOMIDC na Yamoussoukro, Ivory Coast . <ref name="Lehto" /> Ọ bụ onye ọrụ nke Ivorian Order of Merit of National Education, na French Ordre des Palmes Académiques . <ref name="Amina">{{Cite web|url=http://aflit.arts.uwa.edu.au/AMINAGuidyWandja.html|archiveurl=https://archive.wikiwix.com/cache/20160416184914/http://aflit.arts.uwa.edu.au/AMINAGuidyWandja.html|title=Interview de Joséphine Guidy Wandja|publisher=Amina|date=July 1986|archivedate=16 April 2016|pages=50–53|accessdate=16 March 2019|url-status=bot: unknown}}<cite class="citation web cs1" data-ve-ignore="true">. Amina. July 1986. pp.&nbsp;<span class="nowrap">50–</span>53. Archived from [http://aflit.arts.uwa.edu.au/AMINAGuidyWandja.html the original] on 16 April 2016<span class="reference-accessdate">. Retrieved <span class="nowrap">16 March</span> 2019</span>.</cite></ref><ref name="CWM"/> == Akwụkwọ ndị e bipụtara == * [Ihe e dere n'ala ala peeji]   == Edemsibia == [[Otú:Mmadụ ndi di ndụ]] 4pdx3vcq69rvlxfyc2yifkna5anna9b Jibril Aminu 0 71793 736839 735396 2026-10-08T04:33:08Z InternetArchiveBot 11600 Rescuing 2 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736839 wikitext text/x-wiki {{Infobox officeholder | name = Jibril Aminu | image = | width = | smallimage = | caption = | alt = | office1 = [[Adamawa Central senatorial district|Senator for Adamawa Central]] | termstart1 = 3 June 2003 | termend1 = 6 June 2011 | predecessor1 = [[Abubakar Girei]] | successor1 = [[Bello Mohammed Tukur]] | birth_date = {{Birth date|1939|08|25|df=y}} | birth_place = [[Song, Nigeria|Song]], Adamawa Province, [[Colony and Protectorate of Nigeria]] | death_date = {{Death date and age|2025|6|5|1939|08|25|df=y}} | death_place = | party = [[Peoples Democratic Party (Nigeria)|Peoples Democratic Party]] | otherparty = | spouse = Fatima Bukar Mulima<br />Ladi Ahmed | children = 9 | education = | occupation = {{hlist|Politician|Professor}} | profession = | alma_mater = | website = | birth_name = Aminu Song }} '''Jibril Muhammad Aminu''' (25 August 1939 - 5 June 2025), nke a maara dịka Aminu Song, bụ onye Naijiria prọfesọ nke ọrịa obi na onye ndọrọ ndọrọ ọchịchị.<ref name="ooni"/> o bụ onye nnọchi anya Naịjirịa na United Steeti malite na 1999 ruo 2003 ma jee ozi dị ka onye omeiwu na-anọchite anya mpaghara Adamawa Central site na 2003 ruo 2011. Ọ bụ onye otu Peoples Democratic Party (PDP). <ref name="nassnig"/> == Mbido ndụ na ọrụ agụmakwụkwọ == A mụrụ Aminu na afọ ọnwa 25 Ọgọstụ 1939. Naịmụ ọgwụ, ọ nwetara M.B.B.S na Mahadum Ibadan na 1965, na PhD na ọgwụ nakwa Royal Post-Graduate Medical Skụụlụ, London na 1972. A họpụtara ya ka ọ osọrọ na ndị nke Naijiria Academy of Science na 1972, Fellow nke Royal College of Physicians, London na 1980 na Fellow nke West African College of Physacians kwa na 1980. E mere ya onye Distinguished Fellow nke Naijiria Postgraduate ụlọọgwụ College na 2004. <ref name="nassnig">{{Cite web|url=http://www.nassnig.org/senate/member.php?senator=19&page=1&state=4|archiveurl=https://web.archive.org/web/20160303200436/http://www.nassnig.org/senate/member.php?senator=19&page=1&state=4|archivedate=2016-03-03|publisher=National Assembly of Nigeria|title=Sen. Jibril Muhammad Aminu|accessdate=2010-06-07|url-status=dead}}<cite class="citation web cs1" data-ve-ignore="">. National Assembly of Nigeria. Archived from [https://web.archive.org/web/20160303200436/http://www.nassnig.org/senate/member.php?senator=19&page=1&state=4 the original] on 3 March 2016<span class="reference-accessdate">. Retrieved <span class="nowrap">7 June</span> 2010</span>.</cite></ref> Aminu bụ onye ndụmọdụ na abịa na ọgwụ, onye nkuzi dị elu na onye isi oche, ọmụmụ ọgwụ na Mahadum nke Ibadan Medical School (1973-1975), na onye isi odeakwụkwọ nke National Universities Commission (1975-1979). Ọ ogara ileta Prọfesọ nke na afọ makaỌgwụ na Howard University College of Medicine na Washington DC (1979-1980) na osote chancellor nke Maiduguri, 1980-1985. Ọ bụkwa Prọfesọ nke Ọgwụ na [[Mahadum Nke Maiduguri|Mahadum nke Maiduguri]] (1979-1995). <ref name="nassnig"/> == Ọrụ ndọrọ ndọrọ ọchịchị == Aminu ketala oke na office minister maka nke agụ makwụkwọ Mmụta na mgbe ahụ Minista Federal nke mmanụ nakwa na Mineral Resources (1989-1992). Mgbe ọ bụ Minista mmanụ ọ bụ Onye isi oche nke African Petroleum Producers' Organization (1991) na Onye isi oche of the OPEC Conference (1991-1992). A họpụtara ya ka ọ bụ onye nnọchi anya National Constitutional Conference (1994-1995). Malite na afọ 1999 ruo 2003, Aminu bụ onye nnọchi anya Naijiria na United States of America . <ref name="nassnig"/> A họpụtara Aminu ka ọ bụrụ onye omeiwu nke Adamawa Central na afọ 2003 ma họpụta ya ọzọ n'afọ 2007. Dị ka Senator, a họpụtara Aminu na kọmitii na-ahụ maka ihe gbasara mba ọzọ, agụmakwụkwọ, ndị agha ụgbọelu na ahụike.<ref name="nassnig"/> Na ime nyocha nke ndị Senate na Mee 2009, ThisDay kwuru na ọ kwadoghị iwu ọ bụla, mana o nyere aka na arụmụka gbasara ụfọdụ mmegharị. Ọ na-elekọta Kọmitii Na-ahụ Maka Ihe Ndị Na-eme ná Mba Ọzọ nke ọma, ọ na-etinye aka na ọrụ nke Kọmitii Mmụta.<ref>{{Cite web|url=https://allafrica.com/stories/200905250350.html|title=An Improved Senate, But Some Uninspiring Senators...|work=ThisDay|date=24 May 2009|accessdate=2019-08-30}}</ref> Na Jenụwarị 2, 2010, Ooni nke Ife, Oba Sijuwade nwebatara "Bobaselu nke Isi Iyi".<ref name="ooni">{{Cite web|url=https://allafrica.com/stories/201001111360.html|title=Between Jibril Aminu and Ooni of Ife|work=Vanguard|date=11 January 2010|accessdate=2019-08-30}}<cite class="citation web cs1" data-ve-ignore="">[https://allafrica.com/stories/201001111360.html "Between Jibril Aminu and Ooni of Ife"]. ''Vanguard''. 11 January 2010<span class="reference-accessdate">. Retrieved <span class="nowrap">30 August</span> 2019</span>.</cite></ref> == Ndụ onwe onye na ọnwụ == Jibril Aminu lụrụ di ugboro abụọ. Nwunye ya nke abụọ bụ Fatima Bukar Mulima onye mụrụ ya ụmụ atọ. Nwunye ya gbara alụkwaghịm bụ Ladi Ahmed, ọnye mụrụ ya ụmụ isii. Ụmụ ya ndi nwoke Bashiru Aminu na Murtala Muhammad Aminu bụ ndị na-ahụ maka akụ na ụba na ndị ọchụnta ego ebe ụmụ ya nwanyị na-arụ ọrụ dị ka ndị ọka iwu (Nana Aminu) na ndị dọkịta ezé ([[Aminu Bello]]). <ref>{{Cite news|url=https://punchng.com/dad-said-anyone-who-has-to-show-diplomatic-immunity-doesnt-deserve-it-prof-jubril-aminus-son/|title=Dad said anyone who has to show diplomatic immunity doesn't deserve it –Prof Jubril Aminu's son|publisher=Punch|date=30 September 2018|accessdate=2019-08-30}}</ref> Aminu nwụrụ na ọwa 5 June ,2025, mgbe ọ dị afọ 85. <ref>{{Cite news|author=Abdullahi|first=Amina|title=Prof Jibril Aminu dies at 85|url=https://dailytrust.com/prof-jibril-aminu-dies-at-85/|accessdate=5 June 2025|publisher=Daily Trust}}</ref> == Edemsibia == {{Reflist}}{{Nigerian Senators of the 5th National Assembly}}{{Nigerian Senators of the 6th National Assembly}}{{Authority control}} [[Otú:1939 mụrụ]] [[Otú:Pages with unreviewed translations]] dc8hfou9lw8ig4qxs05nu4l8odio55u Ego ihu igwe na Naịjirịa 0 71811 736703 730002 2026-10-07T13:58:51Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736703 wikitext text/x-wiki [[Faịlụ:Climate_change_09.jpg|thumb|307x307px|Usoro [[Retrogression and land degradation|mmebi ala]] n'obodo [[Gombe (Nigeria)|Gombe]], n'ebe ọwụwa anyanwụ [[Naijiria|Naịjirịa]], na 2023.]]   Ego maka ihu igwe na Naịjirịa gụnyere ngwakọta nke ego sitere n'ime obodo na nke mba ụwa maka mgbanwe ihu igwe, ibelata ya na iguzogide ya. <ref name=":1">{{Cite news|title=Okpanachi: Green Climate Fund Will Aid Nigeria in Fight against Effects of Climate Change|publisher=THISDAYLIVE|date=24 July 2024|accessdate=7 November 2024|url=https://www.thisdaylive.com/2024/07/24/okpanachi-green-climate-fund-will-aid-nigeria-in-fight-against-effects-of-climate-change/}}</ref> <ref name=":3">{{Cite news|author=Adejoro|first=Lara|title=Nigeria may lose $460bn to climate change — Report|publisher=Punch Newspapers|date=22 November 2023|accessdate=7 November 2024|url=https://punchng.com/nigeria-may-lose-460bn-to-climate-change-report/}}</ref> Dịka akụnụba kachasị na Afrịka na otu n'ime ndị na-emepụta mmanụ na kọntinent a, Naịjirịa na-eche nnukwu ihe ịma aka metụtara mgbanwe ihu igwe ihu, gụnyere idei mmiri, ọzara, na ịdabere na mmanụ ọkụ, nke na-emetụta akụ na ụba ya na nchekwa nri. : 54 Mba a na-achọ ime ka amụma ihu igwe ya kwekọọ na ebumnuche nke Nkwekọrịta Paris, site n'iji njikọta nke ego ọha na nkeonwe na mmekorita mba ụwa iji mezuo ebumnuche ndị e depụtara na Ntinye Aka nke Mba (NDC) ya.. <ref name=":5">{{Cite web|title=Nigeria at a glance|publisher=FAO in Nigeria|accessdate=28 July 2025|url=http://www.fao.org/nigeria/fao-in-nigeria/nigeria-at-a-glance/en/}}</ref> == Ihe gbara ya gburugburu na adịghị ike ya == === Ọrụ ugbo na Ọhịa === [[Faịlụ:Koppen-Geiger_Map_NGA_present.svg|thumb|353x353px|Map nke Köppen-Geiger nkewa ihu igwe nke Naịjirịa maka oge 1980-2016]] Naịjirịa nwere ngụkọta ala nke 910,770 km<sup>2</sup>, <ref name=":7">{{Cite web|title=Land area (sq. km) - Nigeria|publisher=World Bank Open Data|accessdate=28 July 2025|url=https://data.worldbank.org/indicator/AG.LND.TOTL.K2?locations=NG}}</ref> nke 77% na-tinye aka na ihe ọkụkụ (gụnyere ala a na-akọ ugbo, ihe ọkụkụ na-adịgide adịgide na ebe ịta nri) <ref name=":8">{{Cite web|title=Country profile – Nigeria|publisher=FAO|date=2016|url=https://www.fao.org/countryprofiles/index/en/?iso3=NGA|accessdate=2025-12-01|archivedate=2025-10-11|archiveurl=https://web.archive.org/web/20251011030604/https://www.fao.org/countryprofiles/index/en/?iso3=NGA}}</ref>: 1 na 22% bụ ọhịa ka ọ na-erule afọ 2020. <ref name=":9">{{Cite web|title=Natural Forest in Nigeria – Nigeria Deforestation Rates & Statistics|publisher=Global Forest Watch|accessdate=28 July 2025|url=https://www.globalforestwatch.org/dashboards/country/NGA/}}</ref> Dị ka Ụlọ Akụ̀ Ụwa si kwuo, ngalaba ọrụ ugbo na-ahụ maka 34% nke ịmepụta ọrụ na mba ahụ.<ref name=":10">{{Cite web|title=Employment in agriculture (% of total employment) – Nigeria|publisher=World Bank Open Data|date=2022|url=https://data.worldbank.org/indicator/SL.AGR.EMPL.ZS?locations=NG}}</ref> Otú ọ dị, mmebi ala na-emetụta ihe dị ka 33% nke ala ugbo, nke mgbanwe ihu igwe mere ka ọ ka njọ. : nke asaa&nbsp;: VII  Ngalaba ọrụ ugbo ka na-akpata ihe dị ka 23% nke GDP nke mba ahụ dịka data Bank World 2021 si dị.<ref name=":12">{{Cite web|title=Agriculture, forestry, and fishing, value added (% of GDP) – Nigeria|publisher=World Bank|url=https://data.worldbank.org/indicator/NV.AGR.TOTL.ZS?locations=NG}}</ref> Mgbanwe nke usoro mmiri ozuzo, mmụba nke idei mmiri, na ọzara n'ebe ugwu nke mba ahụ na-eyi nchekwa nri na ihe oriri na Naịjirịa egwu; mba ahụ na'ihu ụkọ nri ma e jiri ya tụnyere ihe ụlọ chọrọ. : 54 <ref name=":5" /> Dị ka akụkọ Post-Disaster Needs Assessment (PDNA) nke afọ 2012 si kwuo, idei mmiri ahụ, nke malitere na July nke afọ ahụ, mere ka mmebi US $ 16.9 dị ijeri, na-eme ka mkpa maka itinye ego na mgbanwe pụta ìhè. [Ihe e dere n'ala ala peeji]: xx  === Ihe gbara ya gburugburu === [[Faịlụ:Nigeria_GHI_Solar-resource-map_GlobalSolarAtlas_World-Bank-Esmap-Solargis.png|thumb|Map nwere nchịkọta nke ike anyanwụ na Naịjirịa]]   Ngalaba ike dị na Naịjirịa bụ mmanụ ọkụ na ihe mkpofu (43.4% nke ike niile a na-enweta), ọkachasị nkụ na unyi, nke 65% nke ezinụlọ na-eji eme ihe kwa ụbọchị dịka isi nri.<ref name=":15">{{Cite web|title=Nigeria Energy Mix – Countries & Regions|publisher=IEA|accessdate=28 July 2025|url=https://www.iea.org/countries/nigeria}}</ref><ref name=":16">{{Cite web|title=Building a Shared Vision for the Clean Cooking Transition|publisher=Heinrich Böll Stiftung|date=1 April 2022|accessdate=28 July 2025|url=https://www.boell.de/en/2022/04/01/building-shared-vision-clean-cooking-transition}}</ref> Ọ bụ gas sitere n'okike (75%), ebe ihe ndị na-agbanwe agbanwe dị ka hydropower (1.1%) na anyanwụ (0.3% na 2022) na-anọchite anya obere akụkụ nke ngwakọta ike.<ref name=":17">{{Cite web|title=Nigeria Electricity – Countries & Regions|publisher=IEA|accessdate=28 July 2025|url=https://www.iea.org/countries/nigeria}}</ref> <ref name=":19">{{Cite journal|author=Nchege|first=Johnson|title=Hydroelectric production and energy consumption in Nigeria: Problems and solutions|journal=Renewable Energy|date=1 December 2023|volume=119|doi=10.1016/j.renene.2023.119548|accessdate=28 July 2025|url=https://www.sciencedirect.com/science/article/pii/S0960148123014635}}</ref> : 27 : 27  Ikike eletrik arụnyere bụ 12.5 GW, mana naanị 3,500 ruo 5,000 MW dị n'ihi nnukwu nnyefe na nkesa ọnwụ (28-40%). N'agbanyeghị nke ahụ, mkpa ọkụ eletrik nke Naịjirịa karịrị ikike kachasị elu nke grid, na ihe dị ka 17,556 MWh / h na 2020, dị ka data gọọmentị si kwuo. : 38 N'afọ 2023, ọnụego ọkụ eletrik bụ 61.2%, yana nnukwu ọdịiche dị n'etiti obodo ukwu (89%) na ime obodo (ihe na-erughị 33%) n'ọnọdụ ebe ọdịda ọkụ eletrik na-efu akụ na ụba gburugburu US $ 29 ijeri kwa afọ.<ref name=":23">{{Cite web|title=Access to electricity (% of population) – Nigeria|publisher=World Bank|date=2023|url=https://data.worldbank.org/indicator/EG.ELC.ACCS.ZS?locations=NG}}</ref><ref name=":24">{{Cite web|title=Access to electricity, rural (% of rural population) – Nigeria|publisher=World Bank|date=2023|url=https://data.worldbank.org/indicator/EG.ELC.ACCS.RU.ZS?locations=NG}}</ref><ref name=":25">{{Cite news|author=Anyaogu|first=Isaac|title=Explainer: Why Nigeria's power grid is failing|publisher=Reuters|date=11 December 2024|accessdate=29 July 2025|url=https://www.reuters.com/world/africa/why-nigerias-power-grid-is-failing-2024-12-11/}}</ref> === Ọnọdụ akụ na ụba === A na-ewere Naịjirịa dị ka akụ na ụba kachasị ukwuu na kọntinent Afrịka, na GDP nke US $ 188.27 ijeri na 2023 na ọnụ ọgụgụ mmadụ nke 233.3 nde, mana GDP ya maka onye ọ bụla bụ nke kachasị ala n'etiti akụ na ụba iri kachasị ukwuu n'Africa n'ihi ọnụ ọgụgụ buru ibu nke ndị bi na ya.<ref name=":26">{{Cite web|title=Nigeria: Datasets|publisher=IMF|url=https://www.imf.org/en/Countries/NGA}}</ref><ref name=":27">{{Cite web|title=Real GDP per capita Comparison|publisher=The World Factbook|accessdate=28 July 2025|url=https://www.cia.gov/the-world-factbook/field/gdp-per-capita}}</ref> Ngalaba ego nke mba ahụ bụ nke atọ kachasị ukwuu n'ahịa ụlọ akụ nke 1 n'Africa, na ụlọ akụ ndị dị ka FBN Holdings, Access Bank, na Zenith Bank na-eduga na ọkwa mpaghara.<ref name=":28">{{Cite news|author=Thomas|first=David|title=Africa's Top 100 Banks 2024: Nigeria tops West and Central Africa|publisher=African Business|date=25 September 2024|accessdate=28 July 2025|url=https://african.business/2024/09/economy/africas-top-100-banks-2024-nigeria-tops-west-and-central-africa/}}</ref> . <ref name=":29">{{Cite web|title=Nigerian Stock Exchange (NGX) Live|publisher=afx.kwayisi.org|date=28 July 2025|accessdate=28 July 2025|url=https://afx.kwayisi.org/ngx-live/}}</ref><ref name=":30">{{Cite web|title=Listed Companies|date=September 2020|publisher=Nigerian Exchange Limited|url=https://ngxgroup.com/markets/listed-companies/}}</ref> N'agbanyeghị ikike, ego na-acha akwụkwọ ndụ akwụkwọ ndụ dị oke ka ihe na-akpali itinye ego na-ebute ụzọ na ngalaba mmanụ ala dị ka Naịjirịa bụ onye na-emepụta mmanụ kachasị n'Africa. : 27 N'afọ 2020, mba ahụ mefuru ijeri $ 71.3 na mbubata, na-agafe mbupụ site na ijeri $ 43.6, nke ka ukwuu n'ihi ịdabere na mmanụ ala a nụchara anụcha a na-ebubata n'agbanyeghị ikike ime ụlọ. <ref name=":32">{{Cite web|title=Nigeria: Leading Crude Oil Producer in Africa|publisher=Nigerian Upstream Petroleum Regulatory Commission|accessdate=28 July 2025|url=https://nuprc.gov.ng/nigeria-leading-crude-oil-producer-in-africa/|archivedate=16 September 2025|archiveurl=https://web.archive.org/web/20250916045542/https://www.nuprc.gov.ng/nigeria-leading-crude-oil-producer-in-africa/}}</ref><ref name=":33">{{Cite news|author=Nnodim|first=Okechukwu|title=Nigeria's petroleum imports exceeded exports by $43.56bn – OPEC|publisher=Punch Newspapers|date=3 October 2021|accessdate=28 July 2025|url=https://punchng.com/nigerias-petroleum-imports-exceeded-exports-by-43-56bn-opec/}}</ref><ref name=":34">{{Cite news|author=Anyaogu|first=Isaac|title=Dangote Oil Refinery begins processing gasoline, NNPC to be sole buyer|publisher=Reuters|date=2 September 2024|accessdate=29 July 2025|url=https://www.reuters.com/business/energy/dangote-oil-refinery-begins-processing-gasoline-nnpc-be-sole-buyer-2024-09-02/}}</ref> == Usoro ndọrọ ndọrọ ọchịchị na nke iwu == Naịjirịa etinyela mgbanwe ihu igwe n'ime iwu ya site na akwụkwọ dịka "Nigeria Energy Transition Plan" (2021) na "National Energy Policy" (2022), nke na-akwalite ebumnuche ike na-agbanwe agbanwe na mgbasawanye nke ahịa itinye ego na-adịgide adịgide. Iwu Mgbanwe Ihu igwe nke 2021 guzobere Kansụl Mgbanwe Ihuigwe nke Mba, nke na-ahụ maka ịhazi iwu ihu igwe na ijikwa National Climate Change Fund.<ref name=":36">{{Cite web|title=FGN Moves to Activate Climate Change Fund, Aligns Finance with Green Agenda|publisher=Federal Ministry of Finance|date=4 April 2025|url=https://finance.gov.ng/fgn-moves-to-activate-climate-change-fund-aligns-finance-with-green-agenda/|access-date=1 December 2025|archive-url=https://web.archive.org/web/20251114214204/https://finance.gov.ng/fgn-moves-to-activate-climate-change-fund-aligns-finance-with-green-agenda/|archive-date=14 November 2025|url-status=dead}}</ref> .<ref name=":37">{{Cite web|title=Regulatory landscape for solar power in Nigeria|publisher=IBA|date=6 November 2024|url=https://www.ibanet.org/regulatory-landscape-solar-power-Nigeria}}</ref> Ndị mba ọzọ nwere ike ijide 100% equity na ọrụ, dabere na ndebanye aha na Corporate Affairs Commission (CAC) na nkwado sitere na Nigerian Electricity Regulatory Commission (NERC) na Federal Competition and Consumer Protection Commission (FCCPC). <ref name=":38">{{Cite web|title=Renewable energy project approvals in Nigeria|publisher=Lexology|date=28 August 2021|accessdate=28 July 2025|url=https://www.lexology.com/library/detail.aspx?g=}}</ref> : 4 Otú ọ dị, nrụrụ aka, bureaucracy, na igbu oge n'ịkwado nkwekọrịta ịzụta ike (PPAs) na-egbochi itinye ego na ike ọhụrụ.<ref name=":40">{{Cite journal|author=Onuh|first=Peter|title=Challenges and Opportunities in Nigeria's Renewable Energy Policy and Legislation|journal=World Journal of Advanced Research and Reviews|date=2024|volume=23|issue=2|pages=2354–2372|doi=10.30574/wjarr.2024.23.2.2391|url=https://zenodo.org/records/14891064}}</ref> == Ọnọdụ ihu igwe na-agafe == === Ndị mmadụ === N'agbata afọ 2012 na 2016, ihe ka ọtụtụ n'ime ego ihu igwe na Naịjirịa sitere na mmefu ego mba, na US $ 4.8 nde e kenyere site na Climate Investment Fund, onyinye £17,000 DFID, na US$ 352,000 site na Global Environment Facility. Tụkwasị na nke a, na 2024, e nyekwara ụlọ akụ mmepe nke Naijiria ikike ịnweta n'etiti US $ 50 nde na US $ 250 nde site na Green Climate Fund iji kwado usoro mgbanwe ihu igwe. <ref name=":1" /> : 167-168 Ego ihu igwe sikwa na Heinrich Böll Foundation (HBS) n'etiti afọ 2012 na 2016 nke ruru € 423,320. : 129 : 129  Dabere na 2012 Post-Disaster Needs Assessment (PDNA) Report maka [[Ọgbakọ Otú United Nations Fremewok maka Ngbanwe Iru igwe|UNFCCC]] na 2017, mkpa ego dị mkpa gụnyere njikwa idei mmiri na mkpa iji dozie mmebi nke US $ 16.9 ijeri. Na mgbakwunye, itinye ego nke ihe dị ka ijeri US $ 177 dị mkpa iji belata ihe ịma aka nke ihe mkpofu, ihe onwunwe mmiri, na gas na-ekpo ọkụ. : 13–14 : 4 : 4  Na 2024, gọọmentị kenyere ego na Climate Change Fund, site na nkwado nke World Bank, International Finance Corporation (IFC), na IMF, iji gbasaa ego akwụkwọ ndụ akwụkwọ ndụ..<ref name=":48">{{Cite web|title=Transcript of G24 October 22 Press Briefing|publisher=IMF|date=22 October 2024|format=PDF|url=https://www.imf.org/external/np/g24/trans/2024/102224.htm}}</ref> N'ọnwa Eprel afọ 2025, Minista na-ahụ maka ego na Minista na na-ahụ Maka akụ na ụba, Wale Edun, zutere Dr. Nkiruka Madueke, onye isi nchịkwa nke Kansụl Mgbanwe Ihu igwe ke Naịjirịa (NCCC), iji kwurịta banyere mmalite nke Ego Mgbanwe Ihuigwe, nke ebumnuche ya bụ ịkwado ngwọta ihu igwe na ịkwalite ego ahịhịa ndụ.<ref name=":49">{{Cite web|title=FGN Moves to Activate Climate Change Fund, Aligns Finance with Green Agenda|publisher=Federal Ministry of Finance, Nigeria|date=4 April 2025|accessdate=29 July 2025|url=https://finance.gov.ng/fgn-moves-to-activate-climate-change-fund-aligns-finance-with-green-agenda/|archive-url=https://web.archive.org/web/20251114214204/https://finance.gov.ng/fgn-moves-to-activate-climate-change-fund-aligns-finance-with-green-agenda/|archive-date=14 November 2025|url-status=dead}}</ref> Otú ọ dị, ibute ụzọ nke itinye ego na mmanụ ala na ọkụ nke ijeri cubic mita 7 nke gas kwa afọ, na-akpata mfu nke ijeri US $ 2.5 na-egbochi ọganihu na ike dị ọcha.<ref name=":50">{{Cite news|title=Gas flaring: Reps to recover over $9 billion fines from oil companies|publisher=Vanguard News|date=24 July 2023|accessdate=29 July 2025|url=https://www.vanguardngr.com/2023/07/gas-flaring-reps-to-recover-over-9bn-fines-from-oil-companies/}}</ref><ref name=":51">{{Cite journal|author=Ojijiagwo|first=Emeka|title=Economics of gas to wire technology applied in gas flare management|journal=Engineering Science and Technology, an International Journal|date=1 December 2016|volume=19|issue=4|pages=2109–2118|doi=10.1016/j.jestch.2016.09.012|url=https://www.sciencedirect.com/science/article/pii/S2215098616301508}}</ref> Ngalaba njem, nke tricycles (keke neutral), minibuses (danfos), na ọgba tum tum (okadas) na-achịkwa, bụ isi ihe na-emetọ obodo.<ref name=":66">{{Cite journal|author=Afolabi|first=Oluwaseyi Joseph|title=Urban Challenges and Informal Public Transport Services in Nigeria|journal=Review of International Comparative Management|date=July 2020|volume=21|issue=3|pages=319‑331|doi=10.24818/RMCI.2020.3.319|accessdate=29 July 2025|url=https://rmci.ase.ro/no21vol3/03.pdf}}</ref> Ahịa ụgbọ ala eletrik (EV) na-arị elu na mba ahụ, n'ihi nchegbu banyere mmetọ na ọnụahịa mmanụ ụgbọala.<ref name=":67">{{Cite journal|author=Akujor|first=Chidi E.|title=Decarbonisation of the Transport Sector in Nigeria|journal=Environmental Health Insights|date=2022|volume=16|doi=10.1177/11786302221125039|pmid=36185498|issn=1178-6302}}</ref> Ụfọdụ atụmatụ na-akwalite nnabata EV site na enyemaka na ọdụ ịkwụ ụgwọ n'efu, ọ bụ ezie na akụrụngwa ịkwụ ụgwọ ka dị obere.<ref name=":68">{{Cite journal|author=Farinloye|first=Temitope|title=Driving the electric vehicle agenda in Nigeria: The challenges, prospects and opportunities|journal=Transportation Research Part D: Transport and Environment|date=1 May 2024|volume=130|doi=10.1016/j.trd.2024.104182|issn=1361-9209|accessdate=29 July 2025|url=https://www.sciencedirect.com/science/article/pii/S136192092400047X}}</ref><ref name=":69">{{Cite web|title=ECN Commissions Hybrid Electric Vehicle Charging Station to Advance Clean Energy in Nigeria|publisher=Energy Commission of Nigeria|accessdate=29 July 2025|url=https://www.energy.gov.ng/ecn-commissions-ev-charging-station/}}</ref> [[Faịlụ:Rice_field_39.jpg|thumb|Ubi osikapa na Naịjirịa]] === Ọrụ ugbo na oké ọhịa === Mba ahụ ekwenyewo iweghachi nde hekta 4 nke ala mebiri emebi ka ọ na-erule 2030 n'okpuru African Forest Landscape Restoration Initiative (AFR100) na inweta Land Degradation Neutrality (LDN) n'otu oge ahụ, na atụmatụ itinye ego nke US $ 194 ijeri.<ref name=":70">{{Cite web|title=The role of forests and wildlife in building resilience and recovery from crises and threats|publisher=FAO|date=August 2022|accessdate=29 July 2025|url=https://www.fao.org/forestry/news/98023/en/}}</ref> : 5 : 4, 30 : 4, 30  == Atụmanya Ndị Na-abịa n'Ọdịnihu == Naịjirịa nwere nnukwu ike mmeghari ohuru, nwere ike imeghari 14,120 MW na mmiri na ruo GW 210 na ike anyanwụ., <ref name=":19" /> == Hụkwa == * Mgbanwe ihu igwe na Kenya * Ego ihu igwe na Kenya * Ego ihu igwe na Jamaica * Ego ihu igwe na Trinidad na Tobago * Ego ihu igwe na Senegal == Edensibia == {{Reflist}} [[Otú:Pages with unreviewed translations]] 4hojrs3up9w23qob4015mjqbtl6bj4p Liudmyla Starytska-Cherniakhivska 0 73528 736854 735617 2026-10-08T11:18:56Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736854 wikitext text/x-wiki [[Faịlụ:Старицька-Черняхівська Л1.jpg|thumb|Lioudmyla Starytska-Tcherniakhivska]] '''Liudmyla Starytska-Cherniakhivska''' (a mụrụ n'ezinụlọ Starytska; n'asụsụ Ukraine: Людмила Михайлівна Старицька-Черняхівська, 17 Ọgọst [O.S. 29 Ọgọst] 1868 – 1941) bụ onye Ukraine na-ede edemede, onye nsụgharị asụsụ, onye nkatọ akwụkwọ ọgụgụ na mmepụta ihe nkiri and na onye ndọrọ ndọrọ ọchịchị.<ref name="TUW"/><ref name="UNIPLiudmyla"/> Onye e boro ebubo na o sooro na emume megidere Soviet, Starytska-Cherniakhivska nwụrụ mgbe a nọ na-ebuga ya n'ogige gulag.<ref name="Міхно"/><ref name="IEU"/><ref name="UNIPOksana"/> == Akụkọ ndụ == A mụrụ Liudmyla Mykhailivna Starytska (Ukrainian: Людмила Михайлівна Старицька) na 17 Ọgọst [O.S. 29 Ọgọst] 1868 na Kyiv, n'Alaeze Ukwu Russia (nke bụ Ukraine taa) n'ezinụlọ ndịUkraine ụbụrụ na-ahọ nkọ. Nna Starytska-Cherniakhivska, Mykhailo Starytsky, bụ onye edemede, ode uri na onye na-ede ejije, ebe nne ya Sofiia Starytska, bụ onye na-eme mkpọsa, onyw nwe ụlọ ahịa na onye na-eme ihe nkiri .<ref name="UNIPLiudmyla">{{Cite web|title=1868 - народилася Людмила Старицька-Черняхівська, письменниця, театрознавиця|url=https://uinp.gov.ua/istorychnyy-kalendar/serpen/29/1868-narodylasya-lyudmyla-starycka-chernyahivska-pysmennycya-teatroznavycya|work=Historical calendar|publisher=[[Ukrainian Institute of National Memory]]|accessdate=15 February 2026|language=uk}}<cite class="citation web cs1 cs1-prop-foreign-lang-source" data-ve-ignore="">[https://uinp.gov.ua/istorychnyy-kalendar/serpen/29/1868-narodylasya-lyudmyla-starycka-chernyahivska-pysmennycya-teatroznavycya "1868 - народилася Людмила Старицька-Черняхівська, письменниця, театрознавиця"] &#x5B;1868 - Lyudmila Starytska-Chernyakhivska, writer, theater critic, was born&#x5D;. ''Historical calendar'' (in Ukrainian). Kyiv: [[Ukrainian Institute of National Memory]]<span class="reference-accessdate">. Retrieved <span class="nowrap">15 February</span> 2026</span>.</cite> [[Category:CS1 Ukrainian-language sources (uk)]]</ref> Starytska-Cherniakhivska bụ nwanne nwanyị nke obere nke onye na-eme ihe nkiri na onye nduzi mmepụta ihe nkiri Mariia Starytska, na nwanne nwanyị nke tọrọ Oksana Steshenko (1875–1941), onye edemede, onye nsụgharị asụsụ na onye ọrụ agụmakwụkwọ, onye o si n'aka ya wee bụrụ nwunye nwanne Ivan Steshenko. Nwanne nna Starytska-Cherniakhivska bụ onye na-ede egwu, onye na-akpọ piano, onye nduzi ndị ọbụabụ na onye na-ahụ maka egwu agbụrụ bụ Mykola Lysenko . <ref name="UNIPLiudmyla"/> Starytska-Cherniakhivska tolitere n'ọnọdụ ebe e nwere mmasị na nkà na ụkpụrụ mba. Starytska-Cherniakhivska gụrụ akwụkwọ na First Private Women's Gymrnasium dị na Kyiv.<ref name="UNIPLiudmyla"/> N'afọ 1888, Starytska-Cherniakhivska sonyeere òtù edemede "Pleiada".<ref name="UNIPLiudmyla"/> N'afọ 1919, Starytska-Cherniakhivska so guzobe, a ma họpụta ya dịka osote onye isi oche nke Kansụl Mba nke Ụmụ Nwanyị. N'ime 1923 ruo 1924 Starytska-Cherniakhivska bụ onye òtù ndị edemedeAspys literary society.<ref name="Sulyma">{{Cite web|author=Sulyma|first=M. M.|title=Аспис (Асоціація письменників)|editor=Dziuba|url=https://esu.com.ua/article-44488|work=Encyclopedia of Modern Ukraine|publisher=National Academy of Sciences of Ukraine, Shevchenko Scientific Society|accessdate=27 February 2026|language=uk|date=2001}}</ref><ref>{{Cite web|title=Аристократка, феміністка, діячка Центральної Ради|date=2020-02-16|url=https://tyzhden.ua/arystokratka-feministka-diiachka-tsentralnoi-rady/|accessdate=2026-02-13}}</ref><ref name="Ageyeva">{{Cite news|author=[[Vira Ageyeva|Ageyeva, Vira]]|title=Аристократка, феміністка, діячка Центральної Ради|url=https://tyzhden.ua/arystokratka-feministka-diiachka-tsentralnoi-rady/|accessdate=27 February 2026|work=[[The Ukrainian Week]]|date=16 February 2020|language=uk}}</ref> == Njichi Ndị E Jichiri Ya == N'oge mgbụsị akwụkwọ nke afọ 1929, e jidere nwa nwanyị Starytska-Cherniakhivska Veronika Chernyakhivska dị ka akụkụ nke Ikpe Union for the Freedom of Ukraine.<ref name="Matsko"/> E mechara tọhapụ Chernyakhivska na Jenụwarị 1930 n'ihi enweghị ihe akaebe.<ref name="Matsko" /> E jidere Starytska-Cherniakhivska na Oleksandr Chernyakhivsky ma mesịa maa ha ikpe dị ka akụkụ nke otu ụzọ ngosi ahụ.<ref name="UNIPLiudmyla"/> Starytska-Cherniakhivska nọrọ n'ụlọ mkpọrọ a kwụsịtụrụ na Stalino ([[Donetsk]] nke oge a). <ref name="UNIPLiudmyla" /> N'ọnwa Ọgọst n'afọ 1989, Ụlọikpe Kasị Elu nke Ukraine SSR weghachiri Starytska-Cherniakhivska mgbe ọ nwụsịrị. === Njide na ọnwụ nke NKVD === Na 20 Julaị 1941, ndị NKVD jidere Starytska-Cherniakhivska na nwanne ya nwanyị Oksana Steshenko.<ref name="Міхно">{{Cite journal|author=Міхно|first=Олександр Петрович|title=Січень – лютий 2025. Постаті|journal=Освіта і суспільство|date=2025|volume=1|issue=82|pages=36–38|url=https://lib.iitta.gov.ua/id/eprint/744526/1/Міхно%20О.%20%282025%29.%20Педагогічний%20календар.%20Січень-лютий%202025.%20Постаті..pdf|accessdate=15 February 2026|language=uk}}<cite class="citation journal cs1 cs1-prop-foreign-lang-source" data-ve-ignore="" id="CITEREFМіхно2025">Міхно, Олександр Петрович (2025). [https://lib.iitta.gov.ua/id/eprint/744526/1/Міхно%20О.%20%282025%29.%20Педагогічний%20календар.%20Січень-лютий%202025.%20Постаті..pdf "Січень – лютий 2025. Постаті"] &#x5B;January-February 2025. Figures&#x5D; <span class="cs1-format">(PDF)</span>. ''Освіта і суспільство'' (in Ukrainian). '''1''' (82): <span class="nowrap">36–</span>38<span class="reference-accessdate">. Retrieved <span class="nowrap">15 February</span> 2026</span>.</cite> [[Category:CS1 Ukrainian-language sources (uk)]]</ref><ref name="IEU">{{Cite web|title=Steshenko, Oksana|url=https://www.encyclopediaofukraine.com/display.asp?linkpath=pages%5CS%5CT%5CSteshenkoOksana.htm|work=Internet Encyclopedia of Ukraine|publisher=Canadian Institute of Ukrainian Studies, University of Alberta|accessdate=15 February 2026|language=en|date=2001}}<cite class="citation web cs1" data-ve-ignore="">[https://www.encyclopediaofukraine.com/display.asp?linkpath=pages%5CS%5CT%5CSteshenkoOksana.htm "Steshenko, Oksana"]. ''Internet Encyclopedia of Ukraine''. Edmonton, Alberta: Canadian Institute of Ukrainian Studies, University of Alberta. 2001<span class="reference-accessdate">. Retrieved <span class="nowrap">15 February</span> 2026</span>.</cite></ref><ref name="UNIPOksana">{{Cite web|title=1875 – народилася Оксана Стешенко (Старицька)|url=https://uinp.gov.ua/istorychnyy-kalendar/sichen/24/1875-narodylasya-oksana-steshenko-starycka|work=Historical calendar|publisher=[[Ukrainian Institute of National Memory]]|accessdate=15 February 2026|language=uk}}<cite class="citation web cs1 cs1-prop-foreign-lang-source" data-ve-ignore="">[https://uinp.gov.ua/istorychnyy-kalendar/sichen/24/1875-narodylasya-oksana-steshenko-starycka "1875 – народилася Оксана Стешенко (Старицька)"] &#x5B;1875 – Oksana Steshenko (Starytska) was born&#x5D;. ''Historical calendar'' (in Ukrainian). Kyiv: [[Ukrainian Institute of National Memory]]<span class="reference-accessdate">. Retrieved <span class="nowrap">15 February</span> 2026</span>.</cite> [[Category:CS1 Ukrainian-language sources (uk)]]</ref> A kpọgara Starytska-Cherniakhivska na Steshenko na Kharkiv ebe e boro ha ebubo ịrụ Ọrụ na-emegide Soviet n'okpuru nkeji edemede 54 nke Iwu Mpụ nke SSR nke Ukraine. <ref name="Міхно" /><ref name="IEU" /><ref name="UNIPOksana" /> E zigara ụmụnne nwanyị abụọ ahụ site na Ụgbọ okporo ígwè Stolypin gaa na Kazakh SSR.<ref name="Міхно" /><ref name="IEU" /><ref name="UNIPOksana" /> Starytska-Cherniakhivska nwụrụ n'oge njem ahụ, a tụpụkwara ozu ya pụọ n'ụgbọ okporo ígwè n'ebe a na-amaghị ama. <ref name="TUW">{{Cite news|title=Turning the pages back... August 29 1868|url=https://archive.ukrweekly.com/wp-content/uploads/The_Ukrainian_Weekly_1994-35.pdf|accessdate=15 February 2026|work=[[The Ukrainian Weekly]]|date=28 August 1994|page=6|archive-url=https://web.archive.org/web/20250323020901/https://archive.ukrweekly.com/wp-content/uploads/The_Ukrainian_Weekly_1994-35.pdf|archive-date=23 March 2025|url-status=bot: unknown}}<cite class="citation news cs1" data-ve-ignore=""> <span class="cs1-format">(PDF)</span>. ''[[The Ukrainian Weekly]]''. Vol.&nbsp;35. Jersey City, New Jersey. 28 August 1994. p.&nbsp;6. Archived from [https://archive.ukrweekly.com/wp-content/uploads/The_Ukrainian_Weekly_1994-35.pdf the original] <span class="cs1-format">(PDF)</span> on 23 March 2025<span class="reference-accessdate">. Retrieved <span class="nowrap">15 February</span> 2026</span>.</cite></ref><ref name="UNIPOksana" /> == Ndụ onwe onye == Starytska-Cherniakhivska lụrụ Oleksandr Chernyakhivsky [uk; fr] (1869-1939), onye dọkịta.<ref name="Matsko">{{Cite web|author=Matsko|first=V. P.|title=Черняхівська Вероніка Олександрівна|editor=Dziuba|url=https://esu.com.ua/article-886291|work=[[Encyclopedia of Modern Ukraine]]|publisher=National Academy of Sciences of Ukraine, Shevchenko Scientific Society|accessdate=14 February 2026|language=uk|date=2024}}<cite class="citation web cs1 cs1-prop-foreign-lang-source" data-ve-ignore="" id="CITEREFMatsko2024">Matsko, V. P. (2024). Dziuba, I.М.; Zhukovsky, A.I.; Zhelezniak, M.H. (eds.). [https://esu.com.ua/article-886291 "Черняхівська Вероніка Олександрівна"] &#x5B;Cherniakhivska Veronika Oleksandrivna&#x5D;. ''[[Encyclopedia of Modern Ukraine]]'' (in Ukrainian). Kyiv: National Academy of Sciences of Ukraine, Shevchenko Scientific Society<span class="reference-accessdate">. Retrieved <span class="nowrap">14 February</span> 2026</span>.</cite> [[Category:CS1 Ukrainian-language sources (uk)]]</ref> Chernyakhivsky na Starytska-Cherniakhivska nwere otu nwa nwanyị, onye na-ede uri na onye nsụgharị asụsụ Veronika Chernyakhiвska.<ref name="Matsko"/> N'afọ 1938, dị ka akụkụ nke Nnukwu Mkpocha, e jidere Chernyakhivska ma mesịa gbuo ya na 22 Septemba 1938 na Kyiv.<ref name="Matsko" /> == Ọrụ ndị dị mkpa == Liudmyla Starytska-Cherniakhivska dere uri, akụkọ, ejije, akụkọ ihe mere eme na nkatọ maka akwụkwọ dị iche iche gụnyere Lviv almanac, ''Pershyi Vinok''. === Ihe nkiri === 1913 - Wings ('Kryla') 1917 - The Last Sheaf ('Ostanniy snip') 1918 - ''Hetman Petro'' Doroshenko 1926 - ''Onye ohi Karmeliuk'' ('Rozbiynyk Karmeliuk') 1927 - ''Ivan Mazepa'' === Ihe Ndị A Ga-echeta === Ihe ndekọ Liudmyla Starytska-Cherniakhivska gụnyere: * Afọ iri abụọ na ise nke ihe nkiri Ukraine. Reflections and Thoughts (Dvadtsiat pyat rokivinskoho teatro. * Nkeji niile nke ndụ Lesia Ukrainka (Khvylyny zhyttia Lesi Ukrainky) * Ihe ncheta banyere M. Lysenko (Spohady pro M. Lysenka) * V. Samiylenko Na Ncheta nke Enyi (V. Samiylenko. Pamyati tovarysha) === Akwụkwọ ndị ọzọ O Dere === '''1893''' - Before the Storm (Pered bureiu), bụ akwụkwọ akụkọ ihe mere eme, nke e bipụtara n'akụkụ n'akụkụ na Pravda, akwụkwọ akụkọ Lviv, n'oge 1893-1894. Onye edemede ahụ edechaghị akwụkwọ akụkọ ahụ. '''1899''' - The Living Grave ('Zhyva Mohyla') bụ nnukwu ọrụ mbụ nke Liudmyla Starytska-Cherniakhivska. E bipụtara akwụkwọ akụkọ ahụ na akwụkwọ akụkọ Kyivan Antiquity. Isiokwu nke akwụkwọ akụkọ ahụ bụ ịhụnanya nke ndị na-eto eto abụọ. E jikọtara akụkọ a ya na ihe ndị si n'akụkọ ọdịnala na akụkọ ifo ndị Ukraine. E nwere ihe oyiyi dị n'etiti The Living Grave na akwụkwọ [[William Shakespeare|Shakespeare]] dere bụ ''Romeo na Juliet'' tinyere Gottfried August Bürger nke dere ''Lenore''. Akwụkwọ akụkọ ahụ bụkwa ezigbo ihe nnọchianya nke íke ịhụnanya na Ukraine ma na-eweta ncheta akwụkwọ Ukraine ndị ochie gbasara ịhụnanya ndị dị ka ballad Marusia nke Levko Borovykovskyi (1829) dere yana (Nikolai Gogol) long tale A Terrible Vengeance (1831-32) nke Mykola Hohol. N'afọ 2015 Sova Books biputara nsụgharị ha n'asụsụ Bekee nke ''The Living Grave''. Otu n'ime ihe ndị na-adọta mmasị na mbipụta ahụ bụ na na mkpuchi akwụkwọ ahụ, ọ na-egosi Daryna, bụ nwanyị kacha pụta ìhè n'akụkọ ahụ nke mere na iji nye onye dere akụkọ ahụ obere ụkpa ekele, onye mbiputa ya megharịrị ihu ya ka o yitu otu n'ime foto nke Liudmyla Starytska-Cherniakhivska. <sup class="noprint Inline-Template Template-Fact" style="white-space:nowrap;">&#x5B;''[[wikipedia:Tinye edensibịa|<span title="This claim needs references to reliable sources. (September 2017)">citation needed</span>]]''&#x5D;</sup> '''1929''' - Onye edemede ahụ dechara Diamond Ring ('Diamantovyi persten') izu isii tupu e jide ya nke mbụ. E mechaghị bipụta ihe odide ahụ ruo afọ iri isii na anọ, ruo mgbe ọ pụtara na akwụkwọ akụkọ Zona n'afọ 1993. == Ihe Ndị e Deturu == == Edensibịa == <references /> [[Otú:Ndị na-ede uri si Kyiv]] [[Otú:Pages with unreviewed translations]] 57wqr12j9re95thmnf1zwif5ausrf2v Kellyanne Conway 0 74512 736849 735568 2026-10-08T07:50:18Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736849 wikitext text/x-wiki {{Infobox officeholder | name = Kellyanne Conway | image = Kellyanne Conway official portrait (3x4 cropped).jpg | caption = Official portrait, 2017 | office = [[Counselor to the President|Senior Counselor to the President]] | president = [[Donald Trump]] | alongside = [[Steve Bannon]] (2017) | term_start = January 20, 2017 | term_end = August 31, 2020 | predecessor = {{br list | [[John Podesta]] | (as Counselor, 2015)}} | successor = {{Ubl | [[Hope Hicks]] | [[Johnny DeStefano]] | (as Counselors, 2020)}} | birth_name = Kellyanne Elizabeth Fitzpatrick | birth_date = {{birth date and age|1967|1|20}} | birth_place = [[Camden, New Jersey]], U.S. | death_date = | death_place = | party = [[Republican Party (United States)|Republican]] | spouse = {{Marriage|[[George Conway]]|2001|2023|end={{abbr|div.|divorced}}}} | children = 4 | education = {{Ubl | [[Trinity Washington University]] ([[Bachelor of Arts|BA]]) | [[George Washington University]] ([[Juris Doctor|JD]]) }} | signature = Kellyanne Conway Signature.svg }} Kellyanne Elizabeth Conway (née Fitzpatrick; amuru Jenụwarị 20, 1967) bụ onye ndụmọdụ ndọrọ ndọrọ ọchịchị na onye nyocha nke jere ozi dị ka onye ndụmọdụ onye isi na Onye isi ala na nwanyị mbụ nke United States Donald Trump site na 2017 ruo 2020. [1] [2] [3] [4] Ọ bụ onye njikwa mgbasa ozi Trump, ahọpụtara ya na August 2016; Conway bụ nwanyị mbụ mere mkpọsa onye isi ala US na-aga nke ọma.[5] Ọ rụrụ ọrụ dị ka onye njikwa mkpọsa na strategist maka Republican Party ma bụrụbu onye isi ala na onye isi oche nke Polling Company/WomanTrend. [6] Na ntuli aka onye isi ala nke Republican Party nke afọ 2016, Conway kwadoro Ted Cruz ma bụrụ onyeisi oche kọmitii ndọrọ ndọrọ ọchịchị na-akwado Cruz ruo mgbe Cruz mechara pụọ n'asọmpi ahụ. N'ọnwa Julaị 2016, mgbe Cruz hapụrụ asọmpi ahụ, Trump họpụtara Conway dị ka onye ndụmọdụ dị elu ma mesịa bụrụ onye njikwa mkpọsa.<ref>{{Cite news|url=https://www.washingtonpost.com/news/post-politics/wp/2016/07/01/trump-hires-ex-cruz-super-pac-strategist-kellyanne-conway/|title=Trump hires ex-Cruz super PAC strategist Kellyanne Conway|date=July 1, 2016|work=The Washington Post|author=Sullivan|first=Sean|accessdate=January 2, 2017}}</ref><ref>{{Cite news|author=Hellmann|first=Jessie|title=Trump campaign manager: Manafort was asked to leave|url=https://thehill.com/blogs/ballot-box/presidential-races/292059-trump-campaign-manager-manafort-was-asked-to-leave/|work=The Hill|date=August 19, 2016|accessdate=January 2, 2017}}</ref> Na Disemba 22, 2016, Trump kwupụtara na Conway ga-esonyere ọchịchị ya dị ka onye ndụmọdụ onye isi ala.<ref name="bbcnewstrumpnames">{{Cite news|title=Trump names Kellyanne Conway as presidential counsellor|url=https://www.bbc.co.uk/news/world-us-canada-38406250|date=December 23, 2016|work=BBC News|accessdate=July 21, 2018}}</ref> Na Nọvemba 29, 2017, Attorney General Jeff Sessions kwupụtara na Conway ga-ahụ maka mbọ White House na-agba iji lụso ọrịa opioid ọgụ. <ref>{{Cite news|url=https://www.buzzfeed.com/danvergano/kellyanne-conway-is-opioids-czar|title=Trump's Counselor Kellyanne Conway Is Now Leading His Opioids Strategy|work=BuzzFeed|accessdate=December 6, 2017|language=en}}</ref><ref>{{Cite news|url=http://www.newsweek.com/kellyanne-conway-lead-white-house-opioid-crisis-efforts-726249|title=Kellyanne Conway will run the White House's opioid crisis efforts|date=November 29, 2017|work=Newsweek|accessdate=December 6, 2017|language=en}}</ref> N'ọrụ ya dị ka Senior Adviser to the President, Conway ji nkebi ahịrịokwu ahụ bụ "Ihe ndị ọzọ" kọwaa ọnụọgụgụ ndị na-aga nraranye Trump. N'afọ 2017, ndị otu Congress sitere na otu abụọ ahụ kpọrọ oku maka nyocha maka mmebi iwu eboro ebubo mgbe ọ kwadoro n'ihu ọha ngwaahịa azụmahịa metụtara ada onye isi ala, Ivanka Trump.[1] Na June 2019, Ọfịs US nke Ndụmọdụ Pụrụ Iche tụrụ aro ka a chụrụ Conway maka “ọnụọgụ a na-enwetụbeghị ụdị ya” nke imebi iwu Hatch nke 1939, mana a chụrụghị ya n'ọrụ.[2] N'August 2020, Conway hapụrụ nchịkwa ahụ. Conway bụ onye na-akọwa mgbasa ozi ugboro ugboro. N'afọ 2022, ọ sonyeere Fox News dị ka onye na-enye onyinye, ọ pụtakwara dị ka onye ọbịa ma ọ bụ onye ọbịa na mmemme dịgasị iche iche, gụnyere ''Hanity'', The Five, Outnumbered, The Big Weekend Show, na ndị ọzọ. O nyekwara aka na ntuli aka nke etiti afọ 2022 nke Fox. N'ọnwa Julaị 2024, Fox News kwupụtara na Conway ga-amalite ịkwado mmemme kwa izu na ikpo okwu netwọk, Fox Nation, nke a na-akpọ Here's The Deal with Kellyanne Conway. == Mbido ndụ na agụmakwụkwọ == A mụrụ Kellyanne Elizabeth Fitzpatrick na Jenụwarị 20, 1967, na Camden, New Jersey, nye Diane (née DiNatale) na John Fitzpatrick, wee tolite na mpaghara Atco dị nso na Waterford Township, New Jersey.[1][2][3] Nna Conway bụ onye German, Bekee na Irish, ebe nne ya bụ onye Italian; John Fitzpatrick nwere obere ụlọ ahịa ụgbọ ala, Diane na-arụkwa ọrụ n'ụlọ akụ.[4] Nne na nna Conway gbara alụkwaghịm mgbe ọ dị afọ atọ, nne ya, nne nne ya na ụmụnne ya abụọ na-alụbeghị di zụlitere ya na Atco.[5][6] Ọ gụsịrị akwụkwọ na St. Joseph High School na 1985 dị ka valedictorian. N'ụlọ akwụkwọ sekọndrị, ọ na-abụkwa abụ n'òtù ukwe, na-egwu egwuregwu hockey, na-arụ ọrụ n'ụgbọ mmiri maka ndụ, ma bụrụ onye na-agba ume.[7] Otu akụkọ 1992 New Jersey Organised Crime Commission mere ka a mara nna nna Conway, Jimmy "The Brute" DiNatale, dịka onye na-eme ihe ike nke ezinụlọ mpụ Philadelphia; ndị DiNatales na nne nne Conway, Conway, na ndị ọzọ so na ezinụlọ ya na-akpakọrịta.[5] Nwa nwanne Conway, Mark DeMarco, kwuru na mgbe ọ nọ n'ụlọ akwụkwọ sekọndrị, Conway nyere ndị otu egwuregwu iwu ka ha kwụsị imegbu ya; dị ka DeMarco si kwuo, mmegbu ahụ kwụsịrị.[8] Ezinụlọ ya bụ ndị Katọlik.[2][9] Conway kwadoro oge okpomọkụ asatọ na-arụ ọrụ n'ugbo blueberry na Hammonton, New Jersey, maka ịkụziri ya ụkpụrụ ọrụ siri ike. "Ka ị na-aga ngwa ngwa, ka ị na-enwetakwu ego," ka o kwuru. Mgbe ọ dị afọ 16, ọ meriri asọmpi New Jersey Blueberry Princess. Mgbe ọ dị afọ 20, ọ meriri asọmpi mbukota Blueberry World Champion. "Ihe niile m mụtara banyere ndụ na azụmahịa malitere n'ugbo ahụ," ka o kwuru na Septemba 2016.[1] Conway gara Trinity College, Washington, D.C., ugbu a Trinity Washington University, ebe a họpụtara ya na Phi Beta Kappa ma gụsịrị akwụkwọ ''magna cum laude'' na Bachelor of Arts na sayensị ndọrọ ndọrọ ọchịchị.<ref>{{Cite news|author=Pascaline|first=Mary|title=Who Is Kellyanne Conway? Trump Aide Turns Down White House Press Secretary Post|url=http://www.ibtimes.com/who-kellyanne-conway-trump-aide-turns-down-white-house-press-secretary-post-2459249|accessdate=February 4, 2017|work=International Business Times|date=December 13, 2016}}</ref> N'afọ 1992, ọ nwetara Juris Doctor na nsọpụrụ site na George Washington University Law School. == Ọrụ == Mgbe ọ gụsịrị akwụkwọ, ọ rụrụ ọrụ dị ka onye odeakwụkwọ ikpe maka Onye ọka ikpe Richard A. Levie <ref name="Levie">{{Cite web|title=Richard A. Levie|url=https://ballotpedia.org/Richard_A._Levie|work=[[Ballotpedia]]|accessdate=May 24, 2022|language=en|archivedate=November 9, 2018|archiveurl=https://web.archive.org/web/20181109101036/https://ballotpedia.org/Richard_A._Levie}}</ref> nke Ụlọikpe Kasị Elu nke District of Columbia.<ref name="ballotpedia.org/Kellyanne">{{Cite web|title=Kellyanne Conway|url=https://ballotpedia.org/Kellyanne_Conway|work=[[Ballotpedia]]|accessdate=May 24, 2022|language=en|archivedate=March 27, 2017|archiveurl=https://web.archive.org/web/20170327131635/https://ballotpedia.org/Kellyanne_Conway}}</ref><ref name="cnn-1996-Kellyanne">{{Cite web|title=Bios – Kellyanne Fitzpatrick|url=https://www.cnn.com/ALLPOLITICS/1996/analysis/bios/cnn/fitzpatrick.shtml|work=AllPolitics|publisher=[[CNN]]|accessdate=May 24, 2022|date=1996|archivedate=May 24, 2022|archiveurl=https://web.archive.org/web/20220524133907/https://www.cnn.com/ALLPOLITICS/1996/analysis/bios/cnn/fitzpatrick.shtml}}</ref><ref name="conwaybio"/> === Pollster na onye ndụmọdụ === Conway banyere na azụmaahịa ntuli aka mgbe ọ nọ n'ụlọ akwụkwọ iwu, na-arụ ọrụ dị ka onye enyemaka nyocha maka Wirthlin Group, ụlọ ọrụ ntuli aka nke Republican. Mgbe ọ gụsịrị akwụkwọ, ọ tụlere ịrụ ọrụ maka ụlọ ọrụ ndị ọka iwu, mana ọ họọrọ ịrụ ọrụ maka Luntz Research Companies kama.<ref name=":0">{{Cite web|url=https://www.theatlantic.com/magazine/archive/2017/04/kellyannes-alternative-universe/517821/|title=Kellyanne's Alternative Universe|author=Ball|first=Molly|date=April 2017|work=[[The Atlantic]]|accessdate=March 15, 2017|archivedate=March 15, 2017|archiveurl=https://web.archive.org/web/20170315014137/https://www.theatlantic.com/magazine/archive/2017/04/kellyannes-alternative-universe/517821/}}</ref> Dị ka nwa akwụkwọ na Trinity College, ọ zutere ma bụrụ enyi Frank Luntz, onye guzobere ụlọ ọrụ ahụ, n'otu afọ na mba ofesi na Mahadum Oxford.<ref name=":0" /> N'afọ 1995, o hiwere ụlọ ọrụ nke ya, The Polling Company, nke na-eme nyocha ndị ahịa, gụnyere n'ihe gbasara ụmụ nwanyị. Ndị ahịa Conway gụnyere Vaseline, American Express na Hasbro.[1] Ọ dụrụkwa onye nnọchi anya US Jack Kemp, US Senator Fred Thompson, [2] [2] [2] Onye isi ala Dan Quayle, [3] Ọkà Okwu nke Houselọ Newt Gingrich, na onye nnọchi anya US (mgbe osote onye isi ala) Mike Pence.[1] Ọ jere ozi dị ka onye ndụmọdụ dị elu nye Gingrich n'oge mkpọsa onye isi ala US na 2012 enweghị ihe ịga nke ọma.[4] Mgbe e mesịrị, na 2012, ọ nọchitere anya onye nnọchiteanya Senate nke United States Todd Akin.[5] Ọ eduzila ọrụ nyocha igwe mmadụ na omume maka ụlọ ọrụ azụmahịa na nkeonwe, gụnyere American Express, ABC News, Major League Baseball, na Ladies Home Journal. Ụlọ ọrụ ya gụnyekwara WomanTrend, ụlọ ọrụ nyocha na ndụmọdụ.[2] === Onye na-akọwa mgbasa ozi === N'afọ ndị 1990, ya na ndị na-akọwa ihe n'ụzọ omenala Laura Ingraham, Barbara Olson, na Ann Coulter, o nyere aka gbanwee punditry ka ọ bụrụ "onye ama ama" na [[Washington, D.C.]] na Televishọn cable. <ref name="COUR">{{Cite web|url=https://www.courant.com/1999/03/27/woman-of-the-right/|title=Woman Of The Right|date=March 27, 1999|accessdate=January 23, 2017|archivedate=December 25, 2016|archiveurl=https://web.archive.org/web/20161225083452/http://articles.courant.com/1999-03-27/features/9903270533_1_laura-ingraham-punditry-cable-television}}</ref><ref name="WP1">{{Cite web|url=https://www.washingtonpost.com/wp-srv/politics/special/clinton/stories/coulter101698.htm|work=Washingtonpost.com|title=The Blonde Flinging Bombshells at Bill Clinton|first=Howard|author=Kurtz|date=October 16, 1998|accessdate=January 23, 2017|archivedate=April 11, 2013|archiveurl=https://web.archive.org/web/20130411100354/http://www.washingtonpost.com/wp-srv/politics/special/clinton/stories/coulter101698.htm}}</ref> ma bụrụ onye a na-ekwu na ọ bụ ya mere ka Washington, D.C. "mmekọahụ teta". N'ime nyocha nke oge ahụ n'isi obodo, Conway (nke a maara dị ka Fitzpatrick n'oge ahụ) kwuru na "uche ya sara mbara na obere úkwù agbanwebeghị ebe". <ref>{{Cite web|url=https://nymag.com/nymetro/news/politics/national/features/2165/index1.html|title=Washington's Sexual Awakening|work=NYMag.com|date=February 9, 1998|accessdate=December 6, 2017|archivedate=June 27, 2021|archiveurl=https://web.archive.org/web/20210627234521/https://nymag.com/nymetro/news/politics/national/features/2165/index1.html}}</ref> A na-akpọ Conway, Ingraham, na Coulter mgbe ụfọdụ "pundettes", <ref name="newyorkerprofile">{{cite magazine |url=https://www.newyorker.com/magazine/2016/10/17/kellyanne-conways-political-machinations |title=Kellyanne Conway's Political Machinations |last=Osnos |first=Evan |date=October 17, 2016 |magazine=[[The New Yorker]]|access-date=December 5, 2016|archive-date=March 8, 2021|archive-url=https://web.archive.org/web/20210308151530/http://www.newyorker.com/magazine/2016/10/17/kellyanne-conways-political-machinations|url-status=live}}</ref> wee pụta na Bill Maher's Politically Incorrect. [[Faịlụ:Kellyanne_Conway_by_Gage_Skidmore_2.jpg|thumb|Conway na 2015]] Conway pụtara dị ka onye na-akọwa ihe gbasara ntuli aka na ndọrọ ndọrọ ọchịchị maka ABC, CBS, NBC, PBS, CNN, MSNBC, NY1, Fox News, na mmemme redio dị iche iche. N'afọ 2004, akwụkwọ akụkọ The Washington Post nyere ya onyinye "Crystal Ball" maka ịkọwapụta ihe ga-esi na ntuli aka nke afọ ahụ pụta.<ref>{{Cite web|url=https://www.pbs.org/to-the-contrary/panelists/41/conway|archiveurl=https://web.archive.org/web/20131123134932/http://www.pbs.org/to-the-contrary/panelists/41/conway|archivedate=November 23, 2013|title=To The Contrary Panelists – To The Contrary|work=[[PBS]]|date=November 23, 2013|accessdate=January 23, 2017}}</ref> === Ntuli aka onye isi ala nke afọ 2016 === ==== Nkwado na nkwado Ted Cruz ==== Na mbido Mee 2016, Cruz kwụsịrị mkpọsa ya. <ref>{{Cite news|url=https://www.bloomberg.com/politics/articles/2016-06-22/new-super-pac-launches-for-donors-who-won-t-back-trump-but-loathe-clinton|title=New Super-PAC Launches for Donors Who Won't Back Trump But Loathe Clinton|author=Green|first=Joshua|date=June 22, 2016|work=Bloomberg.com|accessdate=January 16, 2017}}</ref> ==== 2016 mkpọsa Trump ==== Na Julaị 1, 2016, Trump kwupụtara na ya goro Conway ọrụ maka ọkwa ndụmọdụ dị elu na mkpọsa onye isi ala ya.[1] A na-atụ anya na Conway ga-adụ Trump ọdụ ka ọ ga-esi mee ka ndị inyom na-eme ntuli aka mara mma.[1] Na August 19, mgbe Paul Manafort kwụsịrị arụkwaghịm, Trump kpọrọ Conway onye njikwa mgbasa ozi nke atọ nke mkpọsa ahụ.[2][3] Ọ jere ozi na ikike a izu iri, site na ntuli aka izugbe nke November 8, ma bụrụ nwanyị mbụ mere nke ọma na mkpọsa onye isi ala America, [4] na nwanyị mbụ mere mkpọsa ntuli aka onye isi ala nke Republican.[3] Saturday Night Live malitere satiri ya na Ọktoba 2016, nke Kate McKinnon gosipụtara.[5][6][7] N'ajụjụ ọnụ Jenụwarị 2017, Conway kwetara na SNL parody site n'ịkọba na, "Kate McKinnon na-ahụ n'ụzọ doro anya na ụzọ ga-eme n'ọdịnihu na-esite n'aka m ma ọ bụghị Hillary."[8] [9] === Mgbanwe nke onye isi ala ===   On November 10, 2016, Conway publicly tweeted that Trump had offered her a White House job. "I can have any job I want", she said on November 28. On November 24, Conway tweeted that she was "Receiving deluge of social media & private comms re: Romney. Some Trump loyalists warn against Romney as sec of state" with a link to an article on Trump loyalists' discontent for the 2012 nominee. Conway told CNN she was only tweeting what she has shared with President-elect Donald Trump and Vice President-elect Mike Pence in private.<ref>{{Cite news|url=http://www.cnn.com/2016/11/24/politics/kellyanne-conway-romney-tweets/index.html|title=Conway tweets about Trump base anger over Romney|author=LoBionco|first=Tom|date=November 24, 2016|publisher=CNN|accessdate=November 24, 2016}}</ref> On November 28, two top sources at the Trump transition team told media outlets that Trump "was furious" at Conway for media comments she made on Trump administration cabinet appointments. The following day, however, Trump released a written statement stating that the campaign sources were wrong and that he had expressed disappointment at her critical comments on Romney. CNBC reported on November 28 that senior officials in the Trump transition "have reportedly been growing frustrated by Conway's failure to become a team player." Na Disemba 1, Conway pụtara na ndị enyemaka mgbasa ozi Trump na Harvard Kennedy School maka nzukọ gbasara agbụrụ onye isi ala 2016; Ụlọ akwụkwọ Gọọmenti akwadola arụmụka onyeisi oche anọ kemgbe 1972. Conway nọ n'akụkụ ndị isi mgbasa ozi Clinton, gụnyere onye njikwa mgbasa ozi Clinton Robby Mook. Ka iwe malitere ịmalite, nzukọ ahụ dara n'ime "egwuregwu mkpu"; N'otu mgbanwe, onye isi atụmatụ Clinton bụ Joel Benenson kwuru, "Nke bụ eziokwu bụ na ọtụtụ ndị America họpụtara Hillary Clinton karịa Donald Trump." Conway zara Benenson mgbe ọ na-ele ndị enyemaka Trump anya: "Hey, ụmụ okorobịa, anyị meriri. Ị gaghị emeghachi omume. Ọ bụ ya kacha mma. [1] " Na mbido Disemba, Conway kwuru na ndị na-akwado Hillary Clinton na-eyi ya egwu ọnwụ.<ref>{{Cite news|url=https://abcnews.go.com/Politics/kellyanne-conway-death-threats-fueled-pro-clinton-rhetoric/story?id=44083275|title=Kellyanne Conway: I'm Getting Death Threats Fueled by Pro-Clinton Rhetoric|author=Caplan|first=David|date=December 9, 2016|publisher=ABC News|accessdate=December 9, 2016}}</ref> N'ihi ya, Trump kenyere ndị Ọrụ Nzuzo iji chebe ya.<ref>{{Cite news|url=https://www.politico.com/story/2017/01/kellyanne-conway-secret-service-protection-234092|title=Conway: I have Secret Service protection because of the media|work=Politico|accessdate=December 6, 2017}}</ref><ref>{{Cite news|url=http://fortune.com/2017/01/24/kellyanne-conway-secret-service/|title=Kellyanne Conway Says She Has Secret Service Protection Because of the Media|work=Fortune|accessdate=December 6, 2017|language=en}}</ref><ref>{{Cite news|url=https://thehill.com/blogs/blog-briefing-room/news/315795-kellyanne-conway-ive-gotten-mail-with-white-substances-in-it/|title=Kellyanne Conway gets Secret Service protection|author=Greenwood|first=Max|date=January 23, 2017|work=TheHill|accessdate=December 6, 2017}}</ref> Conway hapụrụ nchebe ya na Septemba 2017 n'ihi "belata egwu". <ref>{{Cite news|url=https://www.nytimes.com/2017/09/18/us/politics/donald-trump-jr-secret-service.html|title=Donald Trump Jr. Gives Up Secret Service Protection, Seeking Privacy|author=Fandos|first=Nicholas|date=September 18, 2017|work=The New York Times|accessdate=December 6, 2017|language=en-US}}</ref><ref>{{Cite news|url=http://www.newsweek.com/donald-trump-jr-and-kellyanne-conway-lose-secret-service-protection-667489|title=Trump's eldest son, Donald Trump Jr., ditches Secret Service detail to have more privacy|date=September 19, 2017|work=Newsweek|accessdate=December 6, 2017|language=en}}</ref><ref>{{Cite news|url=http://www.nj.com/politics/index.ssf/2017/09/kellyanne_conway_no_longer_protected_by_secret_ser.html|title=Kellyanne Conway no longer protected by Secret Service, report says|work=NJ.com|accessdate=December 6, 2017|language=en-US}}</ref> [[Faịlụ:Kellyanne_Conway_Speaks_to_the_Press_(47751382671).jpg|thumb|Conway na-agwa ndị nta akụkọ okwu n'èzí White House na 2019]] N'ajụjụ ọnụ a gbara na Meet the Press ụbọchị abụọ ka emechara Trump ka ọ bụrụ onye isi ala, Conway ji ahịrịokwu ahụ "Ihe ndị ọzọ" gbachitere ihe onye ode akwụkwọ mgbasa ozi White House Sean Spicer kwuru banyere ndị mmadụ. [1] [2] [3] Okwu Conway na-echetara "Newspeak," ụdị asụsụ rụrụ arụ bụ akụkụ bụ isi nke ọha mmadụ na akwụkwọ akụkọ dystopian George Orwell 1984.[4] N'oge na-adịghị anya ka Conway gbasịrị ajụjụ ọnụ, ahịa nke akwụkwọ ahụ gbagoro 9,500%, na New York Times na ndị ọzọ na-ehota okwu Conway ji nkebi ahịrịokwu ahụ, na-eme ka ọ bụrụ akwụkwọ kacha ere na Amazon.com.[5] ==== Mgbukpọ nke Bowling Green ==== Na February 2, 2017, Conway pụtara na ihe nkiri akụkọ telivishọn Hardball na Chris Matthews. N'ịkwado mmachibido iwu Onye isi ala Trump, ọ zoro aka na ihe omume nke ndị na-eyi ọha egwu Iraq mere, nke ọ kpọrọ " igbuchapụ Bowling Green ". Ọ nweghị ụdị ihe ahụ merenụ.[1][2] Vox tụrụ aro na Conway na-ekwu maka njide 2011 nke ndị gbara ọsọ ndụ Iraq abụọ na Bowling Green, Kentucky.[2] Conway kwuru n'echi ya na ọ pụtara "ndị na-eyi ọha egwu na-agba ọsọ", ha abụọ kwetara na ha mere na ịkwado mwakpo ndị agha America na Iraq.[3] O nweghị echiche na ha mere atụmatụ ime mwakpo na United States.[4] Na Febụwarị 5, 2017, prọfesọ na-ahụ maka akụkọ na Mahadum New York Jay Rosen kwuru na, n'ihi na a na-ekwughi eziokwu ugboro ugboro, Conway kwesịrị ịkwụsị idebanye aha ya dị ka onye ọbịa na ihe ngosi akụkọ telivishọn. CNN họọrọ ịghara ide Conway dị ka onye ọbịa n'ụbọchị ahụ n'ihi ihe netwọk ahụ kwuru bụ "ajụjụ siri ike banyere ntụkwasị obi ya" Iwu Hatch nke 1939 na-ekwu na ndị ọrụ gọọmentị etiti ekwesịghị ịkwado òtù ndọrọ ndọrọ ọchịchị ha mgbe ha na-anọchite anya ọfịs ọha na eze. Imebi iwu dị otú ahụ nwere ike ime ka ewepụ onye ọrụ dị otú ahụ n'ọkwa ọha na eze, mana a tụghị ya mkpọrọ.<ref>{{Cite news|author=Phillips|first=Amber|title=What is the Hatch Act, and why did Kellyanne Conway get accused of violating it so egregiously?|url=https://www.washingtonpost.com/politics/2019/06/13/what-is-hatch-act-why-did-kellyanne-conway-get-accused-violating-it-so-egregiously|work=[[The Washington Post]]|accessdate=June 14, 2019}}</ref> A na-ebo Conway ebubo imebi iwu ahụ ọtụtụ oge. Na February 9, 2017, n'oge ngosipụta na Fox & Enyi, Conway lebara mkpebi Nordstrom siri wepụ ngwaahịa na ngwa ahịa Ivanka Trump. "Gaa zụta Ivanka bụ ihe m na-agwa gị," Conway kwuru; ọ gbakwụnyere, "Ọ bụ akara dị mma. Enwere m ụfọdụ n'ime ya. M ga-enyefe mgbasa ozi n'efu ebe a: Gaa zụta ya taa, onye ọ bụla. Ị nwere ike ịchọta ya n'ịntanetị. "[1] [2] N'ime awa ole na ole, òtù abụọ gbara akwụkwọ mkpesa ụkpụrụ omume megide Conway maka imebi iwu gọọmenti etiti nke machibidoro iji ọnọdụ gọọmentị "maka nkwado nke ngwaahịa, ọrụ ma ọ bụ ụlọ ọrụ ọ bụla." [3] Citizen Public jụrụ Office of Government Ethics (OGE) ka ọ nyochaa, na-ekwu na okwu Conway na-egosipụta "na-aga n'ihu na nleghara anya nke esemokwu nke iwu na ụkpụrụ nke mmasị nke ụfọdụ ndị òtù ezinụlọ Trump na ọchịchị Trump." Onye isi oche otu ahụ, Robert Weissman, kwuru, "Ebe ọ bụ na o kwuru na ọ bụ mgbasa ozi ọha na eze, ha abụọ na-ewepụ ajụjụ ọ bụla ma ndị si mba ọzọ na-agụ nkwupụta ahụ ezighi ezi, na abụọ, ọ na-eme ka o doo anya na ọ bụghị ihe a na-amaghị."[4]. Citizens for Responsibility and Ethics na Washington tinyere akwụkwọ mkpesa yiri nke ahụ n'aka OGE na Officelọ Ọrụ Ndụmọdụ White House; Onye isi oche otu ahụ, Noah Bookbinder, kwuru na "Nke a yiri ka o doro anya na mmebi iwu dịka ị nwere ike ịhụ"[5][6] Prọfesọ iwu Harvard Laurence Tribe gwara The New York Times, "Ị pụghị icheta ihe atụ doro anya nke mmebi nke mmachibido iwu iji ọnọdụ gọọmentị gị dị ka ụdị mpempe akwụkwọ na-eje ije maka ngwaahịa ma ọ bụ ọrụ a na-enye na nzuzo," na-agbakwụnye na "Ọ na-agbalị ime ka Ivanka baa ọgaranya na ya mere ezinụlọ onyeisi oche." [1] Chris Lu, osote odeakwụkwọ ọrụ na nchịkwa Obama, tweeted na Jason Chaffetz, onye isi oche nke Kọmitii Ụlọ Nzukọ US na Nlekọta na Ndozigharị, @WeWeWe.[2] [3] Richard Painter, onye ọka iwu na-ahụ maka ụkpụrụ omume maka George W. Bush, jụrụ ikwu ma o chere na ihe Conway kwuru megidere iwu, mana na agaghị anabata omume dị otú ahụ na ọchịchị Bush. "Ihe ndị mere n'izu gara aga na-egosi na ọ dịghị ebumnobi n'akụkụ nke onye isi ala, ezinụlọ ya ma ọ bụ ndị ọrụ White House iji mee ka ọdịiche dị n'etiti ikike ya dị ka onyeisi oche na mmasị azụmahịa nke ezinụlọ Trump." [1] N'oge mkparịta ụka mgbasa ozi mgbe niile n'ehihie ahụ, Sean Spicer gwara ndị nta akụkọ na "a dụrụ Kenlyanne ọdụ, na nke ahụ bụ naanị anyị ga-eso ya... A dụrụ ya ọdụ n'okwu ahụ, ọ bụ ya." N'ịkatọ Spicer ozugbo, Conway tweeted na Trump "na-ahọrọ 'onye ndụmọdụ' karịa 'onye ndụmọdụ.'" [4] [5] [6] Ihe Conway kwuru mere ka ndị otu abụọ katọọ ya. Chaffetz, onye Republican, kpọrọ ha "n'ụzọ doro anya karịa akara" na "ihe a na-anabataghị". Cummings, onye ndọrọ ndọrọ ọchịchị na onye otu kọmitii ahụ, kpọrọ ha "ndị na-atụfu agbà". Ma Chaffetz ma Cummings dere OGE na Febụwarị 9, 2017, na-arịọ ka a nyochaa omume Conway nakwa na ọfịs ahụ na-atụ aro "omume ịdọ aka ná ntị, ma ọ bụrụ na ọ dị mma". Na Nọvemba 24, 2017, Walter Shaub, onye bụbu onye nduzi nke OGE, kwuru na o tinyere akwụkwọ mkpesa megide Conway.<ref name="Green">{{Cite web|author=Green|first=Miranda|title=Former ethics director: Kellyanne Conway violated Hatch Act with Roy Moore comments|url=http://www.cnn.com/2017/11/22/politics/kellyanne-conway-hatch-act/index.html|publisher=CNN|accessdate=November 25, 2017|date=November 24, 2017|archivedate=November 6, 2021|archiveurl=https://web.archive.org/web/20211106214531/https://www.cnn.com/2017/11/22/politics/kellyanne-conway-hatch-act/index.html}}</ref> O kwuru na Conway mebiri Iwu Hatch mgbe ọ katọrọ Doug Jones, onye na-azọ ọkwa na ntuli aka pụrụ iche nke Senate US na 2017 na Alabama.<ref name="Green" /> Na Machị 6, 2018, U.S. Office of Special Counsel (OSC) - nke onye Trump họpụtara Henry Kerner duziri - wepụtara akụkọ ikpeazụ ya, na-ekpebi na Conway mebiri Iwu Hatch na ajụjụ ọnụ telivishọn abụọ na Nọvemba na Disemba 2017.<ref>{{Cite news|author=Mallin|first=Alexander|url=https://abcnews.go.com/Politics/kellyanne-conway-found-violated-hatch-act/story?id=53557326|title=Kellyanne Conway found to have violated law banning use of office for political ends|date=March 6, 2018|publisher=ABC News|accessdate=March 6, 2018}}</ref><ref>{{Cite web|authorlink=Henry Kerner|first=Henry|author=Kerner|url=https://osc.gov/Resources/Conway%20HA-18-0966%20Final%20Report.pdf|title=Report of Prohibited Political Activity under the Hatch Act OSC File No. HA-18-0966 (Kellyanne Conway)|work=U.S. Office of Special Counsel|date=March 6, 2018|accessdate=March 8, 2018|archivedate=May 29, 2019|archiveurl=https://web.archive.org/web/20190529225453/https://osc.gov/Resources/Conway%20HA-18-0966%20Final%20Report.pdf}}</ref>    Conway gara n'ihu na-apụta na telivishọn ugboro ugboro ma na-ekwu okwu banyere isiokwu ndọrọ ndọrọ ọchịchị. Na Mee 2019, Conway kwupụtara, sị: "Ọ bụrụ na ị na-anwa ime ka m mechie ọnụ site na Iwu Hatch, ọ gaghị arụ ọrụ... Ka m mara mgbe ikpe ụlọ mkpọrọ malitere".<ref>{{Cite web|author=Samuels|first=Brett|title=Kellyanne Conway dismisses Hatch Act violation: 'Let me know when the jail sentence starts'|url=https://thehill.com/homenews/administration/445914-kellyanne-conway-dismisses-hatch-act-violation-let-me-know-when-the/|work=[[The Hill (newspaper)|The Hill]]|accessdate=June 13, 2018|archivedate=July 2, 2021|archiveurl=https://web.archive.org/web/20210702084226/https://thehill.com/homenews/administration/445914-kellyanne-conway-dismisses-hatch-act-violation-let-me-know-when-the}}</ref>&nbsp; Na June 13, 2019, OSC tụrụ aro ka ewepụ Conway na ọrụ gọọmentị etiti, na-ekwu maka ọtụtụ mmebi iwu Hatch Act site na Conway kemgbe nkwadebe nke akụkọ ya nke afọ 2018, "site n'ịkwado ndị na-azọ ọkwa onye isi ala nke Democratic mgbe ọ na-ekwu okwu n'oge ajụjụ ọnụ telivishọn na mgbasa ozi mmekọrịta". OSC kwuru nkatọ ya site na Febụwarị ruo Mee 2019 nke ndị na-azọ ọkwa dịka Amy Klobuchar, Bernie Sanders, Beto O'Rourke, Cory Booker, Elizabeth Warren, Joe Biden na Kirsten Gillibrand, ma kpọọ mmebi iwu ya "ihe ọjọọ, nke a ma ama, na nke na-aga n'ihu". OSC kwuru na nke a bụ oge mbụ ha "na-enye onye isi ala ọtụtụ akụkọ gbasara mmebi iwu Hatch site n'aka otu onye ahụ". <ref name="auto1">{{Cite news|url=https://www.washingtonpost.com/politics/office-of-special-counsel-recommends-removal-of-kellyanne-conway-from-federal-office-for-violating-the-hatch-act/2019/06/13/0786ae2e-8df4-11e9-8f69-a2795fca3343_story.html|title=Federal watchdog agency recommends removal of Kellyanne Conway from federal office for violating the Hatch Act|work=The Washington Post|first=Michelle Ye Hee|author=Lee|authorlink=Michelle Ye Hee Lee|date=June 13, 2019|accessdate=June 13, 2019}}</ref><ref>{{Cite web|author=Freking|first=Kevin|title=Federal Watchdog Agency Says White House Should Fire Kellyanne Conway for Violating the Hatch Act|url=https://www.apnews.com/b2f61bdd9831460b98cba45fefc9b293|work=[[Associated Press]]|date=June 14, 2019|accessdate=June 14, 2019|archivedate=June 30, 2021|archiveurl=https://web.archive.org/web/20210630005917/https://apnews.com/b2f61bdd9831460b98cba45fefc9b293}}</ref><ref>{{Cite web|author=Baker|first=Peter|title=Trump Is Urged to Fire Kellyanne Conway for Hatch Act Violations|url=https://www.nytimes.com/2019/06/13/us/politics/kellyanne-conway-hatch-act.html|work=[[The New York Times]]|accessdate=June 14, 2019|date=June 13, 2019|archivedate=October 21, 2021|archiveurl=https://web.archive.org/web/20211021063806/https://www.nytimes.com/2019/06/13/us/politics/kellyanne-conway-hatch-act.html}}</ref> N'ajụjụ ọnụ, Kerner kọwara aro ụlọ ọrụ ya dị ka ihe a na-ahụtụbeghị mbụ, na-agbakwụnye, "Ị maara ihe ọzọ a na-enwetụbeghị mbụ? Omume Kellyanne Conway. "<ref name="auto1" /> N'ihi ọnọdụ Conway dị ka onye a họpụtara dịka onye isi ala, OSC enweghị ike ime ihe ọ bụla iji mezuo aro ya, mana e nyefere ya onye isi ala maka ịtụle ya. <ref>{{Cite news|author=Sonmez|first=Felicia|title=Federal watchdog agency recommends removal of Kellyanne Conway from federal office for violating the Hatch Act|url=https://www.washingtonpost.com/politics/office-of-special-counsel-recommends-removal-of-kellyanne-conway-from-federal-office-for-violating-the-hatch-act/2019/06/13/0786ae2e-8df4-11e9-8f69-a2795fca3343_story.html|accessdate=June 13, 2019|work=[[The Washington Post]]|date=June 13, 2019|language=en}}</ref><ref>{{Cite news|author=Singman|first=Brooke|title=Special Counsel recommends firing Kellyanne Conway over alleged Hatch Act violations|url=https://www.foxnews.com/politics/special-counsel-recommends-firing-of-kellyanne-conway-over-alleged-hatch-act-violations|accessdate=June 13, 2019|work=Fox News|date=June 13, 2019}}</ref><ref>{{Cite web|author=Morin|first=Rebecca|title=All the times Kellyanne Conway ran afoul of a federal watchdog over the Hatch Act|url=https://www.usatoday.com/story/news/politics/2019/06/13/kellyanne-conway-times-trumps-counselor-ran-afoul-hatch-act/1446389001/|work=[[USA Today]]|accessdate=June 14, 2019|date=June 13, 2019|archivedate=June 24, 2021|archiveurl=https://web.archive.org/web/20210624210155/https://www.usatoday.com/story/news/politics/2019/06/13/kellyanne-conway-times-trumps-counselor-ran-afoul-hatch-act/1446389001/}}</ref> White House jụrụ nchọpụta ahụ ozugbo ma chọọ ka OSC wepụ ya.<ref>{{Cite web|url=https://www.reuters.com/article/us-usa-trump-conway-idUSKCN1TE2FI|title=Government watchdog: Trump aide Conway should be fired for...|date=June 13, 2019|work=[[Reuters]]|accessdate=June 13, 2019|archivedate=June 27, 2021|archiveurl=https://web.archive.org/web/20210627232350/https://www.reuters.com/article/us-usa-trump-conway-idUSKCN1TE2FI}}</ref> Trump kwuru na ya chere na aro ahụ "bụ ihe na-ezighị ezi, a na-akpọ ya nnwere onwe ikwu okwu" <ref>{{Cite news|url=https://www.cnn.com/2019/06/14/politics/kellyanne-conway-trump-hatch-act/index.html|title=Trump won't fire Conway despite federal agency recommendation|author=Vazquez|first=Maegan|date=June 14, 2019|work=CNN|accessdate=June 14, 2019}}</ref> Na June 26, 2019, Conway apụtaghị na mkparịta ụka nke Kọmitii Ụlọ na Nlekọta na Mgbanwe, na-eduga kọmitii ahụ ka ọ nye ya akwụkwọ ịkpọ òkù. N'oge a na-ege ntị, onye ọka iwu pụrụ iche Henry Kerner gbara akaebe na ikpe mara Conway maka mmebi iwu Hatch abụọ na 2018 na 11 na 2019. N'iji ya tụnyere, n'ime afọ asatọ nke ọchịchị Obama, ọ bụ naanị ndị ọrụ gọọmentị etiti abụọ ka a mara ikpe maka imebi Iwu Hatch, na otu mmebi nke ọ bụla.<ref>{{Cite web|author=Kwong|first=Jessica|title=Kellyanne Conway had more Hatch Act violation reports filed against her than anyone else in 30 years|url=https://www.newsweek.com/kellyanne-conway-subpoena-hatch-act-1446085|work=[[Newsweek]]|accessdate=June 27, 2019|date=June 26, 2019|archivedate=October 29, 2021|archiveurl=https://web.archive.org/web/20211029120729/https://www.newsweek.com/kellyanne-conway-subpoena-hatch-act-1446085}}</ref> ==== Michael Flynn kwuru ==== Na February 13, 2017, Conway kwuru na onye bụbu onye ndụmọdụ nchekwa mba Michael Flynn nwere "nkwado zuru oke" nke onye isi ala. Mgbe awa ole na ole gachara, Flynn gbara arụkwaghịm.[1] N'echi ya, Conway kwuru na Flynn kwuru na ya ga-agba arụkwaghịm, mana odeakwụkwọ mgbasa ozi White House Sean Spicer kwuru na Trump gwara Flynn ka ọ gbaa arụkwaghịm.[1] A kọkwara na Conway kwuru na ọ gwara ndị nta akụkọ ihe na-adịghị mma gbasara Spicer.[2] Na Febụwarị 15, ihe ngosi akụkọ MSNBC ''Morning Joe'' machibidoro Conway ka ọ pụta n'ọdịnihu. Onye isi na-eme ihe ngosi ahụ bụ Joe Scarborough kwuru na mkpebi ahụ machibidoro Conway na ihe ngosi ahụ dabere na ọ "na-apụ n'anya" na "ọ dịghị nzukọ ọ bụla dị mkpa".<ref name="morningjoe">{{Cite news|url=http://www.nydailynews.com/entertainment/tv/morning-joe-bans-trump-aide-kellyanne-conway-article-1.2973225|title="Morning Joe" bans Trump aide Kellyanne Conway: She's not credible anymore|work=New York Daily News|date=February 15, 2017|accessdate=February 19, 2017}}</ref> == Ihe omume ndị ọzọ == [[Faịlụ:Kellyane_Conway_walking_towards_the_Fiserv_Forum_on_the_final_evening_of_the_2024_RNC_IMG_9642_(1).jpg|thumb|Conway na-aga Nzukọ Mba nke Republican nke 2024]] Na 2022, Conway sonyeere Fox News dị ka onye ntinye aka.[1] Ọ pụtala ugboro ugboro dị ka onye ọbịa/onye ọbịa na mmemme dị iche iche, gụnyere Hanity, The Five, Outnumbered, The Big Weekend Show, na ndị ọzọ. Conway nyekwara aka na ntuli aka etiti oge Fox nke 2022. Conway kwadoro mmemme kwa izu nke akpọrọ Here's The Deal with Kellyanne Conway na Fox Nation site na Julaị 2024 ruo Nọvemba 2024.[2][3] N'ọnwa Eprel afọ 2022, Conway sonyeere ụlọ ọrụ America First Policy Institute. <ref>{{Cite web|title=Kellyanne Conway Joins the America First Policy Institute|url=https://americafirstpolicy.com/issues/kellyanne-conway-joins-afpi|work=America First Policy Institute|accessdate=19 July 2024|language=en|date=April 21, 2022}}</ref> N'ọnwa Nọvemba 2022, Conway gbara ajụjụ ọnụ na United States House Select Committee na Jenụwarị 6. <ref>{{Cite web|author=Nobles|first=Ryan|title=Kellyanne Conway meets with Jan. 6 committee for nearly 5 hours|url=https://www.nbcnews.com/politics/congress/kellyanne-conway-appears-jan-6-committee-rcna58963|work=NBC News|accessdate=19 July 2024|language=en|date=28 November 2022}}</ref> Na Machị 1, 2023, Conway gwara ndị ọkàiwu si n'Ọfịs onye ọka iwu distrikti Manhattan okwu dị ka akụkụ nke nyocha mpụ ha banyere Trump <ref>{{Cite web|author=Piccoli|first=Sean|title=Kellyanne Conway Meets With Prosecutors as Trump Inquiry Escalates|url=https://www.nytimes.com/2023/03/01/nyregion/kellyanne-conway-stormy-daniels-trump-inquiry.html|work=The New York Times|accessdate=19 July 2024|date=1 March 2023}}</ref> N'ọnwa Disemba afọ 2023, Conway zutere ndị Republican na-eme ntụli aka ma kwuo na ọ dị mkpa maka ha ịkwado nchebe nke ịnweta [[Ibelata ịmụ ọtụtụ ụmụ|igbochi ọmụmụ]], na-ekwu maka nkwado ọha na eze maka nchebe dị otú ahụ.<ref>{{Cite web|author=Ollstein|first=Alice Miranda|title=Contraception is a winning issue, conservative strategists tell GOP|url=https://www.politico.com/news/2023/12/13/kellyanne-conway-contraception-republicans-2024-00131410|work=Politico|accessdate=19 July 2024|date=December 13, 2023}}</ref> N'oge na-adịghị anya mgbe Ụlọikpe Kasị Elu nke Alabama wepụtara mkpebi ikpe ha na February 2024 na ''LePage v. Center for Reproductive Medicine'', ụlọ ọrụ Conway kesara ntuli aka ha mere na-egosi nkwado ọha na eze maka nchebe nke IVF na Ọgwụgwọ ọmụmụ, ọbụlagodi n'etiti ndị America na-emegide ite ime na ndị na-ekwupụta onwe ha. <ref>{{Cite web|author=Oliphant|first=James|title=Republicans, Trump try to contain backlash from Alabama fertility ruling|url=https://www.reuters.com/world/us/republicans-trump-try-contain-backlash-alabama-fertility-ruling-2024-02-23|work=Reuters|accessdate=19 July 2024|date=February 23, 2024}}</ref> N'afọ 2024, Club for Growth kwụrụ Conway ụgwọ iji kwado maka ngwa mgbasa ozi mmekọrịta TikTok na ụlọ ọrụ nne ya, ByteDance.<ref>{{Cite news|author=Lippman|first=Daniel|date=March 9, 2024|title=Kellyanne Conway advocating for TikTok on Capitol Hill|url=https://www.politico.com/news/2024/03/09/kellyanne-conway-tiktok-trump-00146144|accessdate=March 10, 2024|work=[[Politico]]}}</ref> N'ọnọdụ a, Conway gbara mbọ megide mgbalị iji gbochie ma ọ bụ manye ire TikTok n'etiti nchebara echiche nke ndị omeiwu banyere Iwu Nchebe Ndị America site na Iwu Nchịkwa Ndị Agha Mba Ọzọ. == Echiche ndọrọ ndọrọ ọchịchị == [[Faịlụ:Kellyanne_Conway_addressing_the_March_for_Life_(31864771073).jpg|thumb|Conway na-ekwu maka March for Life nke 2017 na Washington, D.C.]] Conway na-ele onwe ya anya dị ka onye na-agbaso omenala nke Generation X.<ref name="HVR">{{Cite web|url=http://www.hoover.org/research/gen-x-files|title=GEN X FILES|publisher=[[Hoover Institute]]|date=October 31, 1997|accessdate=December 29, 2016|archivedate=November 16, 2018|archiveurl=https://web.archive.org/web/20181116121810/https://www.hoover.org/research/gen-x-files}}</ref><ref name="ATL" /> Conway na-emegide ite ime, na-ekwu na 1996: "Anyị na-akwado ndụ. Nwa e bu n'afọ ahụ na-eti anyị ihe. Anyị ji sonograms too. Anyị maara ndụ mgbe anyị hụrụ ya. " Ọ kwuru okwu na March for Life nke afọ 2017, nzukọ kwa afọ na-eme mkpesa megide ite ime na Roe v. Wade.<ref name="ATL">{{Cite web|url=https://www.theatlantic.com/magazine/archive/1996/09/in-the-land-of-conservative-women/376667/|title=In the Land of Conservative Women|first=Elinor|author=Burkett|date=September 1996|accessdate=March 8, 2017|archivedate=September 6, 2021|archiveurl=https://web.archive.org/web/20210906002106/https://www.theatlantic.com/magazine/archive/1996/09/in-the-land-of-conservative-women/376667/}}</ref><ref>{{Cite news|first=Eugene|author=Scott|title=Pence, Conway cheer on March for Life|publisher=CNN|date=January 27, 2017|url=http://www.cnn.com/2017/01/27/politics/trump-march-for-life-call/|accessdate=January 28, 2017}}</ref> Ọ naghị ele onwe ya anya dị ka onye na-akwado ụmụ nwanyị "n'echiche ọdịnala", na-ekwu na ọ kwenyere na okwu ahụ nwere njikọ na ịbụ "onye na-emegide nwoke" na "onye na'na-akwado ite ime", mana ọ na-akọwa onwe ya dị ka ihe ọ na-akpọ "onye na na-akwado nwanyị".<ref>{{Cite news|url=https://www.washingtonpost.com/news/post-politics/wp/2017/02/23/kellyanne-conway-feminism-associated-with-being-anti-male-and-pro-abortion/|title=Kellyanne Conway: Feminism associated with being 'anti-male' and 'pro-abortion'|author=Wagner|first=John|date=February 23, 2017|work=[[The Washington Post]]|accessdate=December 6, 2017|language=en-US}}</ref> Conway ekwuola na ọtụtụ ndị na-ahụ maka ụmụ nwanyị anaghị anabata ụmụ nwanyị na-akwado ndụ na ndị na-agbaso omenala, nakwa na ha "na-eche banyere ihe na-eme site n'úkwù ruo n'ala... Ọ bụ mkparị. Ị maara, ọ bụ [site] n'ụ́ ruo n'elu m - anya m, ntị m, isi m, obi m, ọnụ m n'ezie". O kwukwara na "ọ dịghị onye nwere nchegbu banyere" ya na nsogbu mmekọahụ na oge ya na oge ndọrọ ndọrọ ọchịchị ya.<ref name="USA TODAY">{{Cite news|url=https://www.usatoday.com/story/news/politics/2017/03/18/kellyanne-conway-paradox/99315516/|title=Cousin: 'Kellyanne wasn't afraid of anything or anyone'|work=USA Today|accessdate=March 27, 2017|language=en}}</ref><ref>{{Cite news|url=https://www.politico.com/story/2017/12/05/kellyanne-conway-me-too-sexual-harassment-281050|title=Kellyanne Conway on her 'Me too' moment: 'Nobody cared'|work=Politico|accessdate=December 6, 2017}}</ref> == Ndụ onwe onye == Conway lụrụ George Conway, <ref>{{Cite web|title=FilAms Greet Potential Trump Pick for Solicitor General With Surprise, Skepticism|url=http://emanilamail.com/filams-greet-potential-trump-pick-solicitor-general-surprise-skepticism/|work=Manila Mail|language=en-US|accessdate=March 10, 2017|archiveurl=https://web.archive.org/web/20170214175914/http://emanilamail.com/filams-greet-potential-trump-pick-solicitor-general-surprise-skepticism/|archivedate=February 14, 2017}}</ref> onye bụ nke ndụmọdụ na ụlọ ọrụ iwu Wachtell, Lipton, Rosen &amp;amp; Katz, ma dee mkpirikpi nke Ụlọikpe Kasị Elu maka Paula Jones n'oge impeachment Clinton na 1998. <ref name="wachtellgeorgetconwayiii">{{Cite web|title=George T. Conway III|url=http://www.wlrk.com/GTConway/|work=Wachtell, Lipton, Rosen & Katz|language=en-US|accessdate=March 21, 2019|archiveurl=https://web.archive.org/web/20190225021313/http://www.wlrk.com/gtconway/|archivedate=February 25, 2019}}</ref><ref name="auto">{{Cite news|title=Trump considers Kellyanne Conway's husband for top US lawyer job|url=http://www.nydailynews.com/news/national/trump-considers-kellyanne-conway-husband-top-lawyer-job-article-1.2929257|work=NY Daily News|language=en-US|accessdate=March 27, 2017}}</ref> Di na nwunye mbụ ahụ nwere ụmụ anọ: ejima Claudia na George IV, Charlotte, na Vanessa.<ref name="auto" /> Tupu Trump bụrụ onye isi ala, ha biri na Alpine, New Jersey.<ref name="conwaybio">{{Cite web|url=http://pollingcompany.com/about/kellyanne/|title=Kellyanne Conway biography|publisher=pollingcompany.com|author=The Polling Company|date=2016|archiveurl=https://web.archive.org/web/20160430223824/http://pollingcompany.com/about/kellyanne/|archivedate=April 30, 2016|access-date=March 27, 2026|url-status=dead}}<cite class="citation web cs1 cs1-prop-unfit" data-ve-ignore="" id="CITEREFThe_Polling_Company2016">The Polling Company (2016). . pollingcompany.com. Archived from the original on April 30, 2016.</cite> [[Category:CS1: unfit URL]]</ref><ref name="CSMO">{{Cite web|author=Sebastian|first=Michael|date=January 22, 2017|title=Who Is Kellyanne Conway? 13 Things to Know About Donald Trump's Presidential Counselor.|url=http://www.cosmopolitan.com/politics/news/a62994/kellyanne-conway-trump-new-campaign-manager/|work=Cosmopolitan|language=en-US|accessdate=January 23, 2017|archivedate=January 20, 2017|archiveurl=https://web.archive.org/web/20170120185202/http://www.cosmopolitan.com/politics/news/a62994/kellyanne-conway-trump-new-campaign-manager/}}</ref><ref>{{Cite news|author=Johnson|first=Brent|date=November 9, 2016|title=How N.J. native Conway got Trump over the finish line|url=https://www.nj.com/politics/2016/11/whats_next_for_conway_trumps_nj-bred_campaign_mana.html|publisher=NJ Advance Media|work=[[NJ.com]]|language=en-US|accessdate=November 9, 2016|quote=Conway, who grew up in the Atco section of Waterford Township in Camden County, was hired in August, at a time when Trump was suffering from gaffes and drooping poll numbers... Conway, her husband, and her four children now live in the northern part of the state, in Alpine in Bergen County.}}</ref> Tupu alụmdi na nwunye ya, Conway na onye omeiwu Fred Thompson. George Conway bụ onye nkatọ nke Trump; na Disemba 2019 o guzobere Lincoln Project, nke mere mkpọsa megide nhọpụta ọzọ nke Trump site n'echiche ndị na-achọghị mgbanwe.<ref>{{Cite news|title=Republican election strategists launch anti-Trump project ahead of 2020|url=https://www.axios.com/never-trump-republicans-lincoln-project-2020-george-conway-47c487d2-a88c-4178-b25c-8683d008fb40.html|work=Axios|language=en-US|date=December 17, 2019|accessdate=January 10, 2020}}</ref> Na Machị 2019, Trump zaghachiri nkatọ sitere n'aka di Kellyanne George site n'ịkọwa George dị ka "LOSER na di si na hel".<ref>{{Cite news|author=Wagner|first=John|date=March 20, 2019|title='Husband from hell!': Trump escalates feud with spouse of Kellyanne Conway, says he's hurting his family|url=https://www.washingtonpost.com/politics/husband-from-hell-trump-escalates-feud-with-spouse-of-kellyanne-conway/2019/03/20/587a03d8-4b07-11e9-93d0-64dbcf38ba41_story.html|work=The Washington Post|language=en-US|accessdate=December 17, 2019}}</ref> Kellyanne gbachitere Trump site n'ikwu na George Conway "abụghị onye isi mgbaka" nakwa na ekwesighi ịtụ anya na Trump ga-azaghachi mgbe George, "onye ọkachamara na-abụghị dọkịta na-ebo ya ebubo na o nwere isi mgbaka". <ref>{{Cite web|author=Lippman|first=Daniel|date=March 20, 2019|title=Kellyanne Conway defends Trump after he attacked her husband|url=https://www.politico.com/story/2019/03/20/kellyanne-george-conway-trump-1229193|work=Politico|language=en-US|accessdate=March 22, 2019|archivedate=February 13, 2021|archiveurl=https://web.archive.org/web/20210213105321/https://www.politico.com/story/2019/03/20/kellyanne-george-conway-trump-1229193}}</ref> Nwa nwanyị Conway bụ Claudia bụ onye nwere mmetụta TikTok nke a maara na 2020, mgbe ọ dị afọ 15, maka ozi ya na-emegide Trump. <ref name="DarbyGQ">{{Cite web|author=Darby|first=Luke|date=June 30, 2020|title=Kellyanne Conway's Kid Is an Anti-Trump Leftist TikTokker|url=https://www.gq.com/story/kellyanne-conway-daughter-tiktok|work=GQ|language=en-US|accessdate=July 4, 2020|archivedate=March 6, 2021|archiveurl=https://web.archive.org/web/20210306203754/https://www.gq.com/story/kellyanne-conway-daughter-tiktok}}</ref><ref name="Santucci CC">{{Cite web|author=Santucci|first=Jeanine|title=Kellyanne Conway's teen daughter hopes to help 'educate' with TikToks opposing Trump, supporting Black Lives Matter|url=https://eu.usatoday.com/story/news/politics/2020/06/30/kellyanne-conways-teen-daughter-claudia-posts-anti-trump-videos/3285180001/|work=USA Today|language=en-US|accessdate=July 4, 2020|archivedate=August 16, 2021|archiveurl=https://web.archive.org/web/20210816222250/https://eu.usatoday.com/story/news/politics/2020/06/30/kellyanne-conways-teen-daughter-claudia-posts-anti-trump-videos/3285180001/}}</ref><ref name="EvansDeadline">{{Cite web|author=Evans|first=Greg|date=July 3, 2020|title=George & Kellyanne Conway Tell Journalists To Stay Away From Daughter Claudia; She Doesn't Take It Well|url=https://deadline.com/2020/07/claudia-conway-george-kellyanne-twitter-sorry-marriage-failed-1202977251/|work=Deadline|language=en-US|accessdate=July 4, 2020|archivedate=January 27, 2021|archiveurl=https://web.archive.org/web/20210127021534/https://deadline.com/2020/07/claudia-conway-george-kellyanne-twitter-sorry-marriage-failed-1202977251/}}</ref> Claudia na-akọwa onwe ya dị ka onye aka ekpe na onye nnwere onwe ya ma kọwaa ndị na-akwado TikTok ya dị ka "onye aka ekpe, A.C.A.B. (All Cops Are Bastards), onye na-emegide trump, (Black Lives Matter) ".<ref>{{Cite web|author=Perrett|first=Connor|date=June 20, 2020|title=Kellyanne Conway's 15-year-old daughter is defiantly posting anti-Trump and pro-Black Lives Matter TikToks 'to inform people and spread love'|url=https://www.insider.com/claudia-conway-posting-anti-trump-tiktoks-2020-6|work=Insider|language=en-US|accessdate=July 4, 2020|archivedate=November 7, 2021|archiveurl=https://web.archive.org/web/20211107141312/https://www.insider.com/claudia-conway-posting-anti-trump-tiktoks-2020-6}}</ref><ref>{{Cite web|author=Neumann|first=Sean|date=July 14, 2020|title=Kellyanne Conway's Daughter Became an Anti-Trump TikTok Star|url=https://people.com/politics/kellyanne-conway-teenage-daughter-claudia-anti-trump-tiktok/|work=People|language=en-US|accessdate=July 4, 2020|archivedate=January 26, 2021|archiveurl=https://web.archive.org/web/20210126125639/https://people.com/politics/kellyanne-conway-teenage-daughter-claudia-anti-trump-tiktok/}}</ref><ref name="Alter Vulture">{{Cite web|author=Alter|first=Rebecca|date=July 2020|title=Kellyanne Conway's Only Good Contribution to the World Is Her TikToker Daughter|url=https://www.vulture.com/2020/07/kellyanne-conway-daughter-claudia-tiktok.html|work=Vulture|language=en-US|accessdate=July 4, 2020|archivedate=March 9, 2021|archiveurl=https://web.archive.org/web/20210309031659/https://www.vulture.com/2020/07/kellyanne-conway-daughter-claudia-tiktok.html}}</ref> Claudia na Kellyanne kewapụrụ onwe ha n'otu oge mana ha emeela ka ọ dịghachi mma na 2024. <ref>{{Cite news|author=Janfaza|first=Rachel|date=October 10, 2024|title=Claudia Conway Declares Her Independence|url=https://www.nytimes.com/2024/10/10/style/claudia-conway-gen-z-voters-politics.html|work=The New York Times|language=en-US|accessdate=29 August 2025}}</ref> Otu n'ime ndị ọrụ White House ole na ole nwere nchebe Secret Service n'ihi egwu dị iche iche, Conway họọrọ "Blueberry" dị ka aha nzuzo ya n'ihi njikọ ya na mkpụrụ osisi ahụ site na ntorobịa ya na mmemme na ịghọrọ mkpụrụ osisi. N'abalị iri abụọ na atọ n'ọnwa Ọgọstụ afọ 2020, Conway kwupụtara ọpụpụ ya iji "na-etinye oge ka ukwuu na ezinụlọ ya," <ref>{{Cite web|title=Kellyanne Conway, counselor to the president, announces departure from White House to focus on family|url=https://www.cbsnews.com/news/kellyanne-conway-anounces-white-house-departure/|work=CBS News|language=en-US|date=August 24, 2020|accessdate=January 23, 2023|archivedate=January 11, 2021|archiveurl=https://web.archive.org/web/20210111115210/https://www.cbsnews.com/news/kellyanne-conway-anounces-white-house-departure/}}</ref> dị ka di ya George, onye kwupụtara na ọ wepụrụ oge na Lincoln Project na Twitter. <ref>{{Cite web|author=LeBlanc|first=Paul|date=August 24, 2020|title=Kellyanne Conway announces she's leaving the White House|url=https://www.cnn.com/2020/08/23/politics/kellyanne-conway-george-conway-white-house-lincoln-project/index.html|work=CNN|language=en-US|accessdate=August 24, 2020|archivedate=February 15, 2021|archiveurl=https://web.archive.org/web/20210215215114/https://www.cnn.com/2020/08/23/politics/kellyanne-conway-george-conway-white-house-lincoln-project/index.html}}</ref> Na Machị 2023, George na Kellyanne kwupụtara na ha na-agba alụkwaghịm mgbe afọ 22 nke alụmdi na nwunye gasịrị. <ref>{{Cite news|author=Floyd|first=Thomas|date=March 4, 2023|title=Kellyanne Conway and George Conway confirm they are divorcing|url=https://www.washingtonpost.com/lifestyle/2023/03/04/kellyanne-conway-george-conway-divorce/|work=The Washington Post|language=en-US|accessdate=March 26, 2026}}</ref> {| class="wikitable" !Afọ !Ihe nrite !Ụdị !Ọrụ ndị a họpụtara !Nsonaazụ !Ref. |- |2019 |Ihe nrite Golden Raspberry nke iri atọ na itoolu |Onye na-eme ihe nkiri kachasị njọ |''Fahrenheit 11/9''| {{Won}} |<ref>{{Cite web|date=February 24, 2019|title=Razzie Awards: Donald Trump Wins Worst Actor For Performances As Himself|url=https://www.huffingtonpost.in/entry/donald-trump-wins-razzie-awards-2019_in_5c723246e4b00eed083500c3|accessdate=March 4, 2021|work=HuffPost|language=en|archivedate=August 3, 2020|archiveurl=https://web.archive.org/web/20200803090820/https://www.huffingtonpost.in/entry/donald-trump-wins-razzie-awards-2019_in_5c723246e4b00eed083500c3}}</ref> |} == Akwụkwọ == N'afọ 2005, Conway na onye nyocha nke Democratic Celinda Lake so dee What Women Really Want: How American Women Are Siletly Ehiching Political, Racial, Class, and Religious Lines to Change the Way We Live (Free Press/Simon & Schuster, 2005; ).  N'afọ 2022, Conway dere Here's the Deal: A Memoir (Threshold Editions, 2022; ).  == Edensibia == {{Reflist|30em}} == Njikọ mpụga == [[Otú:Mmadụ ndi di ndụ]] [[Otú:Pages with unreviewed translations]] otkjspclwd5tilqdwbgsban979u2n25 Farah Abdullahi Abdi 0 79114 736817 735232 2026-10-07T16:59:46Z InternetArchiveBot 11600 Rescuing 2 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736817 wikitext text/x-wiki <templatestyles src="Module:Infobox/styles.css"></templatestyles>  '''Farah Abdullahi Abdi''' (amụrụ na 21 Julaị 1995 na Beledweyne) bụ onye na-ahụ maka ihe ndị ruuru mmadụ. Ọ bụ onye gbara ọsọ ndụ si Somalia <ref name="world forum democracy 2016"/> na onye isi iwu maka ebe mgbaba ndị gbara ọsọ ndụ yana nkwagharị n'ụlọ ọrụ Transgender Europe. <ref name="europride program"/> == Mmalite Ndụ Ya na ịgbaga Malta == Farah na ndị mụrụ ya na nwanne ya nwoke gbapụrụ n'agha dị na Somalia mgbe ọ dị afọ atọ.<ref name="maltatoday"/> Ezinụlọ ya bu ụzọ nọrọ n'ogige ndị gbara ọsọ ndụ ma mechaa ha akwaga n'isi obodo.<ref name="ratsch-menke">{{Cite web|author=Ratsch-Menke|first=Britta|title=Laudatio für Farah Abdullahi Abdi|url=https://dieschwelle.de/fileadmin/user_upload/Bilder_Dokumente/Friedenspreis/Laudatio/2015_Farah_Abdi_Laudatio.pdf|work=dieschwelle.de|publisher=dieschwelle|accessdate=23 September 2023}}</ref> Ọ tolitere na Nairobi, Kenya. Nna ya bụ onye na-ekpe Alakụba. Ezinụlọ ahụ nọ na-ekpe ekpere ma na-agụ Koran mgbe niile. Farah kọwara ndị mụrụ ya dị ka ndị na-agbaso omenala na ndị na-arụsi ọrụ ike. Ọ tolitere n'ogo akụnaụba etiti. Ọ kọwara nne ya na nne nne ya, ndị ya na ezinụlọ ahụ bi na Nairobi, dị ka ndị na-akwalite mmetụta siri ike nke uru onwe onye n'ime ya site na nwata. Nne na nna ya nyere ya na nwanne ya nwoke ezigbo agụmakwụkwọ. Farah tolitere na-asụ asụsụ atọ, na-asụ Bekee na [[Swahili language|Swahili]], na-asụkwa [[Asusu Somali|Somalia]] na ezinụlọ ya n'ụlọ. Ọ zochiri mmasị ya na egwu, ọdịbendị America, ejiji na ime ihe nkiri pụọ n'aka ezinụlọ ya ma mesịa zoo mmekọahụ ya na nkwenye njirimara nwoke na nwanyị ya.<ref name="ratsch-menke" /> N'ihi na a nabataghị ya maka ịbụ nwoke na-edina nwoke nakwa nwoke na-edina nwanyị ma ọ bụ nwoke na-agbanwe ghọọ nwanyị, ọ gbapụrụ ọzọ mgbe ọ dị afọ iri na isii site na Uganda, South Sudan, Sudan na Libya gaa Malta. N'oge ịgba ọsọ ahụ, a tụrụ ya mkpọrọ ugboro ise, mekpọọ ya ọnụ ma metọọ ya ma manye ya ịrụ ọrụ n'akwụghị ụgwọ na ebe a na-ewu ihe na Libya. Ọnụ ego nke ịgbapụ site na Kenya gaa Malta bụ puku dọla iri na abụọ ka o furu ezinụlọ ya.<ref name="weser kurier"/> Abdi rutere Malta n'afọ 2012. Ọ gbapụrụ na Somalia site na Libya wee jiri ụgbọ mmiri bịa Malta.<ref name="world forum democracy 2016">{{Cite web|title=Farah ABDI|url=https://www.coe.int/en/web/world-forum-democracy/2016-speakers/-/asset_publisher/JTQ3V5aITSo7/content/abdi-farah|accessdate=23 September 2023|work=Council of Europe|publisher=}}<cite class="citation web cs1" data-ve-ignore="">[https://www.coe.int/en/web/world-forum-democracy/2016-speakers/-/asset_publisher/JTQ3V5aITSo7/content/abdi-farah "Farah ABDI"]. ''Council of Europe''<span class="reference-accessdate">. Retrieved <span class="nowrap">23 September</span> 2023</span>.</cite></ref> Onye dị afọ iri na isii, e jidere Abdi nwa oge mgbe ọ rutere Malta n'agbanyeghị ọnọdụ ya dị ka onye na-eto eto.<ref>{{Cite web|date=2016-05-15|title=Journey of a Somali youngster|url=https://timesofmalta.com/article/journey-of-a-somali-youngster.612171|accessdate=2024-04-01|work=Times of Malta|language=en-gb}}</ref> Mgbe oge ụfọdụ gasịrị, ọ gwara onye na-agwọ ya ọrịa banyere mkpagbu ọ na-enwe maka mmekọahụ na okike ya na mba ya nke mere e ji hapụ ya. Mgbe ọ bịarutere, Abdi rụrụ ọrụ dị ka onye ntụgharị asụsụ maka NGO na ụlọ oriri na ọṅụṅụ dị na Senglea.<ref name="maltatoday">{{Cite web|title=Farah Abdi|url=https://www.maltatoday.com.mt/author/farah_abdi/|accessdate=23 September 2023|work=Malta Today}}<cite class="citation web cs1" data-ve-ignore="">[https://www.maltatoday.com.mt/author/farah_abdi/ "Farah Abdi"]. ''Malta Today''<span class="reference-accessdate">. Retrieved <span class="nowrap">23 September</span> 2023</span>.</cite></ref> == Nkwuchite-ọnụ == Abdi malitere ịrụ ọrụ dị ka onye na-ede akwụkwọ akụkọ maka akwụkwọ akụkọ Maltese bụ ''[[:en:Malta_Today|Malta Today]]''. <ref name="maltatoday"/> O dere banyere mmeso ọjọọ na nsogbu nke ndị mbịarambịa na Malta na-eche ihu ma bụrụ onye a ma ama karịsịa n'etiti ndị mbịarambịa nke mba ahụ. Farah kwupụtara na ha nọ ebe ahụ "ịrụ ọrụ ma nye aka na mmepe obodo".<ref name="weser kurier">{{Cite web|author=Schaefer|first=York|title=Bremer Friedenspreis für Flüchtlingsaktivist|url=https://www.weser-kurier.de/bremen/bremer-friedenspreis-fuer-fluechtlingsaktivist-doc7e4h1vt2qd195z7hd1o|work=weser kurier|accessdate=23 September 2023}}<cite class="citation web cs1" data-ve-ignore="" id="CITEREFSchaefer">Schaefer, York. [https://www.weser-kurier.de/bremen/bremer-friedenspreis-fuer-fluechtlingsaktivist-doc7e4h1vt2qd195z7hd1o "Bremer Friedenspreis für Flüchtlingsaktivist"]. ''weser kurier''<span class="reference-accessdate">. Retrieved <span class="nowrap">23 September</span> 2023</span>.</cite></ref> Ndị na-emegide mbata na ọpụpụ katọrọ ya maka ikwu okwu n'ezoghị ọnụ.<ref name="dieschwelle">{{Cite web|title=Für die Rechte von Flüchtlingen in Europa: Farah Abdullahi Abdi|url=https://dieschwelle.de/friedenspreis-2015/farah-abdullahi-abdi|work=dieschwelle.de|accessdate=23 September 2023}}</ref> N'afọ 2014, Farah kwuru okwu n'ihu ndị omeiwu Europe na nkwado nke nzukọ [[:en:Terre_des_hommes|terre des hommes]] n'oge ihe omume "A maghị ebe m na-aga" ma rịọ maka nchebe nke ụmụaka na ụmụaka gbara ọsọ ndụ. Kọmishọna Europe Cecilia Malmström kwuru na ọ ga-ekwe omume n'ụzọ iwu kwadoro maka ụmụaka na ndị gbara ọsọ ndụ na-eto eto ịkwaga na European Union.<ref name="reliefweb">{{Cite web|title=From chains to freedom: why I decided to migrate to Europe|url=https://reliefweb.int/report/world/chains-freedom-why-i-decided-migrate-europe|work=reliefweb|date=20 February 2014|accessdate=23 September 2023}}</ref> O bipụtara akụkọ ndụ onwe ya, Never Arrive, na 2015.<ref name="unhcr">{{Cite web|title=Book reading of Never Arrive|url=https://www.unhcr.org/mt/3228-book-reading-never-arrive.html|accessdate=23 September 2023|work=UNHCR}}</ref> N'afọ 2023, Abdi kwuru okwu na LGBTIQ+ Human Rights Conference, akụkụ nke [[:en:EuroPride|EuroPride]]. <ref name=":0"/> == Ịkwaga Berlin == Farah Abdi mechara si Malta kwaga Berlin, n'ihi ịkpa ókè agbụrụ o chere ihu na Malta.<ref name=":0">{{Cite web|date=2023-09-13|title=Common EU migration policy will harm LGBTIQ asylum seekers - activist|url=https://timesofmalta.com/article/common-eu-migration-policy-harm-lgbtiq-asylum-seekers-activist.1054993|accessdate=2024-04-01|language=en-gb}}<cite class="citation web cs1" data-ve-ignore="">[https://timesofmalta.com/article/common-eu-migration-policy-harm-lgbtiq-asylum-seekers-activist.1054993 "Common EU migration policy will harm LGBTIQ asylum seekers - activist"]. ''Times of Malta''. 13 September 2023<span class="reference-accessdate">. Retrieved <span class="nowrap">1 April</span> 2024</span>.</cite></ref> Na Berlin, Abdi na-arụ ọrụ ugbu a dị ka onye na-ahụ maka ebe mgbaba ndị gbara ọsọ ndụ na onye mgbasa ozi n'ụlọ ọrụ Transgender Europe. Ọ bụ onye otu Alfred Landecker Foundation for Democracy, onye otu Torschreiber Foundation maka ndị edemede nọ n'ebe a chụgara ha ma natakwa "Digital Europe fellowship" maka ịkwalite ọchịchị onye kwuo uche ya n'ịntanetị.<ref name="humanity in action">{{Cite web|title=Farah Abdi|url=https://humanityinaction.org/person/farah-abdi/|accessdate=7 October 2023|work=Humanity in Action|publisher=}}</ref> == Ndụ onwe onye == Abdi bụ onye Alakụba na nwanyị gbanwere ghọọ nwoke.<ref name="europride program">{{Cite web|title=Program Europride 2023|url=https://europride2023.mt/lgbtiqconf/programme/|work=europride2023.mt|accessdate=23 September 2023|archivedate=22 September 2023|archiveurl=https://web.archive.org/web/20230922091626/https://europride2023.mt/lgbtiqconf/programme/|url-status=dead}}<cite class="citation web cs1" data-ve-ignore="">. ''europride2023.mt''. Archived from [https://web.archive.org/web/20230922091626/https://europride2023.mt/lgbtiqconf/programme/ the original] on 22 September 2023<span class="reference-accessdate">. Retrieved <span class="nowrap">23 September</span> 2023</span>.</cite></ref> == Ihe nrite Ndị O Nwetara == * Ihe nrite International Bremen Peace Award sitere na German NGO, Stiftung "die Schwelle" <ref name="weser kurier"/> * Onyinye Eze Nwanyị nke England maka ndị isi na-eto eto * Ihe nrite Forbes mmadụ iri atọ na-erubeghị afọ iri atọ na Europe 2017 <ref name="forbes">{{Cite web|title=Farah Abdi|url=https://www.forbes.com/profile/farah-abdi/?sh=2457b81a7d2b|work=Forbes|accessdate=7 October 2023}}</ref> == Akwụkwọ ndị O bipụtara == * {{Cite book|author=Abdi|first=Farah Abdullahi|title=Never Arrive|url=https://archive.org/details/neverarrive0000abdi|year=2015|isbn=9789995709006}} == Edensibịa == {{Reflist}} <templatestyles src="Reflist/styles.css" />  [[Otú:Mmadụ ndi di ndụ]] [[Otú:Articles with hCards]] [[Otú:Pages with unreviewed translations]] 96hwojw3p6sugzfat6eexdex2u5sk6u Ikike Mgbochi Ọrịa (ọgwụ) 0 79140 736830 735303 2026-10-08T00:59:47Z InternetArchiveBot 11600 Rescuing 2 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736830 wikitext text/x-wiki Na nkà mmụta ihe ndị dị ndụ, ikike mgbochi ọrịa bụ ọnọdụ nke ịbụ onye na-adịghị anabata ma ọ bụ onye na-eguzogide ihe ma ọ bụ usoro na-emerụ ahụ, ọkachasị nje na-akpata ọrịa ma ọ bụ Ọrịa na-efe efe. Ikike mgbochi ọrịa nwere ike ime n'ụzọ ebumpụtaụwa ma ọ bụ e mepụta ya site na inweta ya enweta ma ọ bụ ịgba ọgwụ mgbochi. == Nke Ebumpụtaụwa na nke E nwetara Enweta == [[Faịlụ:Fc_receptor_schematic_big.png|thumb|Atụmatụ nke Onye na-anabata Fc]] [[:en:Immune_system|Usoro ahụ ji alụso ọrịa ọgụ]] nwere [[:en:Innate_immune_system|ndị e bu pụta ụwa]] na ndị a na-enweta enweta. Ikike mgbochi ọrịabu nke ebumpụtaụwa dị na [[Animal|Metazoans]] niile, <ref>{{Cite journal|title=Molecules, cells, and tissues of immunity|journal=Immunology Guidebook|date=1 January 2004|pages=1–15|doi=10.1016/B978-012198382-6/50025-X}}</ref> mmeghachi omume nke nguzogide ọrịa: [[:en:Inflammation|ọzịza nke akụkụ ahụ ọbụla]] na phagocytosis. Akụkụ ya bụ nke e nwetara enweta, n'aka nke ọzọ, na-agụnye mkpụrụ ndụ [[:en:Lymphocyte|lymphatic]] dị elu karị nke nwere ike ịmata ọdịiche dị n'etiti ihe "ndị na-esighi n'ahụ" ndị dị "n'ahụ". A na-akọwa mmeghachi omume nye ihe ndị na-esighi na ahụ dị ka ọzịza ebe a na-akọwakarị adịghị mmeghachi omume na-eme nye ihe ndị si n'ahụ dị ka nguzogide ọrịa. Akụkụ abụọ a nke usoro ahụ ji alụso ọrịa ọgụ na-emepụta gburugburu ebe obibi dị ike ebe a pụrụ ịhụ "ahụike" dị ka ọnọdụ anụ ahụ ebe a na-echebe onwe onye, wee wepụ ihe dị batara abata site n'ụzọ ọzịza na usoro ahụ ji alụso ọrịa ọgụ. "Ọrịa" nwere ike ibilite mgbe a na-enweghị ike iwepụ ihe ndị batara abata n'ahụ ma ọ bụ ihe ndị dị n'ahụ adịghị nchekwa.<ref>{{Cite journal|title=Innate immunity|journal=The Journal of Allergy and Clinical Immunology|volume=125|issue=2 Suppl 2|pages=S24-32|date=February 2010|pmid=19932920|doi=10.1016/j.jaci.2009.07.016}}</ref> Ikike mgbochi ọrịa ebumpụtaụwa, nke a makwaara dị ka ikike mgbochi ọrịa ọnatarachi, bụ ụdị mgbochi ọrịa bụ n'otu akụkụ kpọmkwem maka ụfọdụ nje na-ebute ọrịa na nke a na-ekesa n'ọtụtụ ebe. A na-akọwa ya dị ka akara mbụ nke nchebe megide nje ndị na-ebute ọrịa, na-anọchite anya nzaghachi dị oke egwu nke usoro ahụ iji gbochie ọrịa na ịnọgide na-enwe homeostasis, na-enye aka n'ịrụ ọrụ nke usoro ahụ ji alụso ọrịa ọgụ e nwetara enweta.<ref>{{Cite journal|title=Innate immunity in vertebrates: an overview|author=Riera Romo|first=M.|journal=Immunology|year=2016|volume=146|issue=2|pages=125–139|doi=10.1111/imm.12597|pmid=26878338}}</ref> Ọ naghị emeghachi omume nye ihe ụfọdụ na-akpali akpali ma ọ bụ ọrịa gara aga, mana ọ na-adabere na njirimara mkpụrụ ndụ ihe nketa nke usoro ụfọdụ.<ref name=":0">{{Cite journal|title=Pathogen recognition and innate immunity|url=https://archive.org/details/cell_2006-02-24_124_4/page/783|language=en|journal=Cell|volume=124|issue=4|pages=783–801|date=February 2006|pmid=16497588|doi=10.1016/j.cell.2006.02.015}}</ref> Ikike mgbochi ọrịa e nwetara enweta bụ akụkụ nke ọzọ na-arụ ọrụ nke ikike ahụ ji alụso ọrịa ọgụ bu nke ebumpụtaụwa, nke [[:en:Lymphocytes|lymphocytes]] na-elekwasị anya kpọmkwem na antigens na-achịkwa. N'adịghị ka ikike mgbochi ọrịa ebumpụta ụwa, ikike mgbochi ọrịa a na-enweta enweta bụ nke a kapịrị ọnụ maka otu nje na-akpata ọrịa, gụnyere mmepe nke [[:en:Immunological_memory|ncheta mgbochi ọrịa]]. Dị ka usoro nke ebumpụta ụwa, usoro e nwetara enweta na-agụnye ma ihe ndị na-egbochi ọrịa humoral na ihe ndị na'egbochi ọrịa cell.   <sup class="noprint Inline-Template Template-Fact" style="white-space:nowrap;">&#x5B;''[[wikipedia:Tinye edensibịa|<span title="This claim needs references to reliable sources. (April 2022)">citation needed</span>]]''&#x5D;</sup> Enwere ike inweta ikike mgbochi ọrịa nke a na-enweta enweta ma ọ bụ 'n'ụzọ okike' (site na ọrịa) ma ọ bụ "n'ụzọ aka mere" (site na [[:en:Artificial_induction_of_immunity|omume ndị a kpachapụrụ anya mee]] dị ka ịgba ọgwụ mgbochi). A pụkwara ịhazi ikike mgbochi ọrịa nke a na-enweta enweta dị ka 'nke na-arụ ọrụ' ma ọ bụ 'nke na-adịghị arụ ọrụ'. A na-enweta ikike mgbochi ọrịa nke na-arụ ọrụ site na ikpughe onwe onye nye nje na-ebute ọrịa, nke na-akpali mmepụta nke ihe ndị na-alụso ọrịa ọgụ n'ime ahụ.<ref>{{Cite web|url=https://www.cdc.gov/vaccines/vac-gen/immunity-types.htm|work=cdc.gov|title=Immunity types|date=2 November 2021|publisher=Centers for Disease Control and Prevention (CDC)}}</ref> A na-enweta ikike mgbochi ọrịa nke na-adịghị arụ ọrụ site na nnyefe nke ihe ndị na-alụso ọrịa ọgụ ma ọ bụ mkpụrụ ndụ T na-arụ ọrụ nke sitere na onye na-alụ ọgụ ma ọ bụ site n'ụzọ aka mere ma ọ bụ site na placenta; ọ na-adị ndụ mkpụmkpụ, na-achọ [[:en:Booster_dose|booster doses]] maka ikike mgbochi ọrịa na-adị gawa n'ihu. Ihe osise dị n'okpuru ebe a chịkọtara nkewa ndị a nke ikike mgbochi ọrịa. Ikike mgbochi ọrịa nke a na-enweta enweta na-amata usoro dịgasị iche iche. N'adịghị ka ikike mgbochi ọrịa nke ebumpụta ụwa, ọ na-ejikọta ya na ncheta nke nje ahụ na-ebute ọrịa.<ref name=":0"/> [[Faịlụ:Immunity.svg|center|600x600px]] == Akụkọ ihe mere eme Nke Echiche Dị Iche Iche Gbasara Ya == [[Faịlụ:Cholera_art.jpg|thumb|Ihe ngosi nke ọrịa ntiwapụ ọrịa ọgbụgbọ na ọnyụnyụ na narị afọ nke iri na itoolu]] Kemgbe ọtụtụ puku afọ, ihe a kpọrọ mmadụ enweela mmasị na ihe na-akpata ọrịa na echiche nke ikike ahụ ji egbochi ọrịa. Echiche tupu akụkọ ihe mere eme bụ na ọ bụ ike karịrị mmadụ kpatara ọrịa, nakwa na ọrịa bụ ụdị ntaramahụhụ [[:en:Theurgy|theurgic]] maka "omume ọjọọ" ma ọ bụ "echiche ọjọọ" nke ndị bụ chi ma ọ bụ ndị iro mmadụ tinyere na mkpụrụ obi. <ref name="Rhodes">{{Cite web|work=Disease and Immunity|date=Spring 2006|publisher=Rhodes College|url=http://www.rhodes.edu/biology/glindquester/disimm/history.html|title=Introduction to the History of disease.|archiveurl=https://web.archive.org/web/20060721232232/http://www.rhodes.edu/biology/glindquester/disimm/history.html|archivedate=2006-07-21}}</ref> N'oge ndị Gris oge ochie, Hippocrates, onye a na-ewere dị ka Nna nke Ọgwụ, kwuru na ọrịa sitere na mgbanwe ma ọ bụ enweghị nkwekọ nke [[:en:Four_humors|otu n'ime ihe anọ ahụ mejupụtara mmadụ]] (ọbara, phlegm, mgbiilu odo odo ma ọ bụ mgbiilu ojii). <ref name="Silverstein"/> Nkọwa mbụ e dere ede nke echiche nke ikike mgbochi ọrịa nwere ike ịbụ nke onye [[Atens]] Thucydides mere, onye, na 430 BC, kọwara na mgbe ihe otiti ahụ dakwasịrị [[:en:Athens|Athens]]: "ndị ọrịa na ndị na-anwụ anwụ ka a nọ na-elekọta site na nlekọta ọmịiko nke ndị gbakere, n'ihi na ha maara usoro ọrịa ahụ ma ha onwe ha enweghị egwu ya. "<ref name="Gheradi"/> Ọgwụ mgbochi ọrịa nwere ike ịmalite na [[:en:Mithridates_VI_of_Pontus|Mithridates VI nke Pontus]] (120-63 BC) <ref name="Maleissye">{{Cite book|title={Histoire du poison}|author=Jean Tardieu de Maleissye|year=1991|location=Paris|publisher=Francois Bourin|isbn=2-87686-082-1|language=fr}}</ref> onye, iji mee ka ọgwụ mgbochi ọrịa dị ike maka nsí agwọ, tụrụ aro iji usoro yiri nke Ọgwụgwọ serum Toxoid nke oge a, site na ịṅụ ọbara nke ụmụ anụmanụ na-eri agwọ na-egbu egbu. A na-ahụta ya na ọ na-eche na anụmanụ ndị ahụ nwetara ụfọdụ ikike iwepụ nsị, nke ga-eme ka ọbara ha nwee nsị agwọ ahụ n'ụdị a gbanwere agbanwe nke nwere ike ime ka o guzogide ya kama inwe mmetụta na-egbu egbu. Mithridates chere na, site na ịṅụ ọbara nke anụmanụ ndị a, ọ nwere ike inweta nguzogide yiri nke ahụ.<ref name="Maleissye" /> N'ịtụ egwu nsí igbu ya, ọ nọ na-aṅụ ọgwụ na-egbu egbu n'ụdị na-esichaghị ike kwa ụbọchị iji mee ka nnagide dị mma. A na-ekwukwa na ọ gbalịrị ịmepụta 'ọgwụgwọ zuru ụwa ọnụ' iji chebe ya pụọ na nsí niile.<ref name="Silverstein"/><ref>{{Cite journal|author=Mayor|first=Adrienne|title=Mithridates of Pontus and His Universal Antidote|journal=Toxicology in Antiquity|date=2019|pages=161–174|doi=10.1016/B978-0-12-815339-0.00011-1}}</ref> Ruo ihe fọrọ nke nta ka ọ bụrụ afọ puku abụọ, a nọ na-eche na nsí bụ [[:en:Proximate_causation|ihe na-akpata ọrịa]], nke a na-ejikwa ngwakọta dị mgbagwoju anya nke ihe dị iche iche, nke a na-akpọ Mithridate, gwọọ nsí n'oge [[:en:Renaissance|Renaissance]]. <ref name="Silverstein" /><ref>{{Cite book|author=Chambers|first=Ephraim|title=History of Science: Cyclopædia|date=1728|location=London|url=http://digicoll.library.wisc.edu/cgi-bin/HistSciTech/HistSciTech-idx?type=turn&id=HistSciTech.Cyclopaedia02&entity=HistSciTech.Cyclopaedia02.p0210&q1=Mithridate|accessdate=4 October 2020|chapter=Mithridate}}</ref> E jiiri ụdị ọgwụgwọ a emelitere, Theriacum Andromachi, mee ihe ruo na narị afọ nke iri na itoolu. A na-ahụkwa okwu ahụ bụ "immunes" n'abụ uri "[[:en:Pharsalia|Pharsalia]]" nke onye na-ede uri bụ Marcus Annaeus Lucanus dere n'ihe dị ka 60 BC iji kọwaa nguzogide otu agbụrụ North Africa nwere nye nsí agwọ.<ref name="Silverstein" /> Nkọwa n'ụzọ ahụike mbụ banyere ikike mgbochi ọrịa nke sitere na otu nje kpọmkwem na-akpata ọrịa bụ ikekwe ''A Treatise on Smallpox and Measles'' ("Kitab fi al-jadari wa-al-hasbah″, nke a sụgharịrị na 1848<ref>{{Cite book|author=Rāzī|first=Abū Bakr Muḥammad ibn Zakarīyā|url=https://books.google.com/books?id=rkQ-AAAAcAAJ|title=A Treatise on the Small-pox and Measles|date=1848|publisher=Sydenham Society|language=en}}</ref>) nke onye dọkịnta [[Àlakụ̀ba|Alakụba]] bụ Al-Razi dere na narị afọ nke itoolu. N’akwụkwọ ahụ, Al-Razi kọwara ihe mgbaàmà na ọdịdị ahụike nke smallpox na measles, ma gaa n’ihu ịkọwa na ịnweta ọrịa ndị a kpọmkwem na-enye ahụ́ mmadụ ikike mgbochi ọrịa na-adịte aka (ọ bụ ezie na o jighị okwu a bụ “immunity”). .<ref name="Silverstein"/> Ruo na narị afọ nke iri na itoolu, a nabatara [[:en:Miasma_theory_of_disease|echiche miasma]] n'ọtụtụ ebe. Echiche ahụ lere ọrịa ndị dị ka ọgbụgbọ na ọnyụnyụ ma ọ bụ [[:en:Black_Plague|Black Plague]] anya dị ka ihe miasma na-akpata, ụdị "ikuku ọjọọ" na-egbu egbu.<ref name="Rhodes"/> Ọ bụrụ na mmadụ ekpughee onwe ya nye miasma n'ime ala mmiri, n'ikuku mgbede, ma ọ bụ n'ikuku mgbe ọ na-eku ume n'ime ụlọ ebe ndị ahụ na-adịghị na-anọ ma ọ bụ ụlọ ọgwụ, ha nwere ike ibute ọrịa. Kemgbe narị afọ nke iri na itoolu, a bịara na-ele ọrịa na-efe efe anya dị ka nke nje / microbes na-akpata. Okwu nke oge a bụ "ikike mgbochi ọrịa" sitere na okwu Latịn bụ immunis, nke pụtara nnwere onwe pụọ n'ọrụ ndị agha, ịkwụ ụtụ isi ma ọ bụ ọrụ ọha na eze ndị ọzọ.<ref name="Gheradi"/> Onye ọkà mmụta sayensị mbụ mepụtara echiche zuru oke gbasara ikke mgbochi ọrịa bụ Ilya Mechnikov <ref>{{Cite web|url=https://www.nobelprize.org/prizes/medicine/1908/mechnikov/biographical/|title=The Nobel Prize in Physiology or Medicine 1908|work=NobelPrize.org}}</ref> onye kpughere phagocytosis na 1882. Site na [[:en:Germ_theory_of_disease|echiche nje na-ebute ọrịa]] nke Louis Pasteur, sayensị na-eto eto nke immunology malitere ịkọwa etu nje bacteria si akpata ọrịa, na otu, mgbe ọrịa gasịrị, ahụ mmadụ nwetara ikike iguzogide ọrịa ndị ọzọ.<ref name="Gheradi"/> [[Faịlụ:Albert_Edelfelt_-_Louis_Pasteur_-_1885.jpg|áká_èkpè|thumb|Louis Pasteur na ụlọ nnyocha ya, 1885, nke Albert Edelfelt sere]] N'afọ 1888, Emile Roux na Alexandre Yersin wepụtara [[:en:Diphtheria_toxin|nsị diphtheria]], ma na nsochi nke nchọpụta nke afọ 1890 nke [[:en:Emil_Adolf_von_Behring|Behring]] na [[Kitasato Shibasaburo|Kitasato]] mere gbasara ikike mgbochi ọrịa [[:en:Diphtheria|diphtheria]] na [[:en:Tetanus|tetanus]] dabeere na anti-toxin, [[:en:Antitoxin|antitoxin]] ahụ ghọrọzi ihe ịga nke ọma mbụ nke usoro ọgwụgwọ nke oge a.<ref name="Silverstein"/> Na [[Europe]], induction nke ikike mgbochi ọrịa na-arụ ọrụ pụtara na mgbalị iji gbochie kịtịkpa. Igbochi ọrịa adịla n'ụdị dị iche iche ruo ma ọ dịkarịa ala otu puku afọ, na-ejighị okwu ahụ egosipụta ya.<ref name="Gheradi">{{Cite web|url=http://nfs.unipv.it/nfs/minf/dispense/immunology/immun.html|title=The Concept of Immunity. History and Applications.|archiveurl=https://web.archive.org/web/20070102170207/http://nfs.unipv.it/nfs/minf/dispense/immunology/immun.html|archivedate=2007-01-02|work=Immunology Course Medical School|publisher=University of Pavia|access-date=2026-08-15|url-status=dead}}<cite class="citation web cs1" data-ve-ignore="" id="CITEREFGherardi">Gherardi E. . ''Immunology Course Medical School''. University of Pavia. Archived from [https://web.archive.org/web/20070102170207/http://nfs.unipv.it/nfs/minf/dispense/immunology/immun.html the original] on 2007-01-02.</cite></ref> A maghị ojiji mbụ nke okwu a bụ ịgba ọgwụ mgbochi ọrịa, mana, n'ihe dị ka 1000 AD, Ndị China malitere ime ụdị dịka ịgba ọgwụ mgbochi site n'ịmịkpọ na ikuru n'imi ajịrịja sitere na mkpocha nke ọrịa kịtịkpa.<ref name="Gheradi" /> N'ihe dị ka narị afọ nke iri na ise na [[Ndia|India]], Alaeze Ukwu Ottoman, na [[:en:East_Africa|ọwụwa anyanwụ Afrịka]], omume nke [[:en:Inoculation|inoculation]] (iji ụdị ya dị ntụ ntụ sitere na mkpocha kịtịkpa na-etinye akpụkpọ ahụ) bụ ihe a na-ahụkarị.<ref name="Gheradi" /> Ọ bụ Lady Mary Wortley Montagu bu ụzọ webata omume a n'ebe ọdịda anyanwụ n'afọ 1721.<ref name="Gheradi" /> N'afọ 1798, Edward Jenner webatara usoro ka dị nchebe nke gụnyere ịkpachara anya bute nje [[:en:Cowpox|cowpox]], ([[:en:Smallpox_vaccine|bụ ọgwụ mgbochi kịtịkpa]]), nke webatara obere nje nke mekwara ka e nwee ike igbochi ọrịa kịtịkpa. Ka ọ na-erule afọ 1800, e bidoro na-akpọ usoro ahụ ịgba ọgwụ mgbochi. Iji zeere inwe mgbagwoju anya, a nọ na-akpọ ịgba ọgwụ mgbochi kịtịkpa dị ka variolation, ọ ghọkwara ihe a na-emekarị iji okwu a n'echebaraghị usoro iheomume echiche. Ihe ịga nke ọma na nnabata zuru oke nke usoro Jenner ga-emecha mee ka ọdịdị ịgba ọgwụ mgbochi nke Pasteur na ndị ọzọ mepụtara na njedebe nke narị afọ nke iri na itolu dị izugbe.<ref name="Silverstein">{{Cite book|date=1989|title=History of Immunology (Hardcover)|publisher=Academic Press|url=https://www.amazon.com/gp/reader/012643770X}}<cite class="citation book cs1" data-ve-ignore="" id="CITEREFSilverstein1989">Silverstein AM (1989). [https://www.amazon.com/gp/reader/012643770X ''History of Immunology (Hardcover)'']. Academic Press &#x2013; via Amazon.com.</cite></ref> N'afọ 1891, Pasteur gbasara nkọwa nke ịgba ọgwụ mgbochi iji sọpụrụ Jenner, ọ ghọkwara ihe dị mkpa ịkọwaru okwu ahụ n'ozuzu site n'izo aka na [[:en:Polio_vaccine|ọgwụ mgbochi polio]], [[:en:Measles_vaccine|ọgwụ mgbochi kịtịkpa]] wdg. == Ikike Mgbochi Ọrịa na-adịghị arụ ọrụ == <templatestyles src="Reflist/styles.css" />Ikike mgbochi ọrịa na-adịghị arụ ọrụ bụ ikike mgbochi ọrịa e nwetara site na mbufe nke ihe ndị na-alụso ọrịa ọgụ na ahụ site n'otu onye gaa na onye ọzọ. Ikike mgbochi ọrịa na-adịghị arụ ọrụ nwere ike ime n'ụzọ ebumpụtaụwa, dịka mgbe a na-ebufe ihe ndị na-alụso ọrịa ọgụ n'ahụ nke nne nye nwa e bu n'afọ site na placenta, a pụkwara ime ka ọ bụrụ ihe aka mere, mgbe a na-ebufe ihe ndị na-alụso ọrịa ọgụ n'ahụ nke [[Madụ̀|mmadụ]] (ma ọ bụ nke ịnyịnya) nke bụ maka nje na-ebute ọrịa kpọmkwem ma ọ bụ nsí n'ebe ọ dị elu bunye ya ndị na-enweghị [[:en:Immune_system|ihe ndị na-alụso ọrịa ọgụ n'ahụ]]. A na-eme ịgba ọgwụ mgbochi na-adịghị arụ ọrụ mgbe enwere nnukwu ihe ize ndụ nke ibute ọrịa na mgbe oge ezughi oke maka ahụ iji mepụta ihe ndị na-alụso ọrịa ọgụ nke ya, ma ọ bụ iji belata mgbaàmà nke ọrịa na-aga n'ihu ma ọ bụ nke [[:en:Immunosuppression|na-abịatu ihe ndị na-alụso ọrịa ọgụ n'ahụ]].<ref name="USC"/> Ịgba ọgwụ mgbochi na-adịghị arụ ọrụ na-enye nchebe ozugbo, mana ahụ anaghị echeta, ya mere onye ọrịa nọ n'ihe ize ndụ nke ibute otu nje ahụ na-ebute ọrịa mgbe e mesịrị.<ref name="Janeway"/> === Ikike Mgbochi Ọrịa na-adịghị arụ ọrụ E Nwetara N'ụzọ Ọnatarachi === Nwa e bu n'afọ na-enweta ikike mgbochi ọrịa na-adịghị arụ ọrụ site n'aka nne ya n'oge ọ dị ime. Ikike mgbochi ọrịa na-adịghị arụ ọrụ nke nne bụ ikike mgbochi ọrịa nke [[:en:Antibody|ihe ndị na-alụso ọrịa ọgụ n'ahụ]] nọ n'etiti ya. A na-ebufe ihe ndị na-alụso nne ọgụ nke nne (MatAb) site na Placenta gaa na nwa e bu n'afọ site na ihe nnabata FcRn ndị dị na mkpụrụ ndụ placenta. Nke a na-eme n'ihe dị ka ọnwa nke atọ nke ịdị ime. IgG bụ naanị di n'otu ụdị ka ihe ndị na-alụso ọrịa ọgụ n'ahụ nke nwere ike ịgafe placenta. A na-enyekwa ikike mgbochi ọrịa na-adịghị arụ ọrụ site na mbufe nke ihe na-egbochi ọrịa IgA dị na mmiri ara nke a na-ebufe na eriri afọ nke nwa ọhụrụ na-aṅụ ara, na-echebe ya megide nje bacteria, ruo mgbe nwa ọhụrụ ahụ nwere ike ịmepụta ihe ndị na-egbochi ọrịa nke ya. Colostrum dị na mmiri ara ndị nne bụ ihe atụ nke ikike mgbochi ọrịa na-adịghị arụ ọrụ.<ref name="Janeway">{{Cite book|title=Immunobiology|edition=Fifth|publisher=Garland Science|year=2001|location=New York and London|url=https://www.ncbi.nlm.nih.gov/books/NBK10757/?depth=10|isbn=978-0-8153-4101-7}}<cite class="citation book cs1" data-ve-ignore="" id="CITEREFJanewayTraversWalportShlomchik2001">[[Charles Janeway|Janeway C]], Travers P, Walport M, Shlomchik M (2001). [https://www.ncbi.nlm.nih.gov/books/NBK10757/?depth=10 ''Immunobiology''] (Fifth&nbsp;ed.). New York and London: Garland Science. [[ISBN]]&nbsp;[[Special:BookSources/978-0-8153-4101-7|<bdi>978-0-8153-4101-7</bdi>]].</cite>.</ref> [[Faịlụ:Antitoxin_diphtheria.jpg|áká_ịkẹngạ|thumb|176x176px|Otu n'ime karama mbụ nke diphtheria antitoxin e mepụtara (nke e dere n'afọ 1895) ]] === Ikike Mgbochi Ọrịa na-adịghị arụ ọrụ E Nwetara N'ụzọ Aka Mere === Ikike mgbochi ọrịa na-adịghị arụ ọrụ e nwetara n'ụzọ aka mere bụ ịgba ọgwụ mgbochi ọrịa dị mkpirikpi nke a na-ebute site na mbufe nke ihe ndị na-egbochi ọrịa n'ahụ, nke enwere ike inye n'ụdị dị iche iche; dị ka plasma ọbara mmadụ ma ọ bụ nke anụmanụ, dị ka immunoglobulin mmadụ maka ịgbanye ya n'akwara (IVIG) ma ọ bụ ịgbanye ya n'uru anụ (IG), yana n'ụdị [[:en:Monoclonal_antibodies|monoclonal antibodies]] (MAb). A na-eji nnyefe na-adịghị arụ ọrụ eme ihe n'ụdị [[:en:Prophylactic|prophylactic]] n'ihe gbasara ọrịa [[:en:Immunodeficiency|immunodeficiency]], dị ka hypogammaglobulinemia.<ref name="Keller"/> A na-ejikwa ya agwọ ọtụtụ ụdị ọrịa siri ike, na iji gwọọ nsị.<ref name="USC">{{Cite web|url=http://pathmicro.med.sc.edu/ghaffar/immunization.htm|title=Microbiology and Immunology On-Line Textbook|publisher=USC School of Medicine}}<cite class="citation web cs1" data-ve-ignore="">[http://pathmicro.med.sc.edu/ghaffar/immunization.htm "Microbiology and Immunology On-Line Textbook"]. USC School of Medicine.</cite></ref> Ikike mgbochi ọrịa nke sitere na ịgba ọgwụ mgbochi ọrịa na-adịghị arụ ọrụ na-adịru naanị obere oge, e nwekwara ihe ize ndụ maka mmeghachi omume [[:en:Hypersensitivity|hypersensitivity]], na Ọrịa serum, ọkachasị site na gamma globulin nke na-abụghị nke si na mmadụ.<ref name="Janeway"/> E jirila ntinye n'ụzọ aka mere nke ikike mgbochi ọrịa na-adịghị arụsi ọrụ ike mee ihe ihe ihe karịrị otu narị afọ iji gwọọ ọrịa na-efe efe, na tupu ọbịbịa nke ọgwụ nje, ọ na-abụkarị naanị ọgwụgwọ a kapịrị ọnụ maka ọrịa ụfọdụ. Ọgwụgwọ immunoglobulin nọgidere na-abụ ọgwụgwọ mbụ na ọgwụgwọ nke ọrịa iku ume siri ike ruo n'afọ ndị 1930, ọbụlagodi mgbe eweputacharara ọgwụ nje sulfonamide.<ref name="Keller">{{Cite journal|title=Passive immunity in prevention and treatment of infectious diseases|url=https://archive.org/details/sim_clinical-microbiology-reviews_2000-10_13_4/page/602|journal=Clinical Microbiology Reviews|volume=13|issue=4|pages=602–14|date=October 2000|pmid=11023960|doi=10.1128/CMR.13.4.602-614.2000}}<cite class="citation journal cs1" data-ve-ignore="" id="CITEREFKellerStiehm2000">Keller MA, Stiehm ER (October 2000). [https://www.ncbi.nlm.nih.gov/pmc/articles/PMC88952 "Passive immunity in prevention and treatment of infectious diseases"]. ''Clinical Microbiology Reviews''. '''13''' (4): <span class="nowrap">602–</span>14. [[Digital object identifier|doi]]:[[doi:10.1128/CMR.13.4.602-614.2000|10.1128/CMR.13.4.602-614.2000]]. [[PMC (identifier)|PMC]]&nbsp;<span class="id-lock-free" title="Freely accessible">[https://www.ncbi.nlm.nih.gov/pmc/articles/PMC88952 88952]</span>. [[PMID (identifier)|PMID]]&nbsp;[https://pubmed.ncbi.nlm.nih.gov/11023960 11023960].</cite></ref> === Mbufe nke mkpụrụ ndụ T na-arụ ọrụ === Mgbochi ọrịa na-adịghị arụsi ọrụ ike, ma ọ bụ “[[:en:Adoptive_immunity|mbufe mgbochi ọrịa site n’ịnabata mkpụrụ ndụ]]” nke mgbochi ọrịa nke mkpụrụ ndụ na-achịkwa, ka a na-enweta site n’ibufe mkpụrụ ndụ T ndị “a kpaliri ịrụ ọrụ” ma ọ bụ ndị rụwalara ọrụ site n’otu onye gaa n’ahụ onye ọzọ. A naghị eji usoro a eme ihe ugboro ugboro n’ebe mmadụ nọ, n’ihi na ọ chọrọ ndị na-enye mkpụrụ ndụ nwere histocompatible (ndị ahụ́ ha kwekọrọ), ndị na-esikarị ike ịchọta. N’ebe ndị na-enye mkpụrụ ndụ na-adịghị ekwekọ, ụdị mbufe a nwere nnukwu ihe ize ndụ nke ibute ọrịa <a href="https://en.wikipedia.org/wiki/Graft_versus_host_disease" rel="mw:ExtLink" title="Graft versus host disease" class="mw-redirect cx-link" data-linkid="192">graft versus host</a>.<ref name="USC"/> Otú ọ dị, ejirila ya agwọ ụfọdụ ọrịa, gụnyere ụfọdụ ụdị '''ọrịa''' kansa na erughị eru nke usoro mgbochi ọrịa ([[:en:Immunodeficiency|immunodeficiency]]) . Ụdị mbufe a dị iche na [[:en:Bone_marrow_transplant|mbugharị ụmị ọkpụkpụ]], nke a na-ebufe [[:en:Hematopoietic_stem_cell|mkpụrụ ndụ stem hematopoietic]] (nke na-adịbeghị iche n’ọrụ ha) n’ime ahụ.   <sup class="noprint Inline-Template Template-Fact" style="white-space:nowrap;">&#x5B;''[[wikipedia:Tinye edensibịa|<span title="This claim needs references to reliable sources. (April 2022)">citation needed</span>]]''&#x5D;</sup> == Ikike Mgbochi ọrịa Na-arụ Ọrụ ==   [[Faịlụ:Immune_response2.svg|thumb|350x350px|Oge nke mmeghachi omume nke usoro ahụ ji alụso ọrịa ọgụ. N'ihi mmepụta nke [[:en:Immunological_memory|ihe ncheta nke immunological]], ibute ọrịa ọzọ mgbe e mesịrị na-eduga na mmụba ngwa ngwa nke ihe ndị na-alụso ọrịa ọgụ n'ahụ na mmepụta nke antibody na ọrụ T cell. Ọrịa ndị a na-esote nwere ike ịdị nro ma ọ bụ ọbụna ghara ịdị.]] Mgbe Mkpụrụ ndụ B na Mkpụrụ ndụ T ka a kpaliri ị na-arụ ọrụ site na nje na-ebute ọrịa, ncheta mkpụrụ ndụ B na mkpụrụ ndụT- na-etolitekwa, mmeghachi omume mbụ nke usoro ilụso ọrịa ọgụ nke ahụ na-apụta. N'oge ndụ niile nke anụmanụ, mkpụrụ ndụ ncheta ndị a niile "ga-echeta" nje na-ebute ọrịa nke ọ bụla o zutere, ma nwee ike ịmalite nzaghachi siri ike ma ọ bụrụ na achọpụta nje ahụ na-ebute ọrịa ọzọ. Nzaghachi mbụ na nke abụọ ka onye Bekee na-ahụ maka ahụike Alexander Glenny kọwara na 1921 <ref>{{Cite journal|title=Notes on the Production of Immunity to Diphtheria Toxin|journal=The Journal of Hygiene|volume=20|issue=2|pages=176–220|date=October 1921|pmid=20474734|doi=10.1017/S0022172400033945}}</ref> ọ bụ ezie na achọtaghị usoro ahụ dị na ya ruo mgbe e mesịrị. Ụdị mgbochi a na-arụ ọrụ ma na-agbanwe agbanwe n'ihi na usoro mgbochi ọrịa nke ahụ na-akwadebe onwe ya maka ihe ịma aka n'ọdịnihu. Ikike mgbochi ọrịa na-arụ ọrụ na-agụnyekarị ma akụkụ nke mkpụrụ ndụ na-achịkwa na nke humoral nke mmegide yana ntinye sitere na usoro ahụike ebumpụta ụwa.{{immune system}} === Ihe e nwetara n'ụzọ aka Mere === {{Authority control}}Enwere ike ịkpali ikike mgbochi ọrịa na-arụsi ọrụ ike nke e nwetara n’ụzọ aka mere site n’iji ọgwụ mgbochi ọrịa ([[:en:Vaccine|vaccine]]), nke bụ ihe nwere antigen n’ime ya. Ọgwụ mgbochi ọrịa na-akpali nzaghachi mbụ nke usoro mgbochi ọrịa megide antigen ahụ n’enweghị ịkpata ihe mgbaàmà nke ọrịa ahụ.<ref name="USC"/> Ọ bụ Richard Dunning, onye ya na Edward Jenner, na-arụkọ ọrụ, chepụtara okwu “vaccination”, ma Louis Pasteur mechara were okwu ahụ mee ihe n’ọrụ ya a ma ama banyere ịgba ọgwụ mgbochi ọrịa. Usoro Pasteur jiri gụnyere ịgwọ ma ọ bụ imezi ihe ndị na-ebute ọrịa na-efe efe ka ha ghara inwezi ike ịkpata ọrịa siri ike. Pasteur jiri aha '''“vaccine”''' mee ihe dịka okwu izugbe iji sọpụrụ nchọpụta Jenner, nke ọrụ Pasteur wuru. [[Faịlụ:Poster_for_vaccination_against_smallpox.jpg|thumb|314x314px|Ihe ngosi nke tupu mkpochapụ nke kịtịkpa na 1979, na-akwalite ịgba ọgwụ mgbochi]] N'afọ 1807, Bavaria ghọrọ otu mbụ chọrọ ka a gbaa ndị agha ha ọgwụ mgbochi megide kịtịkpa, ebe mgbasa nke kịtịkpa ka e jikọrọ ya na agha.<ref name="NIH-Variolation">{{Cite web|publisher=[[National Institutes of Health]]|work=Smallpox – A Great and Terrible Scourge|url=https://www.nlm.nih.gov/exhibition/smallpox/sp_variolation.html|title=Variolation}}</ref> N'ikpeazụ, omume ịgba ọgwụ mgbochi ga-abawanye na mgbasa nke agha. E nwere ụdị ọgwụ mgbochi ọdịnala anọ: <ref>{{Cite web|url=http://www2.cdc.gov/nip/isd/ycts/mod1/courses/genrec/10300.asp?student_id=|title=Immunization: You call the shots.|archiveurl=https://web.archive.org/web/20060929162613/http://www2.cdc.gov/nip/isd/ycts/mod1/courses/genrec/10300.asp?student_id=|archivedate=2006-09-29|work=The National Immunization Program|publisher=U.S. Centers for Disease Control and Prevention}}</ref> * Ọgwụ mgbochi ndị na-adịghị arụ ọrụ nwere nje ndị e ji kemịkal na/ma ọ bụ okpomọkụ gbuo ma bụrụ ndị na-adịghị ebufenwuzi ọrịa. Ihe atụ bụ ọgwụ mgbochi megide influenza, ọgbụgbọ na ọnyụnyụ, [[Plague immunization|Ihe otiti]], na [[:en:Hepatitis_A|ịba ọcha n'anya A]]. Ọtụtụ ọgwụ mgbochi nke ụdị a nwere ike ịchọ mmụba. * Ọgwụ mgbochi dị ndụ, nke e belatara ikike ya, bụ ọgwụ mgbochi ọrịa nke e ji ụmụ nje ndị a zụlitere n’ọnọdụ pụrụ iche mee, nke mere ka ha ghara inwe ike ịkpata ọrịa. Nzaghachi usoro mgbochi ọrịa ndị a na-adịte aka karịa; Otú ọ dị, mmadụ nwere ike ịchọ ịgba ọgwụ nkwado. Ihe atụ gụnyere [[:en:Yellow_fever|yellow fever]], [[:en:Measles|measles]], rubella, na [[:en:Mumps|mumps]]. * Toxoids bụ ihe ndị na-egbu egbu sitere n’ime ụmụ nje ndị a kwụsịrị ịrụ ọrụ, n’ọnọdụ ebe ihe ndị a—kama ịbụ nje ahụ n’onwe ya—na-akpata ọrịa. A na-eji ha eme ihe tupu mmadụ ezute nsị nke nje ahụ. Ihe atụ nke ọgwụ mgbochi ọrịa sitere na toxoid gụnyere tetanus na diphtheria. * Ọgwụ mgbochi [[:en:Subunit_vaccine|Subunit]], [[:en:Recombinant_DNA|recombinant]], <a href="https://en.wikipedia.org/wiki/Polysaccharide" rel="mw:ExtLink" title="Polysaccharide" class="cx-link" data-linkid="258">polysaccharide</a>, na [[:en:Conjugate_vaccine|conjugate]] bụ ọgwụ mgbochi ọrịa ndị e ji obere akụkụ ma ọ bụ iberibe sitere n’ahụ́ nje na-akpata ọrịa mee. <ref name="vaccines.gov">{{Cite web|title=Vaccine Types|url=https://www.vaccines.gov/basics/types|accessdate=2020-08-07|work=www.vaccines.gov}}</ref> Ihe atụ doro anya bụ ọgwụ mgbochi subunit megide nje [[:en:Hepatitis_B_virus|Hepatitis B]]. Na mgbakwunye, e nwere ụdị ọgwụ mgbochi ọhụrụ a na-eji eme ihe: * Ọgwụ mgbochi [[:en:Bacterial_outer_membrane_vesicles|Outer Membrane Vesicle]] (OMV) bụ ọgwụ mgbochi ọrịa nwere akpụkpọ mpụta (outer membrane) nke nje bacteria, na-enweghị akụkụ dị n’ime nje ahụ ma ọ bụ ihe mkpụrụ ndụ ihe nketa ya. N’ihi ya, n’ụzọ zuru oke, ha na-akpali usoro mgbochi ọrịa ka o nwee ike ịlụso nje bacteria mbụ ahụ ọgụ, n’enweghị ihe ize ndụ nke ibute ọrịa.<ref>{{Cite journal|author=Acevedo|first=R|year=2014|title=Bacterial outer membrane vesicles and vaccine applications|journal=Frontiers in Immunology|volume=5|pmid=24715891|doi=10.3389/fimmu.2014.00121}}</ref> * [[:en:Genetic_vaccine|Ọgwụ mgbochi sitere na mkpụrụ ndụ ihe nketa]] na-ebunye nucleic acid nke nwere koodu maka antigen n’ime mkpụrụ ndụ nke onye a na-agwọ. Mkpụrụ ndụ ndị ahụ na-emepụtazi antigen ahụ, nke na-akpalite nzaghachi usoro mgbochi ọrịa. Ụdị ọgwụ mgbochi a gụnyere Ọgwụ mgbochi DNA, <ref name="DNA immunization">{{Cite journal|title=DNA immunization as a technology platform for monoclonal antibody induction|first=Shuying|author=Liu|date=April 27, 2016|journal=Emerging Microbes & Infections|volume=5|issue=4|pages=e33|doi=10.1038/emi.2016.27|pmid=27048742}}</ref> Ọgwụ mgbochi RNA, <ref name="Pardi">{{Cite journal|author=Pardi|first=Norbert|date=April 2018|title=mRNA vaccines — a new era in vaccinology|journal=Nature Reviews Drug Discovery|volume=17|issue=4|pages=261–279|doi=10.1038/nrd.2017.243|pmid=29326426|issn=1474-1784}}</ref> na <a href="https://en.wikipedia.org/wiki/Viral_vector_vaccine" rel="mw:ExtLink" title="Viral vector vaccine" class="cx-link" data-linkid="272">Ọgwụ mgbochi viral vector</a>, <ref>{{Cite journal|title=Recombinant vector vaccine evolution|journal=PLOS Computational Biology|volume=15|issue=7|date=July 2019|pmid=31323032|doi=10.1371/journal.pcbi.1006857}}</ref> <ref>{{Cite journal|title=Multivalent and Multipathogen Viral Vector Vaccines|journal=Clinical and Vaccine Immunology|volume=24|issue=1|pages=e00298–16, e00298–16|date=January 2017|pmid=27535837|doi=10.1128/CVI.00298-16}}</ref> ụ́ ndị dị iche n’ụdị kemịkalụ nke nucleic acid ha na ụzọ e si ebufe ya n’ime mkpụrụ ndụ onye a na-agwọ. Ụdị ọgwụ mgbochi dị iche iche ka na-emepe emepe; lee [[:en:Vaccine#Experimental|Ụdị ọgwụ mgwọ ọrịa ndị a ka na-anwale]]. A na-enye ọtụtụ ọgwụ mgbochi ọrịa site n’ịgba ọgwụ n’okpuru akpụkpọ ahụ ma ọ bụ n'ime uru anụ n’ihi na eriri afọ anaghị anabata ha nke ọma mgbe niile. A na-enye ọgwụ mgbochi Ọrịa polio dị ndụ nke e mebelatara ike ya yana ụfọdụ ọgwụ mgbochi ọrịa [[:en:Typhoid|typhoid]] na ọrịa [[:en:Cholera|ọgbụgbọ na ọnyụnyụ]] [[:en:Mouth|site n'ọnụ]] iji mepụta mgbochi ọrịa nke na-adabere n’usoro mgbochi ọrịa dị n’ime eriri afọ. === Ikike Mgbochi ọrịa nke ngwakọta === Ikike Mgbochi ọrịa nke ngwakọta bụ njikọta nke ikike mgbohi ọrịa nke ọnatarachi na ikike mgbochi ọrịa nke aka mere. Nnyocha nke ndị nwere ikike mgbochi ọrịa nke ngwakọta chọpụtara na ọbara ha nwere ike igbochi Beta na ụdị SARS-CoV-2 ndị ọzọ karịa ndị na-enwetụbeghị ọrịa, ndị gbara ọgwụ mgbochi.<ref>{{Cite journal|author=Callaway|first=Ewen|date=2021-10-14|title=COVID super-immunity: one of the pandemic's great puzzles|url=https://www.nature.com/articles/d41586-021-02795-x|journal=Nature|volume=598|issue=7881|pages=393–394|language=en|doi=10.1038/d41586-021-02795-x|pmid=34650244|issn=0028-0836}}</ref> Ọzọkwa, na 29 Ọktọba 2021, [[:en:Centers_for_Disease_Control_and_Prevention|Centers for Disease Control and Prevention]] (CDC) kwubiri na "Ọtụtụ nnyocha e mere na ntọala dị iche iche egosila na nje SARS-CoV-2 na ịgba ọgwụ mgbochi ọrịa n'otu n'otu na-ebute obere ihe ize ndụ nke ibute ọrịa ka e mesịrị na ụdị ndị yiri ya ruo ọ dịkarịa ala ọnwa isii. Ọtụtụ ọmụmụ gbasara usoro mgbochi ọrịa, yana ọnụ ọgụgụ na-arịwanye elu nke ọmụmụ gbasara mgbasa na nkesa ọrịa n’obodo (epidemiology), egosila na ịgba ọgwụ mgbochi ọrịa nye ndị mmadụ bu ọrịa ahụ mbụ na-eme ka nzaghachi usoro mgbochi ọrịa ha sie ike nke ukwuu, ma na-ebelata nke ọma ihe ize ndụ nke ibute ọrịa ọzọ, gụnyere n’ọnọdụ ebe ụdị nje ndị na-efe efe ngwa ngwa na-agbasawanye.<ref name="CDC-20211029">{{Cite news|author=Staff|title=Science Brief: SARS-CoV-2 Infection-induced and Vaccine-induced Immunity|url=https://www.cdc.gov/coronavirus/2019-ncov/science/science-briefs/vaccine-induced-immunity.html|date=29 October 2021|work=[[Centers for Disease Control and Prevention]]|accessdate=12 November 2021}}</ref> == Ọmụmụ mkpụrụ ndụ ihe nketa == A na-ekpebi ikike mgbochi ọrịa site na mkpụrụ ndụ ihe nketa. Genome ndị dị n'ime ụmụ mmadụ na [[Animal|Ụmụ anụmanụ]] na-edepụta [[:en:Antibody|ihe ndị na-alụso ọrịa ọgụ n'ahụ]] na ọtụtụ mkpụrụ ndụ ihe nketa ndị ọzọ na-emeghachi omume nye ọrịa. Ọ bụ ezie na a na-achọkarị ọtụtụ n'ime Mkpụrụ ndụ ihe nketa ndị a maka ikike mgbochi ọrịa na-arụ ọrụ na nke na-adịghị arụsi ọrụ ike (lee ngalaba ndị dị n'elu), e nwekwara ọtụtụ [[:en:Gene|mkpụrụ ndụ ihe nketa]] nke yiri ka a chọrọ ha maka mmeghachi omume ahụike pụrụ iche. Dịka ọmụmaatụ, a chọrọ [[:en:Tumor_necrosis_factor|Tumor Necrosis Factor]] (TNF) maka nchebe pụọ na [[Ụkwara Nta|ụkwara nta]] n'ime ụmụ mmadụ. Ndị nwere nkwarụ mkpụrụ ndụ ihe nketa na TNF nwere ike ịnata ọrịa na-egbu egbu na nke na-abịaghachị ugboro ugboro ndụ na nje ụkwara nta (''[[:en:Mycobacterium_tuberculosis|Mycobacterium tuberculosis]]'') mana ha nwere ahụike. O yikwara ka ha na-emeghachi omume nye ọrịa ndị ọzọ n'ụzọ dị mma. Ya mere, a na-akpọ ọnọdụ ahụ ''Mendelian susceptibility to mycobacterial disease'' (MSMD) na ụdị ya nwere ike e bute ya site na mkpụrụ ndụ ihe nketa ndị ọzọ metụtara mmepụta ma ọ bụ mgbaàmà interferon (dịka site na mgbanwe na mkpụrụ ndụ ''''<a href="https://en.wikipedia.org/wiki/Interferon_gamma" rel="mw:ExtLink" title="Interferon gamma" class="cx-link" data-linkid="306">IFNG</a>'''', ''[[:en:Interleukin-12_subunit_beta|IL12B]], [[:en:Interleukin_12_receptor,_beta_1_subunit|IL12RB1]],'' ''''''IL12RB2'''''', ''IL23R'', ''ISG15'', ''MCTS1'', ''RORC'', ''TBX21'', ''TYK2'', ''CYBB'', ''JAK1'', ''IFNGR1'', ''[[:en:Interferon_gamma_receptor_2|IFNGR2]]'', ''STAT1'', ''USP18,'' ''[[:en:IRF1|IRF1]],'' ''<a href="https://en.wikipedia.org/wiki/IRF8" rel="mw:ExtLink" title="IRF8" class="cx-link" data-linkid="323">IRF8</a>'', ''NEMO'', ''SPPL2A'').<ref>{{Cite journal|author=Arias|first=Andrés A.|date=2024-09-12|title=Tuberculosis in otherwise healthy adults with inherited TNF deficiency|journal=Nature|language=en|volume=633|issue=8029|pages=417–425|doi=10.1038/s41586-024-07866-3|issn=0028-0836|pmid=39198650}}</ref> == Hụkwa == <templatestyles src="Div col/styles.css" />  == Edensibịa == {{Reflist}} == Njikọ mpụga == * [http://www.modelingimmunity.org/ The Center for Modeling Immunity to Enteric Pathogens (MIEP)] [[Otú:Pages with unreviewed translations]] ecn6yt7n15z9m9uhgoc1r5lm1cp8hjc Febụwarị 2009 Mwakpo ndị na-eyi ọha egwu na Cairo 0 79302 736819 735238 2026-10-07T17:26:50Z InternetArchiveBot 11600 Rescuing 2 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736819 wikitext text/x-wiki <templatestyles src="Module:Hatnote/styles.css"></templatestyles>Mwakpo ndị na-eyi ọha egwu na Febụwarị 2009 na Cairo bụ ihe atọ mere na Cairo, Egypt site na 22 Febụwarụ 2009 ruo 28 Febụwar's 2009. N'ime mwakpo atọ, ọ bụ naanị nke mbụ nwụrụ, na-akpata ọnwụ nke onye French dị afọ iri na asaa. O yiri ka a na-eduzi mwakpo ahụ n'ụzọ dị iche iche na Ndị njem nleta si mba ọzọ na ndị mba Ijipt. Ọ dịghị nke ọ bụla n'ime mwakpo ndị ọrụ nchekwa Ijipt kọwara dị ka nke dị mgbagwoju anya. Ihe kpatara ma ọ dịkarịa ala abụọ n'ime mwakpo ahụ edoghị anya, mana oke ime ihe ike bịara n'etiti esemokwu dị elu na-esote esemokwu Israel-Gaza nke 2008-2009, mgbe ndị Ijipt mere ngagharị iwe megide mmechi gọọmentị ha nke Rafah Border Crossing. == Ihe omume mbụ: Bọmbụ Khan el-Khalili == <templatestyles src="Module:Side box/styles.css"></templatestyles><templatestyles src="Sister project/styles.css"></templatestyles>N'elekere 18:30 nke oge mpaghara na 22 n'ọnwa Febụwarị afọ 2009, otu bọmbụ gbawara na Khan el-Khalili, a ''Souq'' n'ebe ọwụwa anyanwụ Cairo. Mwakpo ahụ mere ozugbo chi jiri n'ihu ụlọ oriri na ọṅụṅụ jupụtara na ndị mmadụ na-ezukọta iji kirie egwuregwu bọọlụ a na-egosi na telivishọn. E nwere akụkọ na-emegiderịta onwe ha na a tụbara bọmbụ ahụ site na veranda ma ọ bụ site na ọgba tum tum, mana ndị ọrụ nchekwa kọrọ na bọmbụ yango gbawara n'okpuru bench n'ogige dị n'oghere ahụ. Bọmbụ nke abụọ agbawaghị ma gbanyụọ ya. Bọmbụ ndị ahụ dị kilogram 1.5 (3.3 ma nwee mbọ na iberibe ígwè.<ref name="BBC">BBC (23 February 2009). [https://news.bbc.co.uk/1/hi/world/middle_east/7907655.stm 'Small cell' behind Cairo blast]. [[BBC]]. Updated 24 February 2009. Retrieved 2009.</ref> E gburu nwa agbọghọ French dị afọ iri na asaa, onye so n'ìgwè ndị nọ n'afọ iri na ụma iri ise na anọ si Levallois-Perret, nso Paris. 17 French, otu German na ndị njem nleta Saudi atọ, yana ndị Ijipt atọ, merụrụ ahụ.<ref name="Rasmussen">Rasmussen, Will (14 January 2009). {{Deprecated archive|url=https://archive.today/20130201075421/http://uk.reuters.com/article/UKNews1/idUKTRE50D3UK20090114|title=Egypt police hold 16 Islamists after Gaza protests.}} [[Reuters]]. Uploaded 14 January 2009. Retrieved 2 March 2009.</ref> Akụkọ ndị mbụ tụrụ aro na ihe ndị na-agbawa agbawa bụ "ndị mbụ".<ref name="Rasmussen" /> Dịka isi mmalite ndị na-ahụ maka nchekwa si kwuo, ọ dịghị otu ndị agha nnupụisi kwuru ozugbo na ha kpatara ihe ahụ, mana e jidere mmadụ atọ a na-enyo enyo. == Ihe omume nke abụọ: Ogbugbu Khan el-Khalili == N'ụbọchị nke 28 n'ọnwa Febụwarị afọ 2009, otu nwoke si mba Egypt mara otu onye nkuzi si mba America mma mgbe ọ na-agafe na mpaghara Khan el-Khalili. Onye ahụ a wakporo, bụ́ onye na-akụzi ihe gbasara sayensị n'ụlọ akwụkwọ American School of Alexandria dị n'obodo Alexandria, mba Ijipt, nwetara ọnyá mma n'ihu. Ndị uwe ojii jidere onye ọrụ Ijipt dị afọ iri anọ na isii, Abdel Rahman Saleh Taher Mohammed ([[Arabic]]), onye ụlọ ọrụ mgbasa ozi nke mba Ijipt bụ MENA kwuru na ọ bụ "ịkpọ ndị mba ọzọ asị n'ihi Mwakpo Israel na Gaza". E mechara kpughee na e jidere onye a na-enyo enyo n'Ụlọ ọgwụ ndị isi mgbaka n'afọ 2000 maka mwakpo a wakporo ndị njem nleta na ndị uwe ojii. == Ihe omume nke atọ: Bọmbụ Metro == Ka e mesịrị na 28 n'ọnwa Febụwarị afọ 2009, a tụbara ma ọ dịkarịa ala otu bọmbụ ọkụ site na àkwà mmiri n'ụgbọ okporo ígwè na-agafe agafe na Cairo Metro. Mwakpo ahụ mere na nso ọdụ ụgbọ oloko Line 1 nke Helmiet El-Zaitoun, nso Ain Shams na ugwu ọwụwa anyanwụ Cairo. Ndị omempụ ahụ gbapụrụ n'ebe ahụ, na akụkọ ndị akaebe gosipụtara ndị a na-enyo enyo n'ụzọ dị iche iche dị ka otu nwoke ma ọ bụ ụmụ nwoke abụọ.<ref name="Africasia">AFP (28 February 2009). [https://web.archive.org/web/20110718153051/http://www.africasia.com/services/news/newsitem.php?area=mideast&item=090228180739.cqfmn85u.php Cairo metro incendiary bottle fails to explode.] {{Webarchive|url=https://web.archive.org/web/20110718153051/http://www.africasia.com/services/news/newsitem.php?area=mideast&item=090228180739.cqfmn85u.php |date=18 July 2011 }} [https://web.archive.org/web/20090122065903/http://africasia.com/ ''Africasia''] {{Webarchive|url=https://web.archive.org/web/20090122065903/http://africasia.com/ |date=22 January 2009 }}. Updated 28 February 2009. Retrieved 2 March 2009.</ref><ref name="Johnston (2009-02-28)">Johnston, Cynthia (28 February 2009). [http://www.iht.com/articles/reuters/2009/02/28/africa/OUKWD-UK-EGYPT-FIREBOMB.php Firebomb thrown at crowded Cairo metro station.] ''[[International Herald Tribune]]''. Updated 28 February 2009. Retrieved 2 March 2009.</ref> O yighị ka ọ ga-emerụ ahụ, na Ngwaọrụ ọkụ ahụ nwere ike ọ gaghị agbawa.<ref name="Africasia" /> == Hụkwa ==  <templatestyles src="Reflist/styles.css" />  * 2004 Bọmbụ a tụrụ na Sinai * Eprel 2005 Mwakpo ndị na-eyi ọha egwu na Cairo * 2005 Mwakpo Sharm el-Sheikh * 2006 Bọmbụ Dahab * 2009 Bọmbụ Khan el-Khalili == Edensibia == {{Reflist}} <templatestyles src="Module:Coordinates/styles.css"></templatestyles>{{Coor|30.048|31.262|type:event_globe:earth_region:EG}} byqkmmk5hx2hw3l973woxmksmn4vn3p Julissa 0 79386 736820 722712 2026-10-07T17:37:11Z Juliegwen 12936 /* Nrụtụaka */ 736820 wikitext text/x-wiki <templatestyles src="Module:Hatnote/styles.css"></templatestyles><templatestyles src="Module:Message box/ambox.css"></templatestyles><templatestyles src="Module:Infobox/styles.css"></templatestyles>  '''Julia Isabel de Llano Macedo''' (amụrụ na 8 Eprel 1944), nke a maara dịka '''Julissa''', bụ onye na-eme ihe nkiri, onye na-emepụta ihe, na onye na-agụ egwu na Mexico. Ọ bụ nwa nwanyị nke onye na-eme ihe nkiri na redio na telivishọn Luis de Llano Palmer na onye na-ese ihe nkiri Rita Macedo. Ụmụ ya gụnyere Benny Ibarra, onye na-agụ egwu na onye na-eti egwu, na Alejandro Ibarra, Onye na-eme ihe nkiri na onye na na-agụ egwú. Nwanne ya nwoke, Luis de Llano Macedo, arụwo ọrụ dị ka onye na-emepụta ihe maka Televisa. == Mbido ndụ na ọrụ == === Egwú === Mgbe ọ dị afọ 14, Julissa malitere ọrụ egwu ya n'otu egwu ụdị 'rock' a na-akpọ The Spitfires; nwanne ya nwoke bụ Luis hiwere otu egwu a. O nwetara ọnọdụ nke abụọ n'asọmpi redio tupu ụlọ ọrụ CBS abanye ya n'akwụkwọ nkwekọrịta, o wee dekọọ ọtụtụ abọm egwu 'rock' n'etiti afọ 1961 na 1964. O dekọrọ otu egwu (nke a na-akpọ 'single') nwere aha bụ "Corazón Salvaje / Te Necesito," nke ụlọ ọrụ Capitol Records na afọ 1966. wepụtara n'afọ 1966. Julissa nyere egwu mbụ bụ "Teacher's Pet" nke Doris Day, gụrụ ụdị ọhụrụ site n'ịgụ ya n'ụzọ dị iche n'ime egwu ọ kpọrọ "La favorita del profesor" ("Onye nkuzi kacha hụ n'anya"). === Ihe nkiri === Ọ malitere ime ihe nkiri wee malite ọrụ ebe ọ bụ onye na-emepụta ihe nkiri na Mexico na-eweta ihe nkiri Broadway a ma ama dị ka Jesus Christ Superstar, Grease, Joseph na Amazing Technicolor Dreamcoat, ''Pipin''.<ref>{{Cite web|url=http://www.broadwaymusicalhome.com|title=Broadway|publisher=broadwaymusicalhome.com|accessdate=20 July 2010}}</ref> Ọ so n'ndị na-eme ihe nkiri n'egwuregwu ''The Rocky Horror Show'';nke afọ 1975 na Mexico Aida Pierce mgbe ọ ka dị obere, so n'òtù ndị na-agụ egwu n'egwuregwu ahụ. == Ihe nkiri == <templatestyles src="Module:Message box/ambox.css"></templatestyles> === Ihe nkiri === {| class="wikitable" style="font-size: 95%;" ! style="background: #B0C4DE;" |Afọ ! style="background: #B0C4DE;" |Aha ya ! style="background: #B0C4DE;" |Ọrụ ! style="background: #B0C4DE;" |Ihe edeturu |- |1962 |''Ime Anwansi'' |Rosario | (nke a na-akpọ Julisa Macedo) |- |1963 |''Ọgwụ ọjọọ nke Llorona'' |Onye Njem Ụgbọ Mmiri nke Nwanyị | (nke a na-akpọ Julissa del Llano) aha ọzọ - The Curse of the Crying Woman''Ọgwụ Nwanyị Na-ebe ákwá'' |- |1964 |''A machibidoro Nrọ'' | | |- |1964 |''Oge Ime Ihe Ike'' | |aha ọzọ - La Edad de la Violencia (aha mbụ) |- |1964 |''N'etiti Ụwa'' | | (nke a na-akpọ Julissa Herrera) |- |1964 |''Ụmụ nwanyị nke ụmụ m nwanyị'' |Maria | |- |1964 |''Izu ohi n'ụgbọ okporo ígwè'' | | |- |1965 |''Obodo Mmụọ'' | |aha ọzọ - Ghost Town''Obodo Mmụọ'' |- |1965 |''Ekwensu n'Eluigwe'' | | |- |1965 |''Mmehie'' |Lidia |aha ọzọ - El Pecador (aha mbụ) |- |1965 |''Ndị A mụrụ Maka Abụ'' | | |- |1965 |''Dengue nke Ịhụnanya'' | | |- |1965 |''Elena Abụọ'' |Elena | |- |1966 |''Otu Nwanyị Estupenda'' |Mercedes | |- |1966 |''Anyị Ndị Ntorobịa'' |Carmen | |- |1966 |''Ịgba Goolu'' | | |- |1966 |''Ike gwụrụ m na-arịọ ya arịrịọ'' | | |- |1967 |''Pedro Páramo'' |Ana Rentería | |- |1967 |''Ọ bụrụ na achọrọ m'' | | |- |1967 |''Lee nwoke dị otú ahụ'' |Laura | |- |1967 |''Egwuregwu Dị Iche Iche'' |Claudia (nkebi "HO") | |- |1967 |''Ndị si n'èzí'' |Paloma |aha ọzọ - Los Caifanes (aha mbụ) |- |1967 |''Ụwa Nzuzu nke Ndị Ntorobịa'' | |aha ọzọ - El Mundo Loco de los Jóvenes (aha mbụ) |- |1968 |''Ụlọ Egwu'' |Corinne Mandel | |- |1968 |''Ụlọ Ihe Ọjọọ'' |Lucy Durant | |- |1968 |''Ndị Ntorobịa'' | |aha ọzọ - The Adolescentes (aha mbụ) |- |1968 |''Ịchụpụ Casada'' |Sonia Vargas | |- |1968 |''Ihe odide abalị agbamakwụkwọ'' | |aha ọzọ - Ensayo de una Noche de Bodas (aha mbụ) |- |1969 |''Santa'' |Santa | |- |1969 |Paula | | |- |1970 |''Ịgha ụgha'' | | |- |1971 |''Agwọ Agwọ'' |Anabella Vandenberg |utu aha ndị ọzọ - La Muerte Viviente (aha mbụ), Snake People''Ndị Agwọ'' |- |1971 |''Oge okpomọkụ na-ere ọkụ'' |Marilu/Maria de la Luz Flores |aha ọzọ - Hot Summer''Oge okpomọkụ'' |- |1972 |''Nwaanyị Na-akwụwa Aka ọtọ'' | | |- |1972 |''Gị, M, Anyị'' | |A họpụtara ya - Ariel Award maka onye na-eme ihe nkiri kacha mma |- |1972 |''Victoria'' | | |- |1973 |''Ndị A Na-atọrọ Nri'' |Lucía Gómez | |- |1979 |''Ịhụnanya Nwere Onwe'' | | |- |1981 |''Pachange'' |Adela, Nwunye Vicente | |- |1981 |''Ọrụ Ọchịchịrị'' | | |- |1981 |''D.F./District Federal'' | |Ariel Award maka onye na-eme ihe nkiri kachasị mma |- |1982 |''Onye a ma ama Remington'' | | |- |1982 |''Ụbọchị Agha'' |Elisa | |- |1982 |''41, nwoke zuru oke'' |Clarissa Machorro | |- |1982 |''Anya Nwatakịrị'' |Patricia | |- |1982 |Ihe Dị Mfe |Elisa Belascoaran | |- |1983 |''Carnales Abụọ'' | | |- |1984 |''A machibidoro Ịhụnanya na New York'' | | |- |1986 |''N'azụ Ọnwụ'' |Andrea/Laura | |- |1994 |''Ịhụnanya Na-egbu'' | | |- |2004 |''Onye Ime Anwansi'' |Raquel |aha ọzọ - The Magician''Onye Ime Anwansi'' |- |2005 |''Enweghị mmasị'' |Gertrudis Alcocer | |} === Ìgwè Onyonyo === {| class="wikitable" style="font-size: 95%;" ! style="background: #B0C4DE;" |Afọ ! style="background: #B0C4DE;" |Aha ya ! style="background: #B0C4DE;" |Ọrụ ! style="background: #B0C4DE;" |Ihe edeturu |- |1962 |''Ozu ndị a gbasiri agbasi na Guanajuato'' | | |- |1963 |''Doña Macabra'' | | |- |1964 |''Orfeón mbụ'' | | |- |1964 |''Onye na-abanye n'ime'' |Veronica | |- |1964 |''Ụlọ ndị agbata obi'' |Lupe | |- |1964 |''Kpakpando'' | | |- |1965 |''Ịgha ụgha'' |Veronica | |- |1966 |''Obi Anụ Ọhịa'' |Mónica Molnar del Diablo | |- |1967 |''Ógbè'' | | |- |1969 |''Mgbe Ịnwụghị Ụma'' |Estela Ballesteros | |- |1971 |''Ụgbọ mmiri nke nwanyị'' | | |- |1972-73 |''Ụmụnne Obi Ike'' |Clara Barros/Diana Lemos/Marcia | |- |1974 |''Isi iyi nke ọrụ ebube'' | | |- |1976 |''Ndị ohi nke Rio Frío'' |Cecilia | |- |1978-79 |''Akwụkwọ ozi e degaara onye e gburu'' | | |- |1979-80 |Veronica |Veronica | |- |1980-81 |''Agba'' |Rita | |- |1986 |''Oge a kara akara'' | | |- |1987-88 |''Dị Anyị Dị'' | |Onye mmepụta |- |1987 |''Onye Na-enweghị Nchịkwa'' | - |Onye na-emepụta naanị |- |1988-89 |''Ihe ịma aka dị ụtọ'' | - |Onye na-emepụta naanị |- |1989 |''Ime Ihe Ike na-adịghị Mma'' | |Ihe nkiri TV |- |1994-95 |''Mmiri na-acha odo odo'' |Lola | |- |1996 |''Onyinyo nke onye nke ọzọ'' | - |Onye na-emepụta naanị |- |2003-04 |''Ụgbọ mmiri nke nwanyị'' |Lia del Moral de Villaseñor | |- |2002 |''Site na Gayola'' |Luchis/ La Nena | |- |2004 |''Iche Cheta America!'' |Ya onwe ya | |- |2004 |''Ọnụ Anọ'' |Ya onwe ya | |- |2005 |''100 ndị Mexico kwuru'' |Ya onwe ya |1 ihe omume - Ndị Nna vs Ụmụ''Ndị Nne na Nna vs Ụmụ'' |- |2005 |''N'okpuru otu uko'' |Julissa Acosta |1 ihe omume - Nleta nke Aunt July''Nleta nke Nwanne nwanyị July'' |- |2006 |''Ihe nrite TV na akwụkwọ akụkọ 2006'' |Ya onwe ya | |- |2006 |''Abụ Anyị Kasị Mma'' |Marcela Andere de Méndez | |- |2006–07 |''Onye mara mma'' |Teresita Sáenz nke Mendiola |Ihe omume 2 |- |2007 |''Ihe nrite TV na Novelas 2007'' |Ya onwe ya | |- |2008 |''Ọkụ n'ime ọbara'' |Raquel Uribe |Ihe omume 9 |- |2009-10 |''Ịtụrụ egwu ime nrọ'' |Doña Cristina "Cristi" Jiménez vda. nke Peralta | |- |2012-13 |''N'ihi na ịhụnanya na-achịkwa'' |Doña Susana Arriaga | |- |2014 |''Dị ka okwu ahụ si kwuo'' |Gertrudis |Ihe omume: "Ịma anyaukwu na oké ọchịchọ" |- |} == Ihe nrita == <templatestyles src="Module:Message box/ambox.css"></templatestyles> === Egwú === {| class="wikitable" style="font-size: 95%;" ! style="background: #B0C4DE;" |Afọ ! style="background: #B0C4DE;" |Nsonaazụ ! style="background: #B0C4DE;" |Ihe nrite ! style="background: #B0C4DE;" |Ụdị |- |1990|{{Won}} |Diski ọla edo na nke platinum |Album nke Mbụ (Mexico) |- |1991|{{Won}} |Diski ọla edo |Album nke Mbụ (Spain) |- |1991|{{Won}} |Diski ọla edo |Album nke Abụọ (Mexico) |- |1992|{{Won}} |Onyinye Eres |Òtù Egwú Ndị Ntorobịa Kasị Mma |- |1992|{{Won}} |Diski Platinum Abụọ |Album nke Mbụ (Spain) |- |1992|{{Won}} |Diski ọla edo na diski platinum |Album nke Abụọ (Spain) |- |1993|{{Won}} |Diski ọla edo |Banda Rock (Mexico) |- |1993|{{Won}} |Onyinye Eres |Òtù Egwú Ndị Ntorobịa Kasị Mma nke Afọ |- |1994|{{Won}} |Ihe nrite Egwú nke Furia |Akara Rock |- |1994|{{Won}} |Diski ọla edo abụọ |El Album DOble (Spain) |- |1994|{{Won}} |Ihe nrite Las Palms de Oro | |- |1995|{{Won}} |Diski ọla edo |Album Hoy (Spain) |} A nabatara Julissa n'ime Paseo de las Luminarias n'afọ 1987 n'ihi ọrụ ya n'ihe nkiri, telivishọn, ihe ngosi n'elu ikpo okwu (theater), na ụlọ ọrụ ndekọ egwu, ebe ọ sonyeere ndị mụrụ ya. N'oge na-adịghị anya, a ga-etinyekwa akara aka nwanne ya nwoke n'akụkụ nke ya; e si otú a sọpụrụ mmadụ anọ niile so n'ezinụlọ De Llano-Macedo na Paseo ahụ. == Edensịbia == <templatestyles src="Reflist/styles.css" />  == Njikọ mpụga == * {{IMDb name|0215612}} * [https://web.archive.org/web/20100127163125/http://www.julissa.com.mx/ Ebe nrụọrụ weebụ gọọmentị] [[Otú:Mmadụ ndi di ndụ]] [[Otú:Articles with hCards]] == Mbido ndụ na ọrụ == === Egwú === Mgbe ọ dị afọ 14, Julissa malitere ọrụ egwu ya n'otu egwu ụdị 'rock' a na-akpọ The Spitfires; nwanne ya nwoke bụ Luis hiwere otu egwu a. O nwetara ọnọdụ nke abụọ n'asọmpi redio tupu ụlọ ọrụ CBS abanye ya n'akwụkwọ nkwekọrịta, o wee dekọọ ọtụtụ abọm egwu 'rock' n'etiti afọ 1961 na 1964. O dekọrọ otu egwu (nke a na-akpọ 'single') nwere aha bụ "Corazón Salvaje / Te Necesito," nke ụlọ ọrụ Capitol Records na afọ 1966. wepụtara n'afọ 1966. Julissa nyere egwu mbụ bụ "Teacher's Pet" nke Doris Day, gụrụ ụdị ọhụrụ site n'ịgụ ya n'ụzọ dị iche n'ime egwu ọ kpọrọ "La favorita del profesor" ("Onye nkuzi kacha hụ n'anya"). === Ihe nkiri === Ọ malitere ime ihe nkiri wee malite ọrụ ebe ọ bụ onye na-emepụta ihe nkiri na Mexico na-eweta ihe nkiri Broadway a ma ama dị ka Jesus Christ Superstar, Grease, Joseph na Amazing Technicolor Dreamcoat, ''Pipin''.<ref>{{Cite web |title=Broadway |url=http://www.broadwaymusicalhome.com |accessdate=20 July 2010 |publisher=broadwaymusicalhome.com}}</ref> Ọ so n'ndị na-eme ihe nkiri n'egwuregwu ''The Rocky Horror Show'';nke afọ 1975 na Mexico Aida Pierce mgbe ọ ka dị obere, so n'òtù ndị na-agụ egwu n'egwuregwu ahụ. == Ihe nkiri ==   === Ihe nkiri === {| class="wikitable" style="font-size: 95%;" ! style="background: #B0C4DE;" |Afọ ! style="background: #B0C4DE;" |Aha ya ! style="background: #B0C4DE;" |Ọrụ ! style="background: #B0C4DE;" |Ihe edeturu |- |1962 |''Ime Anwansi'' |Rosario | (nke a na-akpọ Julisa Macedo) |- |1963 |''Ọgwụ ọjọọ nke Llorona'' |Onye Njem Ụgbọ Mmiri nke Nwanyị | (nke a na-akpọ Julissa del Llano) aha ọzọ - The Curse of the Crying Woman''Ọgwụ Nwanyị Na-ebe ákwá'' |- |1964 |''A machibidoro Nrọ'' | | |- |1964 |''Oge Ime Ihe Ike'' | |aha ọzọ - La Edad de la Violencia (aha mbụ) |- |1964 |''N'etiti Ụwa'' | | (nke a na-akpọ Julissa Herrera) |- |1964 |''Ụmụ nwanyị nke ụmụ m nwanyị'' |Maria | |- |1964 |''Izu ohi n'ụgbọ okporo ígwè'' | | |- |1965 |''Obodo Mmụọ'' | |aha ọzọ - Ghost Town''Obodo Mmụọ'' |- |1965 |''Ekwensu n'Eluigwe'' | | |- |1965 |''Mmehie'' |Lidia |aha ọzọ - El Pecador (aha mbụ) |- |1965 |''Ndị A mụrụ Maka Abụ'' | | |- |1965 |''Dengue nke Ịhụnanya'' | | |- |1965 |''Elena Abụọ'' |Elena | |- |1966 |''Otu Nwanyị Estupenda'' |Mercedes | |- |1966 |''Anyị Ndị Ntorobịa'' |Carmen | |- |1966 |''Ịgba Goolu'' | | |- |1966 |''Ike gwụrụ m na-arịọ ya arịrịọ'' | | |- |1967 |''Pedro Páramo'' |Ana Rentería | |- |1967 |''Ọ bụrụ na achọrọ m'' | | |- |1967 |''Lee nwoke dị otú ahụ'' |Laura | |- |1967 |''Egwuregwu Dị Iche Iche'' |Claudia (nkebi "HO") | |- |1967 |''Ndị si n'èzí'' |Paloma |aha ọzọ - Los Caifanes (aha mbụ) |- |1967 |''Ụwa Nzuzu nke Ndị Ntorobịa'' | |aha ọzọ - El Mundo Loco de los Jóvenes (aha mbụ) |- |1968 |''Ụlọ Egwu'' |Corinne Mandel | |- |1968 |''Ụlọ Ihe Ọjọọ'' |Lucy Durant | |- |1968 |''Ndị Ntorobịa'' | |aha ọzọ - The Adolescentes (aha mbụ) |- |1968 |''Ịchụpụ Casada'' |Sonia Vargas | |- |1968 |''Ihe odide abalị agbamakwụkwọ'' | |aha ọzọ - Ensayo de una Noche de Bodas (aha mbụ) |- |1969 |''Santa'' |Santa | |- |1969 |Paula | | |- |1970 |''Ịgha ụgha'' | | |- |1971 |''Agwọ Agwọ'' |Anabella Vandenberg |utu aha ndị ọzọ - La Muerte Viviente (aha mbụ), Snake People''Ndị Agwọ'' |- |1971 |''Oge okpomọkụ na-ere ọkụ'' |Marilu/Maria de la Luz Flores |aha ọzọ - Hot Summer''Oge okpomọkụ'' |- |1972 |''Nwaanyị Na-akwụwa Aka ọtọ'' | | |- |1972 |''Gị, M, Anyị'' | |A họpụtara ya - Ariel Award maka onye na-eme ihe nkiri kacha mma |- |1972 |''Victoria'' | | |- |1973 |''Ndị A Na-atọrọ Nri'' |Lucía Gómez | |- |1979 |''Ịhụnanya Nwere Onwe'' | | |- |1981 |''Pachange'' |Adela, Nwunye Vicente | |- |1981 |''Ọrụ Ọchịchịrị'' | | |- |1981 |''D.F./District Federal'' | |Ariel Award maka onye na-eme ihe nkiri kachasị mma |- |1982 |''Onye a ma ama Remington'' | | |- |1982 |''Ụbọchị Agha'' |Elisa | |- |1982 |''41, nwoke zuru oke'' |Clarissa Machorro | |- |1982 |''Anya Nwatakịrị'' |Patricia | |- |1982 |Ihe Dị Mfe |Elisa Belascoaran | |- |1983 |''Carnales Abụọ'' | | |- |1984 |''A machibidoro Ịhụnanya na New York'' | | |- |1986 |''N'azụ Ọnwụ'' |Andrea/Laura | |- |1994 |''Ịhụnanya Na-egbu'' | | |- |2004 |''Onye Ime Anwansi'' |Raquel |aha ọzọ - The Magician''Onye Ime Anwansi'' |- |2005 |''Enweghị mmasị'' |Gertrudis Alcocer | |} === Ìgwè Onyonyo === {| class="wikitable" style="font-size: 95%;" ! style="background: #B0C4DE;" |Afọ ! style="background: #B0C4DE;" |Aha ya ! style="background: #B0C4DE;" |Ọrụ ! style="background: #B0C4DE;" |Ihe edeturu |- |1962 |''Ozu ndị a gbasiri agbasi na Guanajuato'' | | |- |1963 |''Doña Macabra'' | | |- |1964 |''Orfeón mbụ'' | | |- |1964 |''Onye na-abanye n'ime'' |Veronica | |- |1964 |''Ụlọ ndị agbata obi'' |Lupe | |- |1964 |''Kpakpando'' | | |- |1965 |''Ịgha ụgha'' |Veronica | |- |1966 |''Obi Anụ Ọhịa'' |Mónica Molnar del Diablo | |- |1967 |''Ógbè'' | | |- |1969 |''Mgbe Ịnwụghị Ụma'' |Estela Ballesteros | |- |1971 |''Ụgbọ mmiri nke nwanyị'' | | |- |1972-73 |''Ụmụnne Obi Ike'' |Clara Barros/Diana Lemos/Marcia | |- |1974 |''Isi iyi nke ọrụ ebube'' | | |- |1976 |''Ndị ohi nke Rio Frío'' |Cecilia | |- |1978-79 |''Akwụkwọ ozi e degaara onye e gburu'' | | |- |1979-80 |Veronica |Veronica | |- |1980-81 |''Agba'' |Rita | |- |1986 |''Oge a kara akara'' | | |- |1987-88 |''Dị Anyị Dị'' | |Onye mmepụta |- |1987 |''Onye Na-enweghị Nchịkwa'' | - |Onye na-emepụta naanị |- |1988-89 |''Ihe ịma aka dị ụtọ'' | - |Onye na-emepụta naanị |- |1989 |''Ime Ihe Ike na-adịghị Mma'' | |Ihe nkiri TV |- |1994-95 |''Mmiri na-acha odo odo'' |Lola | |- |1996 |''Onyinyo nke onye nke ọzọ'' | - |Onye na-emepụta naanị |- |2003-04 |''Ụgbọ mmiri nke nwanyị'' |Lia del Moral de Villaseñor | |- |2002 |''Site na Gayola'' |Luchis/ La Nena | |- |2004 |''Iche Cheta America!'' |Ya onwe ya | |- |2004 |''Ọnụ Anọ'' |Ya onwe ya | |- |2005 |''100 ndị Mexico kwuru'' |Ya onwe ya |1 ihe omume - Ndị Nna vs Ụmụ''Ndị Nne na Nna vs Ụmụ'' |- |2005 |''N'okpuru otu uko'' |Julissa Acosta |1 ihe omume - Nleta nke Aunt July''Nleta nke Nwanne nwanyị July'' |- |2006 |''Ihe nrite TV na akwụkwọ akụkọ 2006'' |Ya onwe ya | |- |2006 |''Abụ Anyị Kasị Mma'' |Marcela Andere de Méndez | |- |2006–07 |''Onye mara mma'' |Teresita Sáenz nke Mendiola |Ihe omume 2 |- |2007 |''Ihe nrite TV na Novelas 2007'' |Ya onwe ya | |- |2008 |''Ọkụ n'ime ọbara'' |Raquel Uribe |Ihe omume 9 |- |2009-10 |''Ịtụrụ egwu ime nrọ'' |Doña Cristina "Cristi" Jiménez vda. nke Peralta | |- |2012-13 |''N'ihi na ịhụnanya na-achịkwa'' |Doña Susana Arriaga | |- |2014 |''Dị ka okwu ahụ si kwuo'' |Gertrudis |Ihe omume: "Ịma anyaukwu na oké ọchịchọ" |- |} == Ihe nrita == === Egwú === {| class="wikitable" style="font-size: 95%;" ! style="background: #B0C4DE;" |Afọ ! style="background: #B0C4DE;" |Nsonaazụ ! style="background: #B0C4DE;" |Ihe nrite ! style="background: #B0C4DE;" |Ụdị |- |1990|{{Won}} |Diski ọla edo na nke platinum |Album nke Mbụ (Mexico) |- |1991|{{Won}} |Diski ọla edo |Album nke Mbụ (Spain) |- |1991|{{Won}} |Diski ọla edo |Album nke Abụọ (Mexico) |- |1992|{{Won}} |Onyinye Eres |Òtù Egwú Ndị Ntorobịa Kasị Mma |- |1992|{{Won}} |Diski Platinum Abụọ |Album nke Mbụ (Spain) |- |1992|{{Won}} |Diski ọla edo na diski platinum |Album nke Abụọ (Spain) |- |1993|{{Won}} |Diski ọla edo |Banda Rock (Mexico) |- |1993|{{Won}} |Onyinye Eres |Òtù Egwú Ndị Ntorobịa Kasị Mma nke Afọ |- |1994|{{Won}} |Ihe nrite Egwú nke Furia |Akara Rock |- |1994|{{Won}} |Diski ọla edo abụọ |El Album DOble (Spain) |- |1994|{{Won}} |Ihe nrite Las Palms de Oro | |- |1995|{{Won}} |Diski ọla edo |Album Hoy (Spain) |} A nabatara Julissa n'ime Paseo de las Luminarias n'afọ 1987 n'ihi ọrụ ya n'ihe nkiri, telivishọn, ihe ngosi n'elu ikpo okwu (theater), na ụlọ ọrụ ndekọ egwu, ebe ọ sonyeere ndị mụrụ ya. N'oge na-adịghị anya, a ga-etinyekwa akara aka nwanne ya nwoke n'akụkụ nke ya; e si otú a sọpụrụ mmadụ anọ niile so n'ezinụlọ De Llano-Macedo na Paseo ahụ. == Edensịbia == {{Reflist}}   == Njikọ mpụga == * {{IMDb name|0215612}} * [https://web.archive.org/web/20100127163125/http://www.julissa.com.mx/ Ebe nrụọrụ weebụ gọọmentị] 7i6ixhxjdaumo0zwmhn68ibsuy9a3b7 736821 736820 2026-10-07T17:40:47Z Juliegwen 12936 /* Egwú */ 736821 wikitext text/x-wiki <templatestyles src="Module:Hatnote/styles.css"></templatestyles><templatestyles src="Module:Message box/ambox.css"></templatestyles><templatestyles src="Module:Infobox/styles.css"></templatestyles>  '''Julia Isabel de Llano Macedo''' (amụrụ na 8 Eprel 1944), nke a maara dịka '''Julissa''', bụ onye na-eme ihe nkiri, onye na-emepụta ihe, na onye na-agụ egwu na Mexico. Ọ bụ nwa nwanyị nke onye na-eme ihe nkiri na redio na telivishọn Luis de Llano Palmer na onye na-ese ihe nkiri Rita Macedo. Ụmụ ya gụnyere Benny Ibarra, onye na-agụ egwu na onye na-eti egwu, na Alejandro Ibarra, Onye na-eme ihe nkiri na onye na na-agụ egwú. Nwanne ya nwoke, Luis de Llano Macedo, arụwo ọrụ dị ka onye na-emepụta ihe maka Televisa. == Mbido ndụ na ọrụ == === Egwú === Mgbe ọ dị afọ 14, Julissa malitere ọrụ egwu ya n'otu egwu ụdị 'rock' a na-akpọ The Spitfires; nwanne ya nwoke bụ Luis hiwere otu egwu a. O nwetara ọnọdụ nke abụọ n'asọmpi redio tupu ụlọ ọrụ CBS abanye ya n'akwụkwọ nkwekọrịta, o wee dekọọ ọtụtụ abọm egwu 'rock' n'etiti afọ 1961 na 1964. O dekọrọ otu egwu (nke a na-akpọ 'single') nwere aha bụ "Corazón Salvaje / Te Necesito," nke ụlọ ọrụ Capitol Records na afọ 1966. wepụtara n'afọ 1966. Julissa nyere egwu mbụ bụ "Teacher's Pet" nke Doris Day, gụrụ ụdị ọhụrụ site n'ịgụ ya n'ụzọ dị iche n'ime egwu ọ kpọrọ "La favorita del profesor" ("Onye nkuzi kacha hụ n'anya"). === Ihe nkiri === Ọ malitere ime ihe nkiri wee malite ọrụ ebe ọ bụ onye na-emepụta ihe nkiri na Mexico na-eweta ihe nkiri Broadway a ma ama dị ka Jesus Christ Superstar, Grease, Joseph na Amazing Technicolor Dreamcoat, ''Pipin''.<ref>{{Cite web|url=http://www.broadwaymusicalhome.com|title=Broadway|publisher=broadwaymusicalhome.com|accessdate=20 July 2010}}</ref> Ọ so n'ndị na-eme ihe nkiri n'egwuregwu ''The Rocky Horror Show'';nke afọ 1975 na Mexico Aida Pierce mgbe ọ ka dị obere, so n'òtù ndị na-agụ egwu n'egwuregwu ahụ. == Ihe nkiri == <templatestyles src="Module:Message box/ambox.css"></templatestyles> === Ihe nkiri === {| class="wikitable" style="font-size: 95%;" ! style="background: #B0C4DE;" |Afọ ! style="background: #B0C4DE;" |Aha ya ! style="background: #B0C4DE;" |Ọrụ ! style="background: #B0C4DE;" |Ihe edeturu |- |1962 |''Ime Anwansi'' |Rosario | (nke a na-akpọ Julisa Macedo) |- |1963 |''Ọgwụ ọjọọ nke Llorona'' |Onye Njem Ụgbọ Mmiri nke Nwanyị | (nke a na-akpọ Julissa del Llano) aha ọzọ - The Curse of the Crying Woman''Ọgwụ Nwanyị Na-ebe ákwá'' |- |1964 |''A machibidoro Nrọ'' | | |- |1964 |''Oge Ime Ihe Ike'' | |aha ọzọ - La Edad de la Violencia (aha mbụ) |- |1964 |''N'etiti Ụwa'' | | (nke a na-akpọ Julissa Herrera) |- |1964 |''Ụmụ nwanyị nke ụmụ m nwanyị'' |Maria | |- |1964 |''Izu ohi n'ụgbọ okporo ígwè'' | | |- |1965 |''Obodo Mmụọ'' | |aha ọzọ - Ghost Town''Obodo Mmụọ'' |- |1965 |''Ekwensu n'Eluigwe'' | | |- |1965 |''Mmehie'' |Lidia |aha ọzọ - El Pecador (aha mbụ) |- |1965 |''Ndị A mụrụ Maka Abụ'' | | |- |1965 |''Dengue nke Ịhụnanya'' | | |- |1965 |''Elena Abụọ'' |Elena | |- |1966 |''Otu Nwanyị Estupenda'' |Mercedes | |- |1966 |''Anyị Ndị Ntorobịa'' |Carmen | |- |1966 |''Ịgba Goolu'' | | |- |1966 |''Ike gwụrụ m na-arịọ ya arịrịọ'' | | |- |1967 |''Pedro Páramo'' |Ana Rentería | |- |1967 |''Ọ bụrụ na achọrọ m'' | | |- |1967 |''Lee nwoke dị otú ahụ'' |Laura | |- |1967 |''Egwuregwu Dị Iche Iche'' |Claudia (nkebi "HO") | |- |1967 |''Ndị si n'èzí'' |Paloma |aha ọzọ - Los Caifanes (aha mbụ) |- |1967 |''Ụwa Nzuzu nke Ndị Ntorobịa'' | |aha ọzọ - El Mundo Loco de los Jóvenes (aha mbụ) |- |1968 |''Ụlọ Egwu'' |Corinne Mandel | |- |1968 |''Ụlọ Ihe Ọjọọ'' |Lucy Durant | |- |1968 |''Ndị Ntorobịa'' | |aha ọzọ - The Adolescentes (aha mbụ) |- |1968 |''Ịchụpụ Casada'' |Sonia Vargas | |- |1968 |''Ihe odide abalị agbamakwụkwọ'' | |aha ọzọ - Ensayo de una Noche de Bodas (aha mbụ) |- |1969 |''Santa'' |Santa | |- |1969 |Paula | | |- |1970 |''Ịgha ụgha'' | | |- |1971 |''Agwọ Agwọ'' |Anabella Vandenberg |utu aha ndị ọzọ - La Muerte Viviente (aha mbụ), Snake People''Ndị Agwọ'' |- |1971 |''Oge okpomọkụ na-ere ọkụ'' |Marilu/Maria de la Luz Flores |aha ọzọ - Hot Summer''Oge okpomọkụ'' |- |1972 |''Nwaanyị Na-akwụwa Aka ọtọ'' | | |- |1972 |''Gị, M, Anyị'' | |A họpụtara ya - Ariel Award maka onye na-eme ihe nkiri kacha mma |- |1972 |''Victoria'' | | |- |1973 |''Ndị A Na-atọrọ Nri'' |Lucía Gómez | |- |1979 |''Ịhụnanya Nwere Onwe'' | | |- |1981 |''Pachange'' |Adela, Nwunye Vicente | |- |1981 |''Ọrụ Ọchịchịrị'' | | |- |1981 |''D.F./District Federal'' | |Ariel Award maka onye na-eme ihe nkiri kachasị mma |- |1982 |''Onye a ma ama Remington'' | | |- |1982 |''Ụbọchị Agha'' |Elisa | |- |1982 |''41, nwoke zuru oke'' |Clarissa Machorro | |- |1982 |''Anya Nwatakịrị'' |Patricia | |- |1982 |Ihe Dị Mfe |Elisa Belascoaran | |- |1983 |''Carnales Abụọ'' | | |- |1984 |''A machibidoro Ịhụnanya na New York'' | | |- |1986 |''N'azụ Ọnwụ'' |Andrea/Laura | |- |1994 |''Ịhụnanya Na-egbu'' | | |- |2004 |''Onye Ime Anwansi'' |Raquel |aha ọzọ - The Magician''Onye Ime Anwansi'' |- |2005 |''Enweghị mmasị'' |Gertrudis Alcocer | |} === Ìgwè Onyonyo === {| class="wikitable" style="font-size: 95%;" ! style="background: #B0C4DE;" |Afọ ! style="background: #B0C4DE;" |Aha ya ! style="background: #B0C4DE;" |Ọrụ ! style="background: #B0C4DE;" |Ihe edeturu |- |1962 |''Ozu ndị a gbasiri agbasi na Guanajuato'' | | |- |1963 |''Doña Macabra'' | | |- |1964 |''Orfeón mbụ'' | | |- |1964 |''Onye na-abanye n'ime'' |Veronica | |- |1964 |''Ụlọ ndị agbata obi'' |Lupe | |- |1964 |''Kpakpando'' | | |- |1965 |''Ịgha ụgha'' |Veronica | |- |1966 |''Obi Anụ Ọhịa'' |Mónica Molnar del Diablo | |- |1967 |''Ógbè'' | | |- |1969 |''Mgbe Ịnwụghị Ụma'' |Estela Ballesteros | |- |1971 |''Ụgbọ mmiri nke nwanyị'' | | |- |1972-73 |''Ụmụnne Obi Ike'' |Clara Barros/Diana Lemos/Marcia | |- |1974 |''Isi iyi nke ọrụ ebube'' | | |- |1976 |''Ndị ohi nke Rio Frío'' |Cecilia | |- |1978-79 |''Akwụkwọ ozi e degaara onye e gburu'' | | |- |1979-80 |Veronica |Veronica | |- |1980-81 |''Agba'' |Rita | |- |1986 |''Oge a kara akara'' | | |- |1987-88 |''Dị Anyị Dị'' | |Onye mmepụta |- |1987 |''Onye Na-enweghị Nchịkwa'' | - |Onye na-emepụta naanị |- |1988-89 |''Ihe ịma aka dị ụtọ'' | - |Onye na-emepụta naanị |- |1989 |''Ime Ihe Ike na-adịghị Mma'' | |Ihe nkiri TV |- |1994-95 |''Mmiri na-acha odo odo'' |Lola | |- |1996 |''Onyinyo nke onye nke ọzọ'' | - |Onye na-emepụta naanị |- |2003-04 |''Ụgbọ mmiri nke nwanyị'' |Lia del Moral de Villaseñor | |- |2002 |''Site na Gayola'' |Luchis/ La Nena | |- |2004 |''Iche Cheta America!'' |Ya onwe ya | |- |2004 |''Ọnụ Anọ'' |Ya onwe ya | |- |2005 |''100 ndị Mexico kwuru'' |Ya onwe ya |1 ihe omume - Ndị Nna vs Ụmụ''Ndị Nne na Nna vs Ụmụ'' |- |2005 |''N'okpuru otu uko'' |Julissa Acosta |1 ihe omume - Nleta nke Aunt July''Nleta nke Nwanne nwanyị July'' |- |2006 |''Ihe nrite TV na akwụkwọ akụkọ 2006'' |Ya onwe ya | |- |2006 |''Abụ Anyị Kasị Mma'' |Marcela Andere de Méndez | |- |2006–07 |''Onye mara mma'' |Teresita Sáenz nke Mendiola |Ihe omume 2 |- |2007 |''Ihe nrite TV na Novelas 2007'' |Ya onwe ya | |- |2008 |''Ọkụ n'ime ọbara'' |Raquel Uribe |Ihe omume 9 |- |2009-10 |''Ịtụrụ egwu ime nrọ'' |Doña Cristina "Cristi" Jiménez vda. nke Peralta | |- |2012-13 |''N'ihi na ịhụnanya na-achịkwa'' |Doña Susana Arriaga | |- |2014 |''Dị ka okwu ahụ si kwuo'' |Gertrudis |Ihe omume: "Ịma anyaukwu na oké ọchịchọ" |- |} == Ihe nrita == <templatestyles src="Module:Message box/ambox.css"></templatestyles> === Egwú === A nabatara Julissa n'ime Paseo de las Luminarias n'afọ 1987 n'ihi ọrụ ya n'ihe nkiri, telivishọn, ihe ngosi n'elu ikpo okwu (theater), na ụlọ ọrụ ndekọ egwu, ebe ọ sonyeere ndị mụrụ ya. N'oge na-adịghị anya, a ga-etinyekwa akara aka nwanne ya nwoke n'akụkụ nke ya; e si otú a sọpụrụ mmadụ anọ niile so n'ezinụlọ De Llano-Macedo na Paseo ahụ. == Edensịbia == <templatestyles src="Reflist/styles.css" />  == Njikọ mpụga == * {{IMDb name|0215612}} * [https://web.archive.org/web/20100127163125/http://www.julissa.com.mx/ Ebe nrụọrụ weebụ gọọmentị] [[Otú:Mmadụ ndi di ndụ]] [[Otú:Articles with hCards]] == Mbido ndụ na ọrụ == === Egwú === Mgbe ọ dị afọ 14, Julissa malitere ọrụ egwu ya n'otu egwu ụdị 'rock' a na-akpọ The Spitfires; nwanne ya nwoke bụ Luis hiwere otu egwu a. O nwetara ọnọdụ nke abụọ n'asọmpi redio tupu ụlọ ọrụ CBS abanye ya n'akwụkwọ nkwekọrịta, o wee dekọọ ọtụtụ abọm egwu 'rock' n'etiti afọ 1961 na 1964. O dekọrọ otu egwu (nke a na-akpọ 'single') nwere aha bụ "Corazón Salvaje / Te Necesito," nke ụlọ ọrụ Capitol Records na afọ 1966. wepụtara n'afọ 1966. Julissa nyere egwu mbụ bụ "Teacher's Pet" nke Doris Day, gụrụ ụdị ọhụrụ site n'ịgụ ya n'ụzọ dị iche n'ime egwu ọ kpọrọ "La favorita del profesor" ("Onye nkuzi kacha hụ n'anya"). === Ihe nkiri === Ọ malitere ime ihe nkiri wee malite ọrụ ebe ọ bụ onye na-emepụta ihe nkiri na Mexico na-eweta ihe nkiri Broadway a ma ama dị ka Jesus Christ Superstar, Grease, Joseph na Amazing Technicolor Dreamcoat, ''Pipin''.<ref>{{Cite web |title=Broadway |url=http://www.broadwaymusicalhome.com |accessdate=20 July 2010 |publisher=broadwaymusicalhome.com}}</ref> Ọ so n'ndị na-eme ihe nkiri n'egwuregwu ''The Rocky Horror Show'';nke afọ 1975 na Mexico Aida Pierce mgbe ọ ka dị obere, so n'òtù ndị na-agụ egwu n'egwuregwu ahụ. == Ihe nkiri ==   === Ihe nkiri === {| class="wikitable" style="font-size: 95%;" ! style="background: #B0C4DE;" |Afọ ! style="background: #B0C4DE;" |Aha ya ! style="background: #B0C4DE;" |Ọrụ ! style="background: #B0C4DE;" |Ihe edeturu |- |1962 |''Ime Anwansi'' |Rosario | (nke a na-akpọ Julisa Macedo) |- |1963 |''Ọgwụ ọjọọ nke Llorona'' |Onye Njem Ụgbọ Mmiri nke Nwanyị | (nke a na-akpọ Julissa del Llano) aha ọzọ - The Curse of the Crying Woman''Ọgwụ Nwanyị Na-ebe ákwá'' |- |1964 |''A machibidoro Nrọ'' | | |- |1964 |''Oge Ime Ihe Ike'' | |aha ọzọ - La Edad de la Violencia (aha mbụ) |- |1964 |''N'etiti Ụwa'' | | (nke a na-akpọ Julissa Herrera) |- |1964 |''Ụmụ nwanyị nke ụmụ m nwanyị'' |Maria | |- |1964 |''Izu ohi n'ụgbọ okporo ígwè'' | | |- |1965 |''Obodo Mmụọ'' | |aha ọzọ - Ghost Town''Obodo Mmụọ'' |- |1965 |''Ekwensu n'Eluigwe'' | | |- |1965 |''Mmehie'' |Lidia |aha ọzọ - El Pecador (aha mbụ) |- |1965 |''Ndị A mụrụ Maka Abụ'' | | |- |1965 |''Dengue nke Ịhụnanya'' | | |- |1965 |''Elena Abụọ'' |Elena | |- |1966 |''Otu Nwanyị Estupenda'' |Mercedes | |- |1966 |''Anyị Ndị Ntorobịa'' |Carmen | |- |1966 |''Ịgba Goolu'' | | |- |1966 |''Ike gwụrụ m na-arịọ ya arịrịọ'' | | |- |1967 |''Pedro Páramo'' |Ana Rentería | |- |1967 |''Ọ bụrụ na achọrọ m'' | | |- |1967 |''Lee nwoke dị otú ahụ'' |Laura | |- |1967 |''Egwuregwu Dị Iche Iche'' |Claudia (nkebi "HO") | |- |1967 |''Ndị si n'èzí'' |Paloma |aha ọzọ - Los Caifanes (aha mbụ) |- |1967 |''Ụwa Nzuzu nke Ndị Ntorobịa'' | |aha ọzọ - El Mundo Loco de los Jóvenes (aha mbụ) |- |1968 |''Ụlọ Egwu'' |Corinne Mandel | |- |1968 |''Ụlọ Ihe Ọjọọ'' |Lucy Durant | |- |1968 |''Ndị Ntorobịa'' | |aha ọzọ - The Adolescentes (aha mbụ) |- |1968 |''Ịchụpụ Casada'' |Sonia Vargas | |- |1968 |''Ihe odide abalị agbamakwụkwọ'' | |aha ọzọ - Ensayo de una Noche de Bodas (aha mbụ) |- |1969 |''Santa'' |Santa | |- |1969 |Paula | | |- |1970 |''Ịgha ụgha'' | | |- |1971 |''Agwọ Agwọ'' |Anabella Vandenberg |utu aha ndị ọzọ - La Muerte Viviente (aha mbụ), Snake People''Ndị Agwọ'' |- |1971 |''Oge okpomọkụ na-ere ọkụ'' |Marilu/Maria de la Luz Flores |aha ọzọ - Hot Summer''Oge okpomọkụ'' |- |1972 |''Nwaanyị Na-akwụwa Aka ọtọ'' | | |- |1972 |''Gị, M, Anyị'' | |A họpụtara ya - Ariel Award maka onye na-eme ihe nkiri kacha mma |- |1972 |''Victoria'' | | |- |1973 |''Ndị A Na-atọrọ Nri'' |Lucía Gómez | |- |1979 |''Ịhụnanya Nwere Onwe'' | | |- |1981 |''Pachange'' |Adela, Nwunye Vicente | |- |1981 |''Ọrụ Ọchịchịrị'' | | |- |1981 |''D.F./District Federal'' | |Ariel Award maka onye na-eme ihe nkiri kachasị mma |- |1982 |''Onye a ma ama Remington'' | | |- |1982 |''Ụbọchị Agha'' |Elisa | |- |1982 |''41, nwoke zuru oke'' |Clarissa Machorro | |- |1982 |''Anya Nwatakịrị'' |Patricia | |- |1982 |Ihe Dị Mfe |Elisa Belascoaran | |- |1983 |''Carnales Abụọ'' | | |- |1984 |''A machibidoro Ịhụnanya na New York'' | | |- |1986 |''N'azụ Ọnwụ'' |Andrea/Laura | |- |1994 |''Ịhụnanya Na-egbu'' | | |- |2004 |''Onye Ime Anwansi'' |Raquel |aha ọzọ - The Magician''Onye Ime Anwansi'' |- |2005 |''Enweghị mmasị'' |Gertrudis Alcocer | |} === Ìgwè Onyonyo === {| class="wikitable" style="font-size: 95%;" ! style="background: #B0C4DE;" |Afọ ! style="background: #B0C4DE;" |Aha ya ! style="background: #B0C4DE;" |Ọrụ ! style="background: #B0C4DE;" |Ihe edeturu |- |1962 |''Ozu ndị a gbasiri agbasi na Guanajuato'' | | |- |1963 |''Doña Macabra'' | | |- |1964 |''Orfeón mbụ'' | | |- |1964 |''Onye na-abanye n'ime'' |Veronica | |- |1964 |''Ụlọ ndị agbata obi'' |Lupe | |- |1964 |''Kpakpando'' | | |- |1965 |''Ịgha ụgha'' |Veronica | |- |1966 |''Obi Anụ Ọhịa'' |Mónica Molnar del Diablo | |- |1967 |''Ógbè'' | | |- |1969 |''Mgbe Ịnwụghị Ụma'' |Estela Ballesteros | |- |1971 |''Ụgbọ mmiri nke nwanyị'' | | |- |1972-73 |''Ụmụnne Obi Ike'' |Clara Barros/Diana Lemos/Marcia | |- |1974 |''Isi iyi nke ọrụ ebube'' | | |- |1976 |''Ndị ohi nke Rio Frío'' |Cecilia | |- |1978-79 |''Akwụkwọ ozi e degaara onye e gburu'' | | |- |1979-80 |Veronica |Veronica | |- |1980-81 |''Agba'' |Rita | |- |1986 |''Oge a kara akara'' | | |- |1987-88 |''Dị Anyị Dị'' | |Onye mmepụta |- |1987 |''Onye Na-enweghị Nchịkwa'' | - |Onye na-emepụta naanị |- |1988-89 |''Ihe ịma aka dị ụtọ'' | - |Onye na-emepụta naanị |- |1989 |''Ime Ihe Ike na-adịghị Mma'' | |Ihe nkiri TV |- |1994-95 |''Mmiri na-acha odo odo'' |Lola | |- |1996 |''Onyinyo nke onye nke ọzọ'' | - |Onye na-emepụta naanị |- |2003-04 |''Ụgbọ mmiri nke nwanyị'' |Lia del Moral de Villaseñor | |- |2002 |''Site na Gayola'' |Luchis/ La Nena | |- |2004 |''Iche Cheta America!'' |Ya onwe ya | |- |2004 |''Ọnụ Anọ'' |Ya onwe ya | |- |2005 |''100 ndị Mexico kwuru'' |Ya onwe ya |1 ihe omume - Ndị Nna vs Ụmụ''Ndị Nne na Nna vs Ụmụ'' |- |2005 |''N'okpuru otu uko'' |Julissa Acosta |1 ihe omume - Nleta nke Aunt July''Nleta nke Nwanne nwanyị July'' |- |2006 |''Ihe nrite TV na akwụkwọ akụkọ 2006'' |Ya onwe ya | |- |2006 |''Abụ Anyị Kasị Mma'' |Marcela Andere de Méndez | |- |2006–07 |''Onye mara mma'' |Teresita Sáenz nke Mendiola |Ihe omume 2 |- |2007 |''Ihe nrite TV na Novelas 2007'' |Ya onwe ya | |- |2008 |''Ọkụ n'ime ọbara'' |Raquel Uribe |Ihe omume 9 |- |2009-10 |''Ịtụrụ egwu ime nrọ'' |Doña Cristina "Cristi" Jiménez vda. nke Peralta | |- |2012-13 |''N'ihi na ịhụnanya na-achịkwa'' |Doña Susana Arriaga | |- |2014 |''Dị ka okwu ahụ si kwuo'' |Gertrudis |Ihe omume: "Ịma anyaukwu na oké ọchịchọ" |- |} == Ihe nrita == === Egwú === {| class="wikitable" style="font-size: 95%;" ! style="background: #B0C4DE;" |Afọ ! style="background: #B0C4DE;" |Nsonaazụ ! style="background: #B0C4DE;" |Ihe nrite ! style="background: #B0C4DE;" |Ụdị |- |1990|{{Won}} |Diski ọla edo na nke platinum |Album nke Mbụ (Mexico) |- |1991|{{Won}} |Diski ọla edo |Album nke Mbụ (Spain) |- |1991|{{Won}} |Diski ọla edo |Album nke Abụọ (Mexico) |- |1992|{{Won}} |Onyinye Eres |Òtù Egwú Ndị Ntorobịa Kasị Mma |- |1992|{{Won}} |Diski Platinum Abụọ |Album nke Mbụ (Spain) |- |1992|{{Won}} |Diski ọla edo na diski platinum |Album nke Abụọ (Spain) |- |1993|{{Won}} |Diski ọla edo |Banda Rock (Mexico) |- |1993|{{Won}} |Onyinye Eres |Òtù Egwú Ndị Ntorobịa Kasị Mma nke Afọ |- |1994|{{Won}} |Ihe nrite Egwú nke Furia |Akara Rock |- |1994|{{Won}} |Diski ọla edo abụọ |El Album DOble (Spain) |- |1994|{{Won}} |Ihe nrite Las Palms de Oro | |- |1995|{{Won}} |Diski ọla edo |Album Hoy (Spain) |} A nabatara Julissa n'ime Paseo de las Luminarias n'afọ 1987 n'ihi ọrụ ya n'ihe nkiri, telivishọn, ihe ngosi n'elu ikpo okwu (theater), na ụlọ ọrụ ndekọ egwu, ebe ọ sonyeere ndị mụrụ ya. N'oge na-adịghị anya, a ga-etinyekwa akara aka nwanne ya nwoke n'akụkụ nke ya; e si otú a sọpụrụ mmadụ anọ niile so n'ezinụlọ De Llano-Macedo na Paseo ahụ. == Edensịbia == {{Reflist}}   == Njikọ mpụga == * {{IMDb name|0215612}} * [https://web.archive.org/web/20100127163125/http://www.julissa.com.mx/ Ebe nrụọrụ weebụ gọọmentị] 6osfcpku4f2d77g61d9ztdi12yfz5w0 736822 736821 2026-10-07T18:02:42Z Juliegwen 12936 736822 wikitext text/x-wiki <templatestyles src="Module:Hatnote/styles.css"></templatestyles><templatestyles src="Module:Message box/ambox.css"></templatestyles><templatestyles src="Module:Infobox/styles.css"></templatestyles>  '''Julia Isabel de Llano Macedo''' (amụrụ na 8 Eprel 1944), nke a maara dịka '''Julissa''', bụ onye na-eme ihe nkiri, onye na-emepụta ihe, na onye na-agụ egwu na Mexico. Ọ bụ nwa nwanyị nke onye na-eme ihe nkiri na redio na telivishọn Luis de Llano Palmer na onye na-ese ihe nkiri Rita Macedo. Ụmụ ya gụnyere Benny Ibarra, onye na-agụ egwu na onye na-eti egwu, na Alejandro Ibarra, Onye na-eme ihe nkiri na onye na na-agụ egwú. Nwanne ya nwoke, Luis de Llano Macedo, arụwo ọrụ dị ka onye na-emepụta ihe maka Televisa. == Mbido ndụ na ọrụ == === Egwú === Mgbe ọ dị afọ 14, Julissa malitere ọrụ egwu ya n'otu egwu ụdị 'rock' a na-akpọ The Spitfires; nwanne ya nwoke bụ Luis hiwere otu egwu a. O nwetara ọnọdụ nke abụọ n'asọmpi redio tupu ụlọ ọrụ CBS abanye ya n'akwụkwọ nkwekọrịta, o wee dekọọ ọtụtụ abọm egwu 'rock' n'etiti afọ 1961 na 1964. O dekọrọ otu egwu (nke a na-akpọ 'single') nwere aha bụ "Corazón Salvaje / Te Necesito," nke ụlọ ọrụ Capitol Records na afọ 1966. wepụtara n'afọ 1966. Julissa nyere egwu mbụ bụ "Teacher's Pet" nke Doris Day, gụrụ ụdị ọhụrụ site n'ịgụ ya n'ụzọ dị iche n'ime egwu ọ kpọrọ "La favorita del profesor" ("Onye nkuzi kacha hụ n'anya"). === Ihe nkiri === Ọ malitere ime ihe nkiri wee malite ọrụ ebe ọ bụ onye na-emepụta ihe nkiri na Mexico na-eweta ihe nkiri Broadway a ma ama dị ka Jesus Christ Superstar, Grease, Joseph na Amazing Technicolor Dreamcoat, ''Pipin''.<ref>{{Cite web|url=http://www.broadwaymusicalhome.com|title=Broadway|publisher=broadwaymusicalhome.com|accessdate=20 July 2010}}</ref> Ọ so n'ndị na-eme ihe nkiri n'egwuregwu ''The Rocky Horror Show'';nke afọ 1975 na Mexico Aida Pierce mgbe ọ ka dị obere, so n'òtù ndị na-agụ egwu n'egwuregwu ahụ. == Ihe nkiri == <templatestyles src="Module:Message box/ambox.css"></templatestyles> {| class="wikitable" style="font-size: 95%;" ! style="background: #B0C4DE;" |Afọ ! style="background: #B0C4DE;" |Aha ya ! style="background: #B0C4DE;" |Ọrụ ! style="background: #B0C4DE;" |Ihe edeturu |- |1962 |''Ime Anwansi'' |Rosario | (nke a na-akpọ Julisa Macedo) |- |1963 |''Ọgwụ ọjọọ nke Llorona'' |Onye Njem Ụgbọ Mmiri nke Nwanyị | (nke a na-akpọ Julissa del Llano) aha ọzọ - The Curse of the Crying Woman''Ọgwụ Nwanyị Na-ebe ákwá'' |- |1964 |''A machibidoro Nrọ'' | | |- |1964 |''Oge Ime Ihe Ike'' | |aha ọzọ - La Edad de la Violencia (aha mbụ) |- |1964 |''N'etiti Ụwa'' | | (nke a na-akpọ Julissa Herrera) |- |1964 |''Ụmụ nwanyị nke ụmụ m nwanyị'' |Maria | |- |1964 |''Izu ohi n'ụgbọ okporo ígwè'' | | |- |1965 |''Obodo Mmụọ'' | |aha ọzọ - Ghost Town''Obodo Mmụọ'' |- |1965 |''Ekwensu n'Eluigwe'' | | |- |1965 |''Mmehie'' |Lidia |aha ọzọ - El Pecador (aha mbụ) |- |1965 |''Ndị A mụrụ Maka Abụ'' | | |- |1965 |''Dengue nke Ịhụnanya'' | | |- |1965 |''Elena Abụọ'' |Elena | |- |1966 |''Otu Nwanyị Estupenda'' |Mercedes | |- |1966 |''Anyị Ndị Ntorobịa'' |Carmen | |- |1966 |''Ịgba Goolu'' | | |- |1966 |''Ike gwụrụ m na-arịọ ya arịrịọ'' | | |- |1967 |''Pedro Páramo'' |Ana Rentería | |- |1967 |''Ọ bụrụ na achọrọ m'' | | |- |1967 |''Lee nwoke dị otú ahụ'' |Laura | |- |1967 |''Egwuregwu Dị Iche Iche'' |Claudia (nkebi "HO") | |- |1967 |''Ndị si n'èzí'' |Paloma |aha ọzọ - Los Caifanes (aha mbụ) |- |1967 |''Ụwa Nzuzu nke Ndị Ntorobịa'' | |aha ọzọ - El Mundo Loco de los Jóvenes (aha mbụ) |- |1968 |''Ụlọ Egwu'' |Corinne Mandel | |- |1968 |''Ụlọ Ihe Ọjọọ'' |Lucy Durant | |- |1968 |''Ndị Ntorobịa'' | |aha ọzọ - The Adolescentes (aha mbụ) |- |1968 |''Ịchụpụ Casada'' |Sonia Vargas | |- |1968 |''Ihe odide abalị agbamakwụkwọ'' | |aha ọzọ - Ensayo de una Noche de Bodas (aha mbụ) |- |1969 |''Santa'' |Santa | |- |1969 |Paula | | |- |1970 |''Ịgha ụgha'' | | |- |1971 |''Agwọ Agwọ'' |Anabella Vandenberg |utu aha ndị ọzọ - La Muerte Viviente (aha mbụ), Snake People''Ndị Agwọ'' |- |1971 |''Oge okpomọkụ na-ere ọkụ'' |Marilu/Maria de la Luz Flores |aha ọzọ - Hot Summer''Oge okpomọkụ'' |- |1972 |''Nwaanyị Na-akwụwa Aka ọtọ'' | | |- |1972 |''Gị, M, Anyị'' | |A họpụtara ya - Ariel Award maka onye na-eme ihe nkiri kacha mma |- |1972 |''Victoria'' | | |- |1973 |''Ndị A Na-atọrọ Nri'' |Lucía Gómez | |- |1979 |''Ịhụnanya Nwere Onwe'' | | |- |1981 |''Pachange'' |Adela, Nwunye Vicente | |- |1981 |''Ọrụ Ọchịchịrị'' | | |- |1981 |''D.F./District Federal'' | |Ariel Award maka onye na-eme ihe nkiri kachasị mma |- |1982 |''Onye a ma ama Remington'' | | |- |1982 |''Ụbọchị Agha'' |Elisa | |- |1982 |''41, nwoke zuru oke'' |Clarissa Machorro | |- |1982 |''Anya Nwatakịrị'' |Patricia | |- |1982 |Ihe Dị Mfe |Elisa Belascoaran | |- |1983 |''Carnales Abụọ'' | | |- |1984 |''A machibidoro Ịhụnanya na New York'' | | |- |1986 |''N'azụ Ọnwụ'' |Andrea/Laura | |- |1994 |''Ịhụnanya Na-egbu'' | | |- |2004 |''Onye Ime Anwansi'' |Raquel |aha ọzọ - The Magician''Onye Ime Anwansi'' |- |2005 |''Enweghị mmasị'' |Gertrudis Alcocer | |} === Ìgwè Onyonyo === {| class="wikitable" style="font-size: 95%;" ! style="background: #B0C4DE;" |Afọ ! style="background: #B0C4DE;" |Aha ya ! style="background: #B0C4DE;" |Ọrụ ! style="background: #B0C4DE;" |Ihe edeturu |- |1962 |''Ozu ndị a gbasiri agbasi na Guanajuato'' | | |- |1963 |''Doña Macabra'' | | |- |1964 |''Orfeón mbụ'' | | |- |1964 |''Onye na-abanye n'ime'' |Veronica | |- |1964 |''Ụlọ ndị agbata obi'' |Lupe | |- |1964 |''Kpakpando'' | | |- |1965 |''Ịgha ụgha'' |Veronica | |- |1966 |''Obi Anụ Ọhịa'' |Mónica Molnar del Diablo | |- |1967 |''Ógbè'' | | |- |1969 |''Mgbe Ịnwụghị Ụma'' |Estela Ballesteros | |- |1971 |''Ụgbọ mmiri nke nwanyị'' | | |- |1972-73 |''Ụmụnne Obi Ike'' |Clara Barros/Diana Lemos/Marcia | |- |1974 |''Isi iyi nke ọrụ ebube'' | | |- |1976 |''Ndị ohi nke Rio Frío'' |Cecilia | |- |1978-79 |''Akwụkwọ ozi e degaara onye e gburu'' | | |- |1979-80 |Veronica |Veronica | |- |1980-81 |''Agba'' |Rita | |- |1986 |''Oge a kara akara'' | | |- |1987-88 |''Dị Anyị Dị'' | |Onye mmepụta |- |1987 |''Onye Na-enweghị Nchịkwa'' | - |Onye na-emepụta naanị |- |1988-89 |''Ihe ịma aka dị ụtọ'' | - |Onye na-emepụta naanị |- |1989 |''Ime Ihe Ike na-adịghị Mma'' | |Ihe nkiri TV |- |1994-95 |''Mmiri na-acha odo odo'' |Lola | |- |1996 |''Onyinyo nke onye nke ọzọ'' | - |Onye na-emepụta naanị |- |2003-04 |''Ụgbọ mmiri nke nwanyị'' |Lia del Moral de Villaseñor | |- |2002 |''Site na Gayola'' |Luchis/ La Nena | |- |2004 |''Iche Cheta America!'' |Ya onwe ya | |- |2004 |''Ọnụ Anọ'' |Ya onwe ya | |- |2005 |''100 ndị Mexico kwuru'' |Ya onwe ya |1 ihe omume - Ndị Nna vs Ụmụ''Ndị Nne na Nna vs Ụmụ'' |- |2005 |''N'okpuru otu uko'' |Julissa Acosta |1 ihe omume - Nleta nke Aunt July''Nleta nke Nwanne nwanyị July'' |- |2006 |''Ihe nrite TV na akwụkwọ akụkọ 2006'' |Ya onwe ya | |- |2006 |''Abụ Anyị Kasị Mma'' |Marcela Andere de Méndez | |- |2006–07 |''Onye mara mma'' |Teresita Sáenz nke Mendiola |Ihe omume 2 |- |2007 |''Ihe nrite TV na Novelas 2007'' |Ya onwe ya | |- |2008 |''Ọkụ n'ime ọbara'' |Raquel Uribe |Ihe omume 9 |- |2009-10 |''Ịtụrụ egwu ime nrọ'' |Doña Cristina "Cristi" Jiménez vda. nke Peralta | |- |2012-13 |''N'ihi na ịhụnanya na-achịkwa'' |Doña Susana Arriaga | |- |2014 |''Dị ka okwu ahụ si kwuo'' |Gertrudis |Ihe omume: "Ịma anyaukwu na oké ọchịchọ" |- |} == Ihe nrita == <templatestyles src="Module:Message box/ambox.css"></templatestyles> === Egwú === A nabatara Julissa n'ime Paseo de las Luminarias n'afọ 1987 n'ihi ọrụ ya n'ihe nkiri, telivishọn, ihe ngosi n'elu ikpo okwu (theater), na ụlọ ọrụ ndekọ egwu, ebe ọ sonyeere ndị mụrụ ya. N'oge na-adịghị anya, a ga-etinyekwa akara aka nwanne ya nwoke n'akụkụ nke ya; e si otú a sọpụrụ mmadụ anọ niile so n'ezinụlọ De Llano-Macedo na Paseo ahụ. == Edensịbia == <templatestyles src="Reflist/styles.css" />  == Njikọ mpụga == * {{IMDb name|0215612}} * [https://web.archive.org/web/20100127163125/http://www.julissa.com.mx/ Ebe nrụọrụ weebụ gọọmentị] [[Otú:Mmadụ ndi di ndụ]] [[Otú:Articles with hCards]] == Mbido ndụ na ọrụ == === Egwú === Mgbe ọ dị afọ 14, Julissa malitere ọrụ egwu ya n'otu egwu ụdị 'rock' a na-akpọ The Spitfires; nwanne ya nwoke bụ Luis hiwere otu egwu a. O nwetara ọnọdụ nke abụọ n'asọmpi redio tupu ụlọ ọrụ CBS abanye ya n'akwụkwọ nkwekọrịta, o wee dekọọ ọtụtụ abọm egwu 'rock' n'etiti afọ 1961 na 1964. O dekọrọ otu egwu (nke a na-akpọ 'single') nwere aha bụ "Corazón Salvaje / Te Necesito," nke ụlọ ọrụ Capitol Records na afọ 1966. wepụtara n'afọ 1966. Julissa nyere egwu mbụ bụ "Teacher's Pet" nke Doris Day, gụrụ ụdị ọhụrụ site n'ịgụ ya n'ụzọ dị iche n'ime egwu ọ kpọrọ "La favorita del profesor" ("Onye nkuzi kacha hụ n'anya"). === Ihe nkiri === Ọ malitere ime ihe nkiri wee malite ọrụ ebe ọ bụ onye na-emepụta ihe nkiri na Mexico na-eweta ihe nkiri Broadway a ma ama dị ka Jesus Christ Superstar, Grease, Joseph na Amazing Technicolor Dreamcoat, ''Pipin''.<ref>{{Cite web |title=Broadway |url=http://www.broadwaymusicalhome.com |accessdate=20 July 2010 |publisher=broadwaymusicalhome.com}}</ref> Ọ so n'ndị na-eme ihe nkiri n'egwuregwu ''The Rocky Horror Show'';nke afọ 1975 na Mexico Aida Pierce mgbe ọ ka dị obere, so n'òtù ndị na-agụ egwu n'egwuregwu ahụ. == Ihe nkiri ==   === Ihe nkiri === {| class="wikitable" style="font-size: 95%;" ! style="background: #B0C4DE;" |Afọ ! style="background: #B0C4DE;" |Aha ya ! style="background: #B0C4DE;" |Ọrụ ! style="background: #B0C4DE;" |Ihe edeturu |- |1962 |''Ime Anwansi'' |Rosario | (nke a na-akpọ Julisa Macedo) |- |1963 |''Ọgwụ ọjọọ nke Llorona'' |Onye Njem Ụgbọ Mmiri nke Nwanyị | (nke a na-akpọ Julissa del Llano) aha ọzọ - The Curse of the Crying Woman''Ọgwụ Nwanyị Na-ebe ákwá'' |- |1964 |''A machibidoro Nrọ'' | | |- |1964 |''Oge Ime Ihe Ike'' | |aha ọzọ - La Edad de la Violencia (aha mbụ) |- |1964 |''N'etiti Ụwa'' | | (nke a na-akpọ Julissa Herrera) |- |1964 |''Ụmụ nwanyị nke ụmụ m nwanyị'' |Maria | |- |1964 |''Izu ohi n'ụgbọ okporo ígwè'' | | |- |1965 |''Obodo Mmụọ'' | |aha ọzọ - Ghost Town''Obodo Mmụọ'' |- |1965 |''Ekwensu n'Eluigwe'' | | |- |1965 |''Mmehie'' |Lidia |aha ọzọ - El Pecador (aha mbụ) |- |1965 |''Ndị A mụrụ Maka Abụ'' | | |- |1965 |''Dengue nke Ịhụnanya'' | | |- |1965 |''Elena Abụọ'' |Elena | |- |1966 |''Otu Nwanyị Estupenda'' |Mercedes | |- |1966 |''Anyị Ndị Ntorobịa'' |Carmen | |- |1966 |''Ịgba Goolu'' | | |- |1966 |''Ike gwụrụ m na-arịọ ya arịrịọ'' | | |- |1967 |''Pedro Páramo'' |Ana Rentería | |- |1967 |''Ọ bụrụ na achọrọ m'' | | |- |1967 |''Lee nwoke dị otú ahụ'' |Laura | |- |1967 |''Egwuregwu Dị Iche Iche'' |Claudia (nkebi "HO") | |- |1967 |''Ndị si n'èzí'' |Paloma |aha ọzọ - Los Caifanes (aha mbụ) |- |1967 |''Ụwa Nzuzu nke Ndị Ntorobịa'' | |aha ọzọ - El Mundo Loco de los Jóvenes (aha mbụ) |- |1968 |''Ụlọ Egwu'' |Corinne Mandel | |- |1968 |''Ụlọ Ihe Ọjọọ'' |Lucy Durant | |- |1968 |''Ndị Ntorobịa'' | |aha ọzọ - The Adolescentes (aha mbụ) |- |1968 |''Ịchụpụ Casada'' |Sonia Vargas | |- |1968 |''Ihe odide abalị agbamakwụkwọ'' | |aha ọzọ - Ensayo de una Noche de Bodas (aha mbụ) |- |1969 |''Santa'' |Santa | |- |1969 |Paula | | |- |1970 |''Ịgha ụgha'' | | |- |1971 |''Agwọ Agwọ'' |Anabella Vandenberg |utu aha ndị ọzọ - La Muerte Viviente (aha mbụ), Snake People''Ndị Agwọ'' |- |1971 |''Oge okpomọkụ na-ere ọkụ'' |Marilu/Maria de la Luz Flores |aha ọzọ - Hot Summer''Oge okpomọkụ'' |- |1972 |''Nwaanyị Na-akwụwa Aka ọtọ'' | | |- |1972 |''Gị, M, Anyị'' | |A họpụtara ya - Ariel Award maka onye na-eme ihe nkiri kacha mma |- |1972 |''Victoria'' | | |- |1973 |''Ndị A Na-atọrọ Nri'' |Lucía Gómez | |- |1979 |''Ịhụnanya Nwere Onwe'' | | |- |1981 |''Pachange'' |Adela, Nwunye Vicente | |- |1981 |''Ọrụ Ọchịchịrị'' | | |- |1981 |''D.F./District Federal'' | |Ariel Award maka onye na-eme ihe nkiri kachasị mma |- |1982 |''Onye a ma ama Remington'' | | |- |1982 |''Ụbọchị Agha'' |Elisa | |- |1982 |''41, nwoke zuru oke'' |Clarissa Machorro | |- |1982 |''Anya Nwatakịrị'' |Patricia | |- |1982 |Ihe Dị Mfe Belascoaran === Ìgwè Onyonyo === {| class="wikitable" style="font-size: 95%;" ! style="background: #B0C4DE;" |Afọ ! style="background: #B0C4DE;" |Aha ya ! style="background: #B0C4DE;" |Ọrụ ! style="background: #B0C4DE;" |Ihe edeturu |- |1962 |''Ozu ndị a gbasiri agbasi na Guanajuato'' | | |- |1963 |''Doña Macabra'' | | |- |1964 |''Orfeón mbụ'' | | |- |1964 |''Onye na-abanye n'ime'' |Veronica | |- |1964 |''Ụlọ ndị agbata obi'' |Lupe | |- |1964 |''Kpakpando'' | | |- |1965 |''Ịgha ụgha'' |Veronica | |- |1966 |''Obi Anụ Ọhịa'' |Mónica Molnar del Diablo | |- |1967 |''Ógbè'' | | |- |1969 |''Mgbe Ịnwụghị Ụma'' |Estela Ballesteros | |- |1971 |''Ụgbọ mmiri nke nwanyị'' | | |- |1972-73 |''Ụmụnne Obi Ike'' |Clara Barros/Diana Lemos/Marcia | |- |1974 |''Isi iyi nke ọrụ ebube'' | | |- ==Ihe nrite== === Egwú === {| class="wikitable" style="font-size: 95%;" ! style="background: #B0C4DE;" |Afọ ! style="background: #B0C4DE;" |Nsonaazụ ! style="background: #B0C4DE;" |Ihe nrite ! style="background: #B0C4DE;" |Ụdị |- |1990|{{Won}} |Diski ọla edo na nke platinum |Album nke Mbụ (Mexico) |- |1991|{{Won}} |Diski ọla edo |Album nke Mbụ (Spain) |- |1991|{{Won}} |Diski ọla edo |Album nke Abụọ (Mexico) |- |1992|{{Won}} |Onyinye Eres |Òtù Egwú Ndị Ntorobịa Kasị Mma |- |1992|{{Won}} |Diski Platinum Abụọ |Album nke Mbụ (Spain) |- |1992|{{Won}} |Diski ọla edo na diski platinum |Album nke Abụọ (Spain) |- |1993|{{Won}} |Diski ọla edo |Banda Rock (Mexico) |- |1993|{{Won}} |Onyinye Eres |Òtù Egwú Ndị Ntorobịa Kasị Mma nke Afọ |- |1994|{{Won}} |Ihe nrite Egwú nke Furia |Akara Rock |- |1994|{{Won}} |Diski ọla edo abụọ |El Album DOble (Spain) |- |1994|{{Won}} |Ihe nrite Las Palms de Oro | |- |1995|{{Won}} |Diski ọla edo |Album Hoy (Spain) |} A nabatara Julissa n'ime Paseo de las Luminarias n'afọ 1987 n'ihi ọrụ ya n'ihe nkiri, telivishọn, ihe ngosi n'elu ikpo okwu (theater), na ụlọ ọrụ ndekọ egwu, ebe ọ sonyeere ndị mụrụ ya. N'oge na-adịghị anya, a ga-etinyekwa akara aka nwanne ya nwoke n'akụkụ nke ya; e si otú a sọpụrụ mmadụ anọ niile so n'ezinụlọ De Llano-Macedo na Paseo ahụ. == Edensịbia == {{Reflist}}   == Njikọ mpụga == * {{IMDb name|0215612}} * [https://web.archive.org/web/20100127163125/http://www.julissa.com.mx/ Ebe nrụọrụ weebụ gọọmentị] cp7onxq67lt26sywsuq0g00ple1b4g0 736823 736822 2026-10-07T18:09:01Z Juliegwen 12936 Ede ziri ya 736823 wikitext text/x-wiki <templatestyles src="Module:Hatnote/styles.css"></templatestyles><templatestyles src="Module:Message box/ambox.css"></templatestyles><templatestyles src="Module:Infobox/styles.css"></templatestyles>  '''Julia Isabel de Llano Macedo''' (amụrụ na 8 Eprel 1944), nke a maara dịka '''Julissa''', bụ onye na-eme ihe nkiri, onye na-emepụta ihe, na onye na-agụ egwu na Mexico. Ọ bụ nwa nwanyị nke onye na-eme ihe nkiri na redio na telivishọn Luis de Llano Palmer na onye na-ese ihe nkiri Rita Macedo. Ụmụ ya gụnyere Benny Ibarra, onye na-agụ egwu na onye na-eti egwu, na Alejandro Ibarra, Onye na-eme ihe nkiri na onye na na-agụ egwú. Nwanne ya nwoke, Luis de Llano Macedo, arụwo ọrụ dị ka onye na-emepụta ihe maka Televisa. == Mbido ndụ na ọrụ == === Egwú === Mgbe ọ dị afọ 14, Julissa malitere ọrụ egwu ya n'otu egwu ụdị 'rock' a na-akpọ The Spitfires; nwanne ya nwoke bụ Luis hiwere otu egwu a. O nwetara ọnọdụ nke abụọ n'asọmpi redio tupu ụlọ ọrụ CBS abanye ya n'akwụkwọ nkwekọrịta, o wee dekọọ ọtụtụ abọm egwu 'rock' n'etiti afọ 1961 na 1964. O dekọrọ otu egwu (nke a na-akpọ 'single') nwere aha bụ "Corazón Salvaje / Te Necesito," nke ụlọ ọrụ Capitol Records na afọ 1966. wepụtara n'afọ 1966. Julissa nyere egwu mbụ bụ "Teacher's Pet" nke Doris Day, gụrụ ụdị ọhụrụ site n'ịgụ ya n'ụzọ dị iche n'ime egwu ọ kpọrọ "La favorita del profesor" ("Onye nkuzi kacha hụ n'anya"). === Ihe nkiri === Ọ malitere ime ihe nkiri wee malite ọrụ ebe ọ bụ onye na-emepụta ihe nkiri na Mexico na-eweta ihe nkiri Broadway a ma ama dị ka Jesus Christ Superstar, Grease, Joseph na Amazing Technicolor Dreamcoat, ''Pipin''.<ref>{{Cite web|url=http://www.broadwaymusicalhome.com|title=Broadway|publisher=broadwaymusicalhome.com|accessdate=20 July 2010}}</ref> Ọ so n'ndị na-eme ihe nkiri n'egwuregwu ''The Rocky Horror Show'';nke afọ 1975 na Mexico Aida Pierce mgbe ọ ka dị obere, so n'òtù ndị na-agụ egwu n'egwuregwu ahụ. == Ihe nkiri == <templatestyles src="Module:Message box/ambox.css"></templatestyles> {| class="wikitable" style="font-size: 95%;" ! style="background: #B0C4DE;" |Afọ ! style="background: #B0C4DE;" |Aha ya ! style="background: #B0C4DE;" |Ọrụ ! style="background: #B0C4DE;" |Ihe edeturu |- |1962 |''Ime Anwansi'' |Rosario | (nke a na-akpọ Julisa Macedo) |- |1963 |''Ọgwụ ọjọọ nke Llorona'' |Onye Njem Ụgbọ Mmiri nke Nwanyị | (nke a na-akpọ Julissa del Llano) aha ọzọ - The Curse of the Crying Woman''Ọgwụ Nwanyị Na-ebe ákwá'' |- |1964 |''A machibidoro Nrọ'' | | |- |1964 |''Oge Ime Ihe Ike'' | |aha ọzọ - La Edad de la Violencia (aha mbụ) |- |1964 |''N'etiti Ụwa'' | | (nke a na-akpọ Julissa Herrera) |- |1964 |''Ụmụ nwanyị nke ụmụ m nwanyị'' |Maria | |- |1964 |''Izu ohi n'ụgbọ okporo ígwè'' | | |- |1965 |''Obodo Mmụọ'' | |aha ọzọ - Ghost Town''Obodo Mmụọ'' |- |1965 |''Ekwensu n'Eluigwe'' | | |- |1965 |''Mmehie'' |Lidia |aha ọzọ - El Pecador (aha mbụ) |- |1965 |''Ndị A mụrụ Maka Abụ'' | | |- |1965 |''Dengue nke Ịhụnanya'' | | |- |1965 |''Elena Abụọ'' |Elena | |- |1966 |''Otu Nwanyị Estupenda'' |Mercedes | |- |1966 |''Anyị Ndị Ntorobịa'' |Carmen | |- |1966 |''Ịgba Goolu'' | | |- |1966 |''Ike gwụrụ m na-arịọ ya arịrịọ'' | | |- |1967 |''Pedro Páramo'' |Ana Rentería | |- |1967 |''Ọ bụrụ na achọrọ m'' | | |- |1967 |''Lee nwoke dị otú ahụ'' |Laura | |- |1967 |''Egwuregwu Dị Iche Iche'' |Claudia (nkebi "HO") | |- |1967 |''Ndị si n'èzí'' |Paloma |aha ọzọ - Los Caifanes (aha mbụ) |- |1967 |''Ụwa Nzuzu nke Ndị Ntorobịa'' | |aha ọzọ - El Mundo Loco de los Jóvenes (aha mbụ) |- |1968 |''Ụlọ Egwu'' |Corinne Mandel | |- |1968 |''Ụlọ Ihe Ọjọọ'' |Lucy Durant | |- |1968 |''Ndị Ntorobịa'' | |aha ọzọ - The Adolescentes (aha mbụ) |- |1968 |''Ịchụpụ Casada'' |Sonia Vargas | |- |1968 |''Ihe odide abalị agbamakwụkwọ'' | |aha ọzọ - Ensayo de una Noche de Bodas (aha mbụ) |- |1969 |''Santa'' |Santa | |- |1969 |Paula | | |- |1970 |''Ịgha ụgha'' | | |- |1971 |''Agwọ Agwọ'' |Anabella Vandenberg |utu aha ndị ọzọ - La Muerte Viviente (aha mbụ), Snake People''Ndị Agwọ'' |- |1971 |''Oge okpomọkụ na-ere ọkụ'' |Marilu/Maria de la Luz Flores |aha ọzọ - Hot Summer''Oge okpomọkụ'' |- |1972 |''Nwaanyị Na-akwụwa Aka ọtọ'' | | |- |1972 |''Gị, M, Anyị'' | |A họpụtara ya - Ariel Award maka onye na-eme ihe nkiri kacha mma |- |1972 |''Victoria'' | | |- |1973 |''Ndị A Na-atọrọ Nri'' |Lucía Gómez | |- |1979 |''Ịhụnanya Nwere Onwe'' | | |- |1981 |''Pachange'' |Adela, Nwunye Vicente | |- |1981 |''Ọrụ Ọchịchịrị'' | | |- |1981 |''D.F./District Federal'' | |Ariel Award maka onye na-eme ihe nkiri kachasị mma |- |1982 |''Onye a ma ama Remington'' | | |- |1982 |''Ụbọchị Agha'' |Elisa | |- |1982 |''41, nwoke zuru oke'' |Clarissa Machorro | |- |1982 |''Anya Nwatakịrị'' |Patricia | |- |1982 |Ihe Dị Mfe |Elisa Belascoaran | |- |1983 |''Carnales Abụọ'' | | |- |1984 |''A machibidoro Ịhụnanya na New York'' | | |- |1986 |''N'azụ Ọnwụ'' |Andrea/Laura | |- |1994 |''Ịhụnanya Na-egbu'' | | |- |2004 |''Onye Ime Anwansi'' |Raquel |aha ọzọ - The Magician''Onye Ime Anwansi'' |- |2005 |''Enweghị mmasị'' |Gertrudis Alcocer | |} === Ìgwè Onyonyo === {| class="wikitable" style="font-size: 95%;" ! style="background: #B0C4DE;" |Afọ ! style="background: #B0C4DE;" |Aha ya ! style="background: #B0C4DE;" |Ọrụ ! style="background: #B0C4DE;" |Ihe edeturu |- |1962 |''Ozu ndị a gbasiri agbasi na Guanajuato'' | | |- |1963 |''Doña Macabra'' | | |- |1964 |''Orfeón mbụ'' | | |- |1964 |''Onye na-abanye n'ime'' |Veronica | |- |1964 |''Ụlọ ndị agbata obi'' |Lupe | |- |1964 |''Kpakpando'' | | |- |1965 |''Ịgha ụgha'' |Veronica | |- |1966 |''Obi Anụ Ọhịa'' |Mónica Molnar del Diablo | |- |1967 |''Ógbè'' | | |- |1969 |''Mgbe Ịnwụghị Ụma'' |Estela Ballesteros | |- |1971 |''Ụgbọ mmiri nke nwanyị'' | | |- |1972-73 |''Ụmụnne Obi Ike'' |Clara Barros/Diana Lemos/Marcia | |- |1974 |''Isi iyi nke ọrụ ebube'' | | |- |1976 |''Ndị ohi nke Rio Frío'' |Cecilia | |- |1978-79 |''Akwụkwọ ozi e degaara onye e gburu'' | | |- |1979-80 |Veronica |Veronica | |- |1980-81 |''Agba'' |Rita | |- |1986 |''Oge a kara akara'' | | |- |1987-88 |''Dị Anyị Dị'' | |Onye mmepụta |- |1987 |''Onye Na-enweghị Nchịkwa'' | - |Onye na-emepụta naanị |- |1988-89 |''Ihe ịma aka dị ụtọ'' | - |Onye na-emepụta naanị |- |1989 |''Ime Ihe Ike na-adịghị Mma'' | |Ihe nkiri TV |- |1994-95 |''Mmiri na-acha odo odo'' |Lola | |- |1996 |''Onyinyo nke onye nke ọzọ'' | - |Onye na-emepụta naanị |- |2003-04 |''Ụgbọ mmiri nke nwanyị'' |Lia del Moral de Villaseñor | |- |2002 |''Site na Gayola'' |Luchis/ La Nena | |- |2004 |''Iche Cheta America!'' |Ya onwe ya | |- |2004 |''Ọnụ Anọ'' |Ya onwe ya | |- |2005 |''100 ndị Mexico kwuru'' |Ya onwe ya |1 ihe omume - Ndị Nna vs Ụmụ''Ndị Nne na Nna vs Ụmụ'' |- |2005 |''N'okpuru otu uko'' |Julissa Acosta |1 ihe omume - Nleta nke Aunt July''Nleta nke Nwanne nwanyị July'' |- |2006 |''Ihe nrite TV na akwụkwọ akụkọ 2006'' |Ya onwe ya | |- |2006 |''Abụ Anyị Kasị Mma'' |Marcela Andere de Méndez | |- |2006–07 |''Onye mara mma'' |Teresita Sáenz nke Mendiola |Ihe omume 2 |- |2007 |''Ihe nrite TV na Novelas 2007'' |Ya onwe ya | |- |2008 |''Ọkụ n'ime ọbara'' |Raquel Uribe |Ihe omume 9 |- |2009-10 |''Ịtụrụ egwu ime nrọ'' |Doña Cristina "Cristi" Jiménez vda. nke Peralta | |- |2012-13 |''N'ihi na ịhụnanya na-achịkwa'' |Doña Susana Arriaga | |- |2014 |''Dị ka okwu ahụ si kwuo'' |Gertrudis |Ihe omume: "Ịma anyaukwu na oké ọchịchọ" |- |} === Egwú === A nabatara Julissa n'ime Paseo de las Luminarias n'afọ 1987 n'ihi ọrụ ya n'ihe nkiri, telivishọn, ihe ngosi n'elu ikpo okwu (theater), na ụlọ ọrụ ndekọ egwu, ebe ọ sonyeere ndị mụrụ ya. N'oge na-adịghị anya, a ga-etinyekwa akara aka nwanne ya nwoke n'akụkụ nke ya; e si otú a sọpụrụ mmadụ anọ niile so n'ezinụlọ De Llano-Macedo na Paseo ahụ. == Edensịbia == <templatestyles src="Reflist/styles.css" />  == Njikọ mpụga == * {{IMDb name|0215612}} * [https://web.archive.org/web/20100127163125/http://www.julissa.com.mx/ Ebe nrụọrụ weebụ gọọmentị] [[Otú:Mmadụ ndi di ndụ]] 2a2wzlcgyhfdkr7yhjmyqn5skclougl Blanca de Castejón 0 80663 736813 735119 2026-10-07T15:48:46Z Vivian Amalachukwu 17172 Removed nonexisting template 736813 wikitext text/x-wiki {{Short description|Puerto Rican actress (1906–1969)}} {{Use mdy dates|date=December 2023}} {{Infobox person | name = Blanca de Castejón | image = Blanca de Castejón en 1955 (cropped).jpg | caption = Blanca de Castejón in 1955 | birth_name = <!-- only use if different from name --> | birth_date = {{Birth date|1906|05|13}} | birth_place = [[Comerío, Puerto Rico]] | death_date = {{Death date and age|1969|12|26|1906|05|13}} | death_place = [[Mexico City, Mexico]] | occupation = Actress | years_active = | spouse = {{marriage|[[Rafael Banquells]]|1934|1942|reason=divorce}} }}   {{Authority control}}  '''Blanca de Castejón''' (Mee 13, 1906 - Disemba 26, 1969) bụ onye na-eme ihe nkiri na Puerto Rican nke rụrụ ọrụ na Golden Age nke sinima Argentina n'ime 1930 na karịsịa Golden Age nke sinima Mexico kemgbe ime 1940, ebe ihe gaara ya nke ọma na nweta nkwanye ùgwù nke ukwuu. A mụrụ ya na Comerío, Puerto Rico, ma nwụọ na Mexico City. Castejón malitere ọrụ ya na-arụ ọrụ na FOX na 1931. Ka ọ na-erute n'afọ sochirinụ, ọ malitela gosipụta ọrụ ya na Mexico dị ka akụkụ nke ọrụ mba ụwa nke ga-akpọrọ ya gaa Spain, Uruguay na Argentina.<ref name="Rivera59">{{Harvnb|Rivera|2010|pp=59}}</ref> Ọ pụtara na Crimen a las tres (1935), ''Carnival del Diablo'' (1936), Mis dos Amores (1938), Los Hijos Mandan (1938), Las Dos Huérfanas (1941), Ave sin nido (1943), La razón de la culpa (1943), Que hombre tan simpático (1943), El Mujer del otro (1948) and Mamá me quita los novios (1952), tinyere ndị ọzọ. == Ndụ na ọrụ == [[File:José_Gola_y_Blanca_de_Castejón_en_Por_buen_camino.jpg|áká_èkpè|thumb|With José Gola in a film still for the 1935 Argentine film ''Por buen camino'', directed by Eduardo Morera.]] [[File:Blanca_de_Castejón_en_1945.jpg|thumb|232x232px|Blanca de Castejón in the ''Novelas de la Pantalla'' magazine in 1945]] A mụrụ Blanca de Castejón Otero na Comerío, Puerto Rico, n'ezinụlọ Rafael Castejón Arnáiz, onye na-ahụ maka telegraf na Josefa Otero Rivera, nwunye ya na-anọ n'ụlọ. O nwere nwanne nwaanyị nke obere aha ya bụ Margarita, onye na-agba egwú. Ọ malitere ọrụ ya site na isonye na ihe nkiri na redio nke Puerto Rico. Ndị nkuzi ya chere na Castejón na-achịkwa ọtụtụ ụdị.<ref name="Rivera59" /> Fox nyere Castejón nkwekọrịta ọrụ, onye o mere ihe nkiri mbụ ya na Hollywood na 1931 Resurrección, otu n'ime ihe nkiri atọ o mere maka ụlọ ọrụ asụsụ Spanish nke Fox. Mgbe nke ahụ gasịrị, ọ pụtara na El impostor (1931) na Eran Trece (1931) maka ụlọ ọrụ ahụ.<ref name="Rivera59" /> Mgbe ọ kwụsịrị na Mexico City na Havana, ebe ọ rụrụ ọrụ na ihe nkiri, Castejón gara Buenos Aires, ebe o mere ihe nkiri abụọ: Crimen a las tres (1935, a box-office flop) na Por buen camino (1935). Ka ọ na-eru ngwụcha afọ 1930, ọ laghachiri Hollywood ma mee ihe nkiri na asụsụ Spanish, ọ kachasị Mis dos amores (1938), nke onye a ma ama na Mexico bụ Tito Guizar, na Los hijos mandan (Gabriel Soria, 1939), ya na Fernando Soler na Arturo nke Córdova. Castejón so dee ihe nkiri nke Los hijos mandan na ihe nkiri abụọ ahụ bụ nke onye Puerto Rican Rafael Ramos Cobián mepụtara. Onye na-eme ihe nkiri ahụ lụrụ onye na-emeeme ihe nkiri na Mexico Rafael Banquells mgbe ọ kwagara Mexico City wee sonye n'ụlọ ọrụ ihe nkiri mba ahụ, ebe o mere ihe dị ka ihe nkiri iri atọ, na-ekere òkè n'ihe a maara dị ka Golden Age of Mexican Cinema . <ref name="Rivera60">{{Harvnb|Rivera|2010|pp=60}}</ref> Ọ bụ ezie na ọ malitere ime ihe nkiri dịka La razón de la culpa (Juan José Ortega, 1943), ya na Pedro Infante na María Elena Marqués, na Divorciadas (Alejandro Galindo, 1943), nke ya na René Cardona na Delia Magaña, Blanca de Castejón ghọrọ onye a ma ama maka ọrụ nkwado ya na ndị na-eme ihe na-atọ ọchị dị ka Luis Sandrini na Fernando Soler. O nwetara Awọọdụ Ariel nke 1954 (Mexico version of the [[Academy Awards|Oscars]]) maka ọrụ nkwado ya dị ka onye na-eme ihe nkiri n'Escuela de vagabundos (School for Tramps), ihe a ma ama nke ihe nkiri screwball nke 1938 Merrily We Live, nke jikọtara ya na Pedro Infante. Castejón meriri na 1956 Ariel de Plata maka iso na Escuela de Vagabundos (1955). Ọ pụtakwara n'ụdị ihe ọzọ, Escuela para suegras (1956). Ihe nkiri ikpeazụ Castejón mere bụ Los Signos del Zodiaco (1963). <ref name="Rivera60" /> == Fimọgrafị == * ''Resurrection'' (1931) * ''El impostor'' (1931) – Sandra * ''Esclavas de la moda'' (1931) – Dora Durke * ''Eran trece'' (''There Were Thirteen'') (1931) – Peggy Minchin (credited as Blanca Castejón) * ''Crimen a las tres'' (1935) * ''Por buen camino'' (1936) * ''El carnaval del diablo'' (1936) * ''Mis dos amores'' (1938) – Rita Santiago * ''Los hijos mandan'' (1939) * ''Qué hombre tan simpático'' (1943) – Doña Blanca * ''La razón de la culpa'' (1943) – María de la Paz * ''[[Ave sin nido]]'' (1943) – Anita de Medina * ''Divorciadas'' (1943) – Cristina * ''Imprudencia'' (1944) * ''¡Ya tengo a mi hijo!'' (1946) – Ana María * ''Los maridos engañan de 7 a 9'' (1946) * ''Yo soy tu padre'' (1948) – Doña Carmen * ''Cuide a su marido'' (1950) – Rosario * ''Yo también soy de Jalisco'' (1950) * ''Nosotras las taquígrafas'' (1950) – Blanquita * ''My Goddaughter's Difficulties'' (1951) – Doña Carmen Martínez * ''Todos son mis hijos'' (1951) – Doña María de Salgado * ''Mamá nos quita los novios'' (1952) – Amadora * ''Prefiero a tu papá'' (1952) – Anita Adalis * ''Escuela para vagabundos'' (''School for Tramps'') (1955) – Emilia de Valverde * ''El gallo colorado'' (1957) * ''Escuela para suegras'' (''School for Mothers-In-Law'') (1958) – Amalia * ''Mientras el cuerpo aguante'' (1958) – Regina Sarmiento * ''Tres lecciones de amor'' (1959) – Doña Angustias * ''Vagabundo y millonario'' (1959) – María de Aguilar * ''Los signos del zodiaco'' (1963) – Lola Casarini == Hụkwa == * Ndepụta nke ndị Puerto Rican == Edensibịa == '''Ndetu n'okpuru akwụkwọ''' '''Footnotes''' {{reflist|2}} '''Akwụkwọ''' == Njikọ mpụga == [[Otú:Articles with hCards]] [[Otú:Ndị a mụrụ na 1906]] [[Otú:Ndi nwụrụ na 1969]] [[Otú:Ndi mmadụ si na Comerío, Puerto Rico]] [[Otú:Ndị na-eme ihe nkiri fiim si Puerto Rico]] [[Otú:Ndị natara Awọọdụ Best Supporting Actress]] is4q783m7ylikcnr629sgf6ocnm9spm 736814 736813 2026-10-07T15:50:25Z Vivian Amalachukwu 17172 736814 wikitext text/x-wiki {{Short description|Puerto Rican actress (1906–1969)}} {{Use mdy dates|date=December 2023}} {{Infobox person | name = Blanca de Castejón | image = Blanca de Castejón en 1955 (cropped).jpg | caption = Blanca de Castejón in 1955 | birth_name = <!-- only use if different from name --> | birth_date = {{Birth date|1906|05|13}} | birth_place = [[Comerío, Puerto Rico]] | death_date = {{Death date and age|1969|12|26|1906|05|13}} | death_place = [[Mexico City, Mexico]] | occupation = Actress | years_active = | spouse = {{marriage|[[Rafael Banquells]]|1934|1942|reason=divorce}} }}  '''Blanca de Castejón''' (Mee 13, 1906 - Disemba 26, 1969) bụ onye na-eme ihe nkiri na Puerto Rican nke rụrụ ọrụ na Golden Age nke sinima Argentina n'ime 1930 na karịsịa Golden Age nke sinima Mexico kemgbe ime 1940, ebe ihe gaara ya nke ọma na nweta nkwanye ùgwù nke ukwuu. A mụrụ ya na Comerío, Puerto Rico, ma nwụọ na Mexico City. Castejón malitere ọrụ ya na-arụ ọrụ na FOX na 1931. Ka ọ na-erute n'afọ sochirinụ, ọ malitela gosipụta ọrụ ya na Mexico dị ka akụkụ nke ọrụ mba ụwa nke ga-akpọrọ ya gaa Spain, Uruguay na Argentina.<ref name="Rivera59">{{Harvnb|Rivera|2010|pp=59}}</ref> Ọ pụtara na Crimen a las tres (1935), ''Carnival del Diablo'' (1936), Mis dos Amores (1938), Los Hijos Mandan (1938), Las Dos Huérfanas (1941), Ave sin nido (1943), La razón de la culpa (1943), Que hombre tan simpático (1943), El Mujer del otro (1948) and Mamá me quita los novios (1952), tinyere ndị ọzọ. == Ndụ na ọrụ == [[File:José_Gola_y_Blanca_de_Castejón_en_Por_buen_camino.jpg|áká_èkpè|thumb|With José Gola in a film still for the 1935 Argentine film ''Por buen camino'', directed by Eduardo Morera.]] [[File:Blanca_de_Castejón_en_1945.jpg|thumb|232x232px|Blanca de Castejón in the ''Novelas de la Pantalla'' magazine in 1945]] A mụrụ Blanca de Castejón Otero na Comerío, Puerto Rico, n'ezinụlọ Rafael Castejón Arnáiz, onye na-ahụ maka telegraf na Josefa Otero Rivera, nwunye ya na-anọ n'ụlọ. O nwere nwanne nwaanyị nke obere aha ya bụ Margarita, onye na-agba egwú. Ọ malitere ọrụ ya site na isonye na ihe nkiri na redio nke Puerto Rico. Ndị nkuzi ya chere na Castejón na-achịkwa ọtụtụ ụdị.<ref name="Rivera59" /> Fox nyere Castejón nkwekọrịta ọrụ, onye o mere ihe nkiri mbụ ya na Hollywood na 1931 Resurrección, otu n'ime ihe nkiri atọ o mere maka ụlọ ọrụ asụsụ Spanish nke Fox. Mgbe nke ahụ gasịrị, ọ pụtara na El impostor (1931) na Eran Trece (1931) maka ụlọ ọrụ ahụ.<ref name="Rivera59" /> Mgbe ọ kwụsịrị na Mexico City na Havana, ebe ọ rụrụ ọrụ na ihe nkiri, Castejón gara Buenos Aires, ebe o mere ihe nkiri abụọ: Crimen a las tres (1935, a box-office flop) na Por buen camino (1935). Ka ọ na-eru ngwụcha afọ 1930, ọ laghachiri Hollywood ma mee ihe nkiri na asụsụ Spanish, ọ kachasị Mis dos amores (1938), nke onye a ma ama na Mexico bụ Tito Guizar, na Los hijos mandan (Gabriel Soria, 1939), ya na Fernando Soler na Arturo nke Córdova. Castejón so dee ihe nkiri nke Los hijos mandan na ihe nkiri abụọ ahụ bụ nke onye Puerto Rican Rafael Ramos Cobián mepụtara. Onye na-eme ihe nkiri ahụ lụrụ onye na-emeeme ihe nkiri na Mexico Rafael Banquells mgbe ọ kwagara Mexico City wee sonye n'ụlọ ọrụ ihe nkiri mba ahụ, ebe o mere ihe dị ka ihe nkiri iri atọ, na-ekere òkè n'ihe a maara dị ka Golden Age of Mexican Cinema . <ref name="Rivera60">{{Harvnb|Rivera|2010|pp=60}}</ref> Ọ bụ ezie na ọ malitere ime ihe nkiri dịka La razón de la culpa (Juan José Ortega, 1943), ya na Pedro Infante na María Elena Marqués, na Divorciadas (Alejandro Galindo, 1943), nke ya na René Cardona na Delia Magaña, Blanca de Castejón ghọrọ onye a ma ama maka ọrụ nkwado ya na ndị na-eme ihe na-atọ ọchị dị ka Luis Sandrini na Fernando Soler. O nwetara Awọọdụ Ariel nke 1954 (Mexico version of the [[Academy Awards|Oscars]]) maka ọrụ nkwado ya dị ka onye na-eme ihe nkiri n'Escuela de vagabundos (School for Tramps), ihe a ma ama nke ihe nkiri screwball nke 1938 Merrily We Live, nke jikọtara ya na Pedro Infante. Castejón meriri na 1956 Ariel de Plata maka iso na Escuela de Vagabundos (1955). Ọ pụtakwara n'ụdị ihe ọzọ, Escuela para suegras (1956). Ihe nkiri ikpeazụ Castejón mere bụ Los Signos del Zodiaco (1963). <ref name="Rivera60" /> == Fimọgrafị == * ''Resurrection'' (1931) * ''El impostor'' (1931) – Sandra * ''Esclavas de la moda'' (1931) – Dora Durke * ''Eran trece'' (''There Were Thirteen'') (1931) – Peggy Minchin (credited as Blanca Castejón) * ''Crimen a las tres'' (1935) * ''Por buen camino'' (1936) * ''El carnaval del diablo'' (1936) * ''Mis dos amores'' (1938) – Rita Santiago * ''Los hijos mandan'' (1939) * ''Qué hombre tan simpático'' (1943) – Doña Blanca * ''La razón de la culpa'' (1943) – María de la Paz * ''[[Ave sin nido]]'' (1943) – Anita de Medina * ''Divorciadas'' (1943) – Cristina * ''Imprudencia'' (1944) * ''¡Ya tengo a mi hijo!'' (1946) – Ana María * ''Los maridos engañan de 7 a 9'' (1946) * ''Yo soy tu padre'' (1948) – Doña Carmen * ''Cuide a su marido'' (1950) – Rosario * ''Yo también soy de Jalisco'' (1950) * ''Nosotras las taquígrafas'' (1950) – Blanquita * ''My Goddaughter's Difficulties'' (1951) – Doña Carmen Martínez * ''Todos son mis hijos'' (1951) – Doña María de Salgado * ''Mamá nos quita los novios'' (1952) – Amadora * ''Prefiero a tu papá'' (1952) – Anita Adalis * ''Escuela para vagabundos'' (''School for Tramps'') (1955) – Emilia de Valverde * ''El gallo colorado'' (1957) * ''Escuela para suegras'' (''School for Mothers-In-Law'') (1958) – Amalia * ''Mientras el cuerpo aguante'' (1958) – Regina Sarmiento * ''Tres lecciones de amor'' (1959) – Doña Angustias * ''Vagabundo y millonario'' (1959) – María de Aguilar * ''Los signos del zodiaco'' (1963) – Lola Casarini == Hụkwa == * Ndepụta nke ndị Puerto Rican == Edensibịa == '''Ndetu n'okpuru akwụkwọ''' '''Footnotes''' {{reflist|2}} '''Akwụkwọ''' == Njikọ mpụga == {{Authority control}} [[Otú:Articles with hCards]] [[Otú:Ndị a mụrụ na 1906]] [[Otú:Ndi nwụrụ na 1969]] [[Otú:Ndi mmadụ si na Comerío, Puerto Rico]] [[Otú:Ndị na-eme ihe nkiri fiim si Puerto Rico]] [[Otú:Ndị natara Awọọdụ Best Supporting Actress]] i9wr4z4th3x4hto3jzjnav4joipqtp2 Ojiarụ:IgboRefBot 2 80780 736726 735659 2026-10-07T14:52:05Z King ChristLike 13051 Ce 736726 wikitext text/x-wiki {{bot|Dolphyb|site=ig}} == IgboRefBot == '''IgboRefBot''' is an automated bot created to help maintain and improve references on the [https://ig.wikipedia.org Igbo Wikipedia]. == What IgboRefBot do == The bot helps identify and repair common reference and citation problems, particularly when content is translated from the English Wikipedia to Igbo Wikipedia that is located in [https://ig.wikipedia.org/wiki/Ot%C3%BA:Pages_with_reference_errors this category] . ===Its tasks may include:=== *Missing empty reference definition with multiple definitions of same reference. *Missing reference list<nowiki> {{Reflist}}, <References /> and ==Edensibia ==</nowiki> *Named reference without any definition found. *Multiple definitions of the same named reference. *Malformed <ref> tag. ''This list is likely going to grow with more tasks in the future.'' == How it works == IgboRefBot uses a citation detection and repair system to analyze article wikitext before making any changes. ===The bot follows a cautious approach:=== *Detect possible citation or reference errors. *Analyze the surrounding wikitext to determine the type of problem. *It's primary source of information is the equivalent article on English Wikipedia. *Determine whether an automatic repair is appropriate. *Apply the repair only when the bot is sufficiently confident. *Record the result of the operation in the bot's logs. The bot is designed to '''avoid making changes when it cannot confidently determine the correct repair'''. == Bot operator == This bot is operated by [[User:Dolphyb|Dolphyb]] and supervised by [[User:King_ChristLike|King ChristLike]]. If you notice a problem with an edit made by this bot, please leave a message on the operator's talk page. == Logs == The bot keeps logs of its activities, including articles checked, articles edited, and successful repair operations. Monthly logs can be found here: [[Ńkàtá_ojiarụ:IgboRefBot | Bot Talkpage]] im3u2195bflm6gjbspa5pfj3sgtbqa8 JoAnne A. Epps 0 80797 736840 735680 2026-10-08T04:44:01Z InternetArchiveBot 11600 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.6 736840 wikitext text/x-wiki <templatestyles src="Module:Infobox/styles.css"></templatestyles>{{Infobox officeholder | name = JoAnne A. Epps | order = 13th President of [[Temple University]] | term_start = April 11, 2023 | term_end = September 19, 2023 | predecessor = [[Jason Wingard]] | successor = [[Richard M. Englert]] (acting) | birth_date = {{Birth date|1951|5|28}} | birth_place = [[Cheltenham, Pennsylvania]], U.S. | death_date = {{Death date and age|2023|9|19|1951|5|28}} | death_place = [[Philadelphia]], Pennsylvania, U.S. | spouse = L. Harrison Jay | education = {{ubl|[[Trinity College (Connecticut)|Trinity College]] ([[Bachelor of Arts|BA]])|[[Yale University]] ([[Juris Doctor|JD]])|[[Temple University]] ([[Honorary Doctor|DHL]])}} }} '''JoAnne Adrienne Epps''' May 28, 1951 - Septemba 19, 2023) bụ onye America na-amụ iwu na njikọ.  Mgbe ọ rụchara ọrụ dị ka osote onye isi oche na onye isi nke Mahadum Ụlọ nsọ, ọ bụ onye isi oche nke iri na atọ nke mahadum ahụ.  Ọ bụ njirimara mbụ a ndabere kpamkpam ma onye isi oche nke Mahadum ahụ. == Mbido ndụ na agụmakwụkwọ == Nna Joanne Adrienne Epps bụ onye na-arụ ọrụ n'akpa, nne ya bụkwa onye ụmụaka na Ụlọ Akwụkwọ Nka Tyler nke Temple(n'oge ahụ na Elkins Park).&amp;nbsp; A akwụkwọ ya na Mee 28, 1951, ma too na Cheltenham, Pennsylvania, akwụkwọ na Cheltenhan , gụsịrị akwụkwọ na Cheltenhan Ụlọ akwụkwọ sekọndrị Cheltenhan na 1969. A nabatara ya dị ka nwa akwụkwọ Africa-America na-ekwe nkwa idebanye aha na Trinity College na Hartford, Connecticut, ebe ọ ghọrọ onye otu klas mbụ nke ụmụ nwanyị n'ụlọ akwụkwọ ahụ.<ref name="Mondics-2016">{{cite news |last1=Mondics |first1=Chris |title=JoAnne A. Epps: Stepping into new roles is nothing new to her |url=https://www.inquirer.com/philly/business/20161113_JoAnne_A__Epps__Stepping_into_new_roles_is_nothing_new_to_her.html |access-date=September 20, 2023 |work=[[The Philadelphia Inquirer]] |date=November 11, 2016}}</ref> Epps nwetara B.A. na 19731973 saịtị na Atọ n'Ime Otu na JD na saịtị 1976 na Yale Ụlọ Akwụkwọ Iwu.. N'afọ 2026, Epps natara Honorary DọkịtaEbe a na-edebe akwụkwọ ozi nsọpụrụ Epps malitere ọrụ iwu ya na 1976, dị ka osote onye ọka iwu obodo na Los Angeles. Ọ laghachiri Philadelphia na 1980, wee bụrụ osote onye ọka iwu United States. Ọ sonyeere TempleDọkịtaEbe dị ka onye otu ngalaba na 1985, wee jee ozi dị ka osote dean maka ihe omume agụmakwụkwọ site na 1989 ruo 2008. N'afọ 2009, a kpọrọ aha ya dị ka onye nwere ike ịbụ Onye na-azọ ọkwa onyeisiala n'Ụlọikpe Kasị Elu nke Barack Obama. Ọ rụrụ ọrụ dị ka dean nke Temple University Beasley School of Law site na 2008 ruo 2016 tupu ọ bụrụ provost. <ref name="Mondics-2016" /> Ọ ghọrọ onye isi oche na 2023, mgbe Jason Wingard gbara arụkwaghịm. Akụkụ izizi bụ isi nke Epps gụnyere usoro mpụ, ihe akaebe, na nkwado ikpe. Ọ kụziri Litigation Basics, ihe ọmụmụ maka ụmụ akwụkwọ iwu afọ mbụ na Temple.<ref name="The Philadelphia Inquirer-2016">{{cite news |title=From prosecutor to provost, Temple's JoAnne Epps leaves a mark in law |url=https://www.inquirer.com/philly/business/20161101_From_prosecutor_to_provost__Temple_s_JoAnne_Epps_leaves_a_mark_in_law.html |access-date=September 20, 2023 |work=[[The Philadelphia Inquirer]] |date=October 31, 2016 |language=en}}</ref> National Jurist kpọrọ Epps otu n'ime ndị isi iri abụọ na ise kachasị emetụta na agụmakwụkwọ iwu, ọrụ ya na usoro mmụta na mmụta mmụta nke agụmakwụkwọ gbasara iwu jere ozi dị ka ihe mkpali maka ụlọ ọrụ ọhụrụ na Ụlọ Akwụkwọ Iwu Ụlọ Nsọmaka ọzụzụ maka ịnweta ikpe ziri ezi (Stephen na Sandra Sheller Center for Social Justice). Epps zụrụ ndị ọka iwu Sudan bụ ndị nọchitere anya ndị agha ahụ metụtara na Darfur, yana ndị ọkàiwu maka Ụlọikpe Mba Nile nke UN maka Rwanda.<ref name="temple-je">{{Cite web|url=https://law.temple.edu/contact/joanne-epps/|title=JoAnne A. Epps – Temple Law|website=Temple University Beasley School of Law|access-date=2026-10-06|archive-url=https://web.archive.org/web/20231204162444/https://law.temple.edu/contact/joanne-epps/|archive-date=2023-12-04|url-status=dead}}</ref> Mgbe ọ nwụsịrị, ndị Temple's Board of Trustees kpọrọ Epps onye isi oche mahadum nke iri na atọ, na-ewepụ "omume" n'ọkwa ya. Epps lụrụ L. (Lamont) Harrison Jay, onye ọrụ ogologo oge na ụlọ ọrụ Temple na-ahụ maka ihe gbasara obodo. Ha biri na Shamong Obodo, New Jersey . L. (Lamont) Harrison Jay nwụrụ n'Ọktoba 30, 2025 obere oge ka ọ gachara afọ iri asaa na otu. Na Septemba 19, 2023, Epps nọ n'elu ikpo okwu n'ememe ncheta maka Charles L. Blockson na Temple's Performing Arts Center, mgbe ọ dara ọrịa na mberede ma tụbọọ n'oche ya. A kpọgara ya n'Ụlọ Ọgwụ Mahadum Temple, ebe a kwupụtara na ọ nwụọla mgbe ọ dị afọ iri asaa na abụọ. Otu onye ọrụ ibe ya na-ekwupụta ọnwụ ya kọwara ọrịa ya dị ka "ihe mberede". * 2026 - Honorary Doctor of Humane Letters - Temple University * 2024 - JoAnne Epps Hero of Justice Award - Pennsylvania Innocence Project * 2023 - Onye isi ala Emerita - Mahadum Temple * 2023 - JoAnne A. Epps Beasley School of Law Scholarship - Temple University<ref name="news.temple.edu">{{cite web | url=https://news.temple.edu/news/2024-09-26/honoring-joanne-epps-year-reflection-and-celebration | title=Honoring JoAnne A. Epps: A year of reflection and celebration | date=September 26, 2024 }}</ref> * 2023 - JoAnne A. Epps Undergraduate Scholarship - Temple University <ref name="news.temple.edu" /> * 2017 - JoAnne Epps Award - Òtù Ndị Ọkaiwu nke Philadelphia * 2016 - Onye ndu azụmaahịa na Diversity Award - Fisher Phillips Law Firm * 2016 - Klas Inaugural Philadelphia Business Hall of Fame - Philadelphia Inquirer * 2016 - Onyinye Mmụọ nke Ịdị Mma - American Bar Association * 2015 - Ashley Dickerson Award - National Association of Women Lawyers <ref name="temple-news.com">{{cite web | url=https://temple-news.com/mentor-educator-friend-honoring-joanne-epps/ | title=Mentor, educator, friend: Honoring JoAnne Epps - the Temple News | date=September 26, 2023 }}</ref> * 2014 - Justice Sonia Sotomayor Diversity Award - Philadelphia Bar Association <ref name="temple-news.com" /><ref name="leadinginclusion2018.president.upenn.edu">{{cite web | url=https://leadinginclusion2018.president.upenn.edu/cth_speaker/joanne-a-epps/ | title=>Changing the National Conversation - Inclusionand Equity 2018 }}</ref> * 2012 - Nwa nwanyị pụrụ iche nke Pennsylvania - Commonwealth of Pennsylvania <ref name="inquirer.com">{{cite web | url=https://www.inquirer.com/obituaries/joanne-a-epps-obituary-temple-university-president-philadelphia-20230922.html | title=From Cheltenham to Temple and all stops in between, JoAnne A. Epps made people feel 'special, important, and seen' | date=September 22, 2023 }}</ref> * 2009 - Wiley A. Branton Award - National Bar Association <ref name="inquirer.com" /> * 2009 - Justice Sandra Day O'Connor Award - Philadelphia Bar Association <ref name="temple-news.com" /><ref name="leadinginclusion2018.president.upenn.edu" /> * "Classical Rhetoric and the Modern Trial Lawyer", 36 Litigation 2, na Paul Mark Sandler & Ronald J. Waicukauski, 2010 *   * The 12 Secrets of Persuasive Argument, na Paul Mark Sandler & Ronald J. Waicukauski, American Bar Association, 2009,   * 101 Vignettes for Improving Trial Evidence: Making and Meeting Objections with Anthony Bocchino and David Sonenshein, , National Institute for Trial Advocacy, mbipụta nke abụọ: 2023, mbipụta nke mbụ: 2005  * Ihe akaebe ikpe: Ime na Nzukọ Ihe Mmegide (akwụkwọ, vidio na akwụkwọ ntuziaka onye nkuzi) na D. Sonenshein & A. Bocchino, , National Institute for Trial Advocacy, mbipụta nke atọ: 2004; mbipụta nke abụọ: 1990  * The Winning Argument, na P. M. Sandler & R. J. Waicukauski, American Bar Association, 2001,   * "Ethos and the Art of Argument", 26 Litigation 31, na Paul Mark Sandler na Ronald J. Waicukauski, 1999 * "Ịkọwapụta ihe Iwu Federal nke Ihe Akaebe pụtara" 703, 36 Boston College Law Review, 53, 1994 * "Ịgafe nkwekọrịta esemokwu ịkwụsị akara: Ọ bụ ihe niile a nụrụ n'iwu kwadoro?" 77 Akwụkwọ akụkọ Iwu Kentucky, 7, 1988 [33] <templatestyles src="Reflist/styles.css" />  == Edensibịa == {{Reflist}} gi2qi8md7n1dd9d8n2gc5e5a8886mlo Prudence Nobantu Mabele 0 81175 736827 736698 2026-10-07T22:56:11Z Adimora chidinma 15845 736827 wikitext text/x-wiki {{databox}}   '''Prudence Nobantu Mabele''' (21 Julaị 1971 – 10 Julaị 2017) bụ onye South Africa [[w:activism|activist]] nke kwadoro ikike ụmụ nwanyị na ụmụaka bi na HIV/AIDS, nakwa megide ime ihe ike n'etiti nwoke na nwanyị. A chọpụtara na o nwere HIV/AIDS na 1990 ma kwupụta ọkwa ya n'ihu ọha na 1992. O hiwere Positive Women's Network na 1996. Ọ rụrụ ọrụ na UNAIDS ma ruo eru dịka sangoma. Ọ nwetara ọtụtụ ihe nrite, gụnyere Felipa de Souza award na 1999. Na 2004, o buru Olympic flame. Ọ nwụrụ na 2017 ma n'uche ya International AIDS Society guzobere ihe nrite kwa afọ maka ndị na-akwado okike. ==ndụ Mmalite == A mụrụ Prudence Nobantu Mabele na Wattville [[obodo]] dị nso na [[w:Benoni, Gauteng|Benoni]], n'ọwụwa anyanwụ nke Johannesburg, South Africa na 21 Julaị 1971.<ref name="Lancet">{{cite journal |last1=Green |first1=Andrew |title=Obituary |journal=The Lancet |date=19 August 2017 |volume=390 |url=https://www.thelancet.com/pdfs/journals/lancet/PIIS0140-6736(17)32096-2.pdf |accessdate=18 August 2020}}</ref> Nne nne ya bụ́ Nosifako Elizabeth Mabele na nna nna ya bụ́ July Mabele zụlitere ya, ebe nne ya nọ n'ala ọzọ, nna ya bụkwa onye agha uMkhonto we Sizwe. Prudence, bụ́ onye mbụ n'ime ụmụnne nwanyị anọ, hapụrụ Wattville gaa Pietermaritzburg ka ọ gaa gụọ akwụkwọ sekọndrị, wee gaa Technikon Witwatersrand na [[w:Cape Peninsula University of Technology|Cape Town Technikon]].{{citation needed|date=August 2020}} A chọpụtara na ọ bu ọrịa [[HIV/AIDS]] na mbụ n'afọ 1990.<ref name="BBC">{{cite news |title=HIV campaigner's 'generosity cost life' |url=https://www.bbc.co.uk/news/world-africa-40653944 |accessdate=18 August 2020 |work=BBC News |date=19 July 2017 |archive-date=6 December 2018 |archive-url=https://web.archive.org/web/20181206185913/https://www.bbc.co.uk/news/world-africa-40653944 |url-status=live }}</ref> N'agbanyeghị ọtụtụ ihe ịma aka ndị a chọpụtara na ha bu nje HIV mgbe ha dị obere, Prudence nwetara akara ugo mmụta diploma na ọkụ eletrik injinịa eletriki na 1994. Ihe ndị ọzọ o mere n'agụmakwụkwọ gụnyere akara ugo mmụta na akparamàgwà mmadụ]] na Intec College na 1996, akara ugo mmụta na njikwa site na [[w:Mahadum nke Witwatersrand|Ụlọ Akwụkwọ Azụmaahịa Wits]] na asambodo na "Ụmụ nwanyị na Njikwa", "Nduzi HIV na AIDS" na "Nlekota na Nyocha maka Mmemme Ahụike Mmekọahụ na Ọmụmụ.{{citation needed|date=August 2020}} ==Ọrụ== Na 1992, Mabele mere ka ọha mara na ọ nwere nje HIV, nke mere ka ọ bụrụ otu n'ime ụmụ nwanyị mbụ si South Africa mee nke ahụ.<ref name=":4">{{Cite book |last1=Windwood |first1=Akaya |url=https://books.google.com/books?id=nOdmEAAAQBAJ&dq=Prudence+Nobantu+Mabele&pg=PA62 |title=Leading with Joy: Practices for Uncertain Times |last2=Bhansali |first2=Rajasvini |date=2022-10-04 |publisher=Berrett-Koehler Publishers |isbn=978-1-5230-0283-2 |pages=62 |language=en}}</ref> Ọ ghọrọ onye na-akwado [[w:HIV/AIDS na Afrịka|mmata HIV]], wee guzobe Positive Women's Network na 1996.<ref name="BBC" /><ref name=":4" /> Mgbe ọ nwụrụ, Mabele bụ onyeisi oche nke Society for Women and AIDS in Africa na osote onyeisi oche nke Civil Society Forum – South African National AIDS Council.<ref name=":0">{{Cite web|url=https://www.enca.com/south-africa/prudence-mabele-leading-hiv-activist-dies|title=Prudence Mabele, leading HIV activist, dies|website=www.enca.com|language=en|access-date=2017-07-13|archive-date=17 July 2017|archive-url=https://web.archive.org/web/20170717101325/http://www.enca.com/south-africa/prudence-mabele-leading-hiv-activist-dies|url-status=live}}</ref> Mabele bụ onye isi oche nke WomenNOW! Summit gbasara Ahụike na Ikpe Ziri Ezi nke Ụmụnwaanyị Ndị Africa na Ndị Africa nke si mba ọzọ bịa.<ref>{{Cite web|title=Women's Activism NYC|url=https://www.womensactivism.nyc/stories/1522|access-date=2021-01-20|website=www.womensactivism.nyc}}</ref><ref>{{Cite web|title=Prudence Nobantu Mabele - InfoHub|url=https://infohub.projecttopics.org/1924119-prudence-nobantu-mabele|access-date=2021-01-20|website=infohub.projecttopics.org|archive-date=29 January 2021|archive-url=https://web.archive.org/web/20210129013423/https://infohub.projecttopics.org/1924119-prudence-nobantu-mabele|url-status=dead}}</ref> Ọ na-arụkọkwa ọrụ mgbe niile na Mmemme Njikọ Mba Ndị Dị n'Otu gbasara HIV/AIDS (UNAIDS).<ref name="UNAIDS">{{cite web |title=UNAIDS saddened by the death of Prudence Mabele |url=https://www.unaids.org/en/resources/presscentre/pressreleaseandstatementarchive/2017/july/20170711-prudence-mabele |website=www.unaids.org |accessdate=18 August 2020 |language=en}}</ref> Mabele gụchara ọzụzụ ya dịka [[w:Ndị na-agwọ ọrịa ọdịnala nke ndịda Afrịka|sangoma]] (dọkịta ọdịnala) na 2004. O were ọgwụ ARV mgbe ha dị na sistemụ ahụike ọha na eze na South Afrịka. O kwadoro iji ọgwụ ARV n'ihi na ya onwe ya ahụla mbibi nke ọrịa AIDS kpatara. Mabele zara oku ya ka ọ bụrụ onye na-agwọ ọrịa ọdịnala afọ ole na ole mgbe ọ malitere ọgwụ ARV, ihe fọrọ nke nta ka ọ bụrụ afọ iri ka ọ chọpụtara na ọ bụ onye HIV..<ref name=":1">{{Cite web|url=http://bhekisisa.org/article/2013-11-29-00-the-sangoma-who-lives-for-science|title=Remembering Prudence Mabele: The sangoma who lived for science|last=Skosana|first=Ina|website=Bhekisisa|date=29 November 2013 |language=en|access-date=2017-07-14|archive-date=13 July 2017|archive-url=https://web.archive.org/web/20170713075300/http://bhekisisa.org/article/2013-11-29-00-the-sangoma-who-lives-for-science|url-status=live}}</ref> Mabele bụ onye a na-eme ngagharị iwe n'afọ 2004 mgbe ihe karịrị ndị na-agwọ ọrịa ọdịnala 500 gara ngagharị iwe iji nye ya akwụkwọ mkpesa megide Mgbasa Ozi Ọgwụgwọ (TAC). Nsogbu bụ na TAC na-akwalite naanị ARV na ọgwụ ọdịnala ndị ọzọ.{{citation needed|date=August 2020}} {{Blockquote | text = Ndị na-enye onyinye kwụsịrị inye ndị otu nkwado ego n'ihi na ha abụghịzi ejiji. Mana Pru maara eziokwu ahụ, nke bụ na ndụ ụmụ nwanyị na-eme na mkparịta ụka, n'oge ọ na-ewe iji nọdụ ala na ibe ha. Ndị otu ahụ bụ nkwado ndụ mmetụta uche maka ụmụ nwanyị nọ n'ọnọdụ dị oke njọ, ndị ndụ ha gbawara agbawa ma chọọ ka obi ha dị n'otu. Pru rụrụ ọrụ ahụ. Ọ gara leta ọtụtụ ezinụlọ na-eru uju. Mgbe e gburu ndị lesbian nwanyị, Pru gara. Mgbe nwanyị ọzọ nwere HIV nwụrụ, Pru nọ ebe ahụ. Mgbe e gburu otu nwanyị, Pru nọ n'ihu. E sere ya ihe, mee ka ọ dị mma, olu ya gbapụrụ agbapụ, na-eku ume n'ọnụ ya, na-akpọ iyi ma na-egwu egwu ma na-agba ọsụsọ, ọ nọ ebe ahụ. | author = [[Sisonke Msimang]] | title = The Pied Piper of the broken-hearted: HIV activist Prudence Mabele | source = <ref>{{Cite news|url=https://mg.co.za/article/2017-07-12-prudence-mabele-my-guide-to-the-new-south-africa|title=The Pied Piper of the broken-hearted: HIV activist Prudence Mabele|last=Msimang|first=Sisonke| author-link= Sisonke Msimang|work=The M&G Online|access-date=2017-07-13|language=en|archive-date=20 July 2017|archive-url=https://web.archive.org/web/20170720092653/https://mg.co.za/article/2017-07-12-prudence-mabele-my-guide-to-the-new-south-africa|url-status=live}}</ref> }} ==Gender advocacy== Mabele bụ onye na-akwadosi ike ịkwụsị ime ihe ike megide ụmụ nwanyị ma bụrụkwa onye otu nke One in Itoolu Campaign. Otu n'ime Itoolu malitere na nzaghachi nye [[w:ikpe mmeko nwoke na nwanyị Jacob Zuma|ikpe mmeko nwoke na nwanyị]] nke Jacob Zuma, onye bụ osote onyeisiala n'oge ahụ. A kpọrọ otu n'ime Itoolu aha maka eziokwu ahụ bụ na naanị otu n'ime ụmụ nwanyị Itoolu na South Africa na-akọ akụkọ mpụ nye ndị uwe ojii, ihe akaebe doro anya gbasara etu ndị uwe ojii na usoro ikpe si dị mfe ịnweta ma ghara ịnabata ha na SA..<ref name=":3">{{Cite news|url=http://www.africanfeministforum.com/prudence-nobantu-mabele/|title=Prudence Nobantu Mabele – African Feminist Forum|date=2016-03-24|work=African Feminist Forum|access-date=2017-07-16|language=en-US|archive-date=28 August 2017|archive-url=https://web.archive.org/web/20170828144010/http://www.africanfeministforum.com/prudence-nobantu-mabele/|url-status=live}}</ref> O kwuru sị, "Ekwenyere m na àgwà ụmụ nwanyị na-edu ndú dị mkpa karịa ọnụọgụgụ ụmụ nwanyị na-edu ndú"."<ref name=":3" /> Mabele so n'ime ndị guzobere mkpọsa [[w:Ntọrọ ụmụ agbọghọ Chibok | Bring Back Our Girls]] nke South Africa.<ref name=":0" /> Ọ rụkwara ọrụ na ihe nkiri akpọrọ "Sunshine Boutique".''.{{citation needed|date=August 2020}} ==Ihe nrite na mmata== Mabele natara nsọpụrụ nke ibu ọkụ Olympic dịka akụkụ nke ngagharị ọkụ mba ụwa maka Olimpiks 2004 na Gris.<ref name=":0" /> Ọ natara ọtụtụ ihe nrite ikike mmadụ n'oge ọrụ ya. Ihe ndị a gụnyere ihe nrite Nwanyị nke Obi Ike site na SOS Children's Villages, ihe nrite nwanyị kachasị elu nke Gauteng Provincial Government, nkwanye ùgwù maka itinye aka na ihe omume HIV/AIDS na ihe nrite nkwanye ùgwù maka nzaghachi ebe ọrụ Eskom.<ref name=":2">{{Cite web|url=http://whoswho.co.za/prudence-mabele-6344|title=Prudence Mabele |work=Who's Who SA|language=en|access-date=2017-07-14|archive-date=23 July 2017|archive-url=https://web.archive.org/web/20170723172836/http://whoswho.co.za/prudence-mabele-6344|url-status=live}}</ref> Na 1999, International Gay and Lesbian Human Rights Commission nyere ya ihe nrite Felipa de Souza.<ref name="Felipa">{{cite web |title=A Celebration of Courage: Felipa Awardees 1994–1999 |url=https://outrightinternational.org/content/celebration-courage-felipa-awardees-1994-1999 |website=OutRight Action International |accessdate=18 August 2020 |language=en |date=1 May 1999 |archive-date=14 July 2020 |archive-url=https://web.archive.org/web/20200714051620/https://outrightinternational.org/content/celebration-courage-felipa-awardees-1994-1999 |url-status=live }}</ref> ==Ọnwụ na ihe nketa== Mabele nwụrụ site na oyi baa n'ahụ na Julaị 10, 2017, mgbe ọ dị afọ 45.<ref name="BBC" /> Iji mee emume ncheta ihe nketa ya, International AIDS Society guzobere onyinye ego ruru $25,000 maka ndị na-akwado okike, nke Ford Foundation, Open Society Foundations na Positive Women's Network of South Africa] kwadoro]]. E nyere Duduzile Dlamini onyinye mbụ na Amsterdam na 2018.<ref name="PMP">{{cite web |title=Prudence Mabele Prize presented to South African sex work activist Duduzile Dlamini at AIDS 2018 |url=http://www.aids2018.org/Media-Centre/The-latest/Press-releases/ArticleID/179/Prudence-Mabele-Prize-presented-to-South-African-sex-work-activist-Duduzile-Dlamini-at-AIDS-2018 |website=AIDS 2018 |accessdate=18 August 2020 |archive-date=18 May 2019 |archive-url=https://web.archive.org/web/20190518194806/http://www.aids2018.org/Media-Centre/The-latest/Press-releases/ArticleID/179/Prudence-Mabele-Prize-presented-to-South-African-sex-work-activist-Duduzile-Dlamini-at-AIDS-2018 |url-status=live }}</ref> == Edensibịa == <templatestyles src="Reflist/styles.css" />  [[Otú:Articles with hCards]] 3zz6huzzj1yqlmeh16edjpgde3j3xqt Ńkàtá ojiarụ:Juan Emilio Prades Bel 3 81176 736699 2026-10-07T12:00:42Z DolphybBot 61063 Nabata onye ohuru na Igbo Wikipedia! (bot) 736699 wikitext text/x-wiki {{Nnọọ|username=Juan Emilio Prades Bel|bot=[[Ojiarụ:DolphybBot|DolphybBot]] ([[Ńkàtá ojiarụ:DolphybBot|ṅkátá]]) 12:00, 7 Ọktoba 2026 (UTC)}} 1m3j7urumrhxaneq51nu9fyqn7whho0 Aminata Traoré (onye edemede) 0 81177 736701 2026-10-07T12:47:22Z Iwuala Judith Chinenyenwa 24940 Ekere na itugharị ihụakwụkwọ nke a "[[:en:Special:Redirect/revision/1348105647|Aminata Traoré (author)]]" 736701 wikitext text/x-wiki {{Infobox officeholder | name = Aminata Traoré | native_name = <!--The person's name in their own language, if different.--> | native_name_lang = <!--ISO 639-1 code, e.g., "fr" for French. If more than one, use {{lang}} in |native_name= instead.--> | image = Aminata Traore IMG 0245.jpg | alt = | caption = Aminata Traoré in 2008 at the [[Libération]] forum in [[Grenoble]] | office = [[Ministry of Tourism, Arts & Culture Ghana|Minister of Culture and Tourism of Mali]] | term_start = 1997 | term_end = 2000 | president = [[Alpha Oumar Konaré]] | primeminister = [[Ibrahim Boubacar Keïta]] | predecessor = | successor = <!-- should not be filled until the successor takes office--> | birth_name = Aminata Dramane Traoré | birth_date = {{Birth year and age|1947}} | birth_place = [[Bamako]], [[Mali]]<ref name=casafrica/> | death_date = <!-- {{Death date and age|YYYY|MM|DD|YYYY|MM|DD}} --> | death_place = | party = | otherparty = <!--For additional political affiliations--> | spouse = | partner = <!--For those with a domestic partner and not married--> | children = | parents = <!-- overrides mother and father parameters --> | education = | alma_mater = | awards = <!-- For civilian awards – appears as "Awards" if |mawards= is not set --> }} <templatestyles src="Reflist/styles.css" />'''Aminata Dramane Traoré''' (amụrụ n'afọ 1947) bụ onye odee [[Mali]] na onye ndọrọ ndọrọ ọchịchị. Ọ rụrụ ọrụ dị ka Minista na-ahụ maka omenala na njem nleta nke Mali site na 1997 ruo 2000 ma rụọkwa ọrụ dị ka onye nhazi nke United Nations Development Programme. Ọ bụ onye nhazi nke Forum pour l'autre Mali ugbua na onye otu onye nhazi nke [[International Network for Cultural Diversity]] ma ahọpụtara ya na bọọdụ nke International Press Service na July 2005. Ọ bụ onye otu kọmitii sayensị nke Fundacion IDEAS, otu ndị ọkachamara na-enye ndụmọdụ nye pati Socialist nke Spain. == Nlele == Traoré bụ onye a ma ama na-akatọ usoro ijikọ ụwa ọnụ (globalization) na atụmatụ akụ na ụba nke mba ndị kacha nwee ọganihu. Karịsịa, o gosipụtara mmegide ya megide omume mba ndị dị n'Ebe Ọdịda Anyanwụ Ụwa nke inye ndị ọrụ ugbo owu nke ha aka ego (subsidies), ihe na-eme ka mba ndị dị n'Ebe Ọdịda Anyanwụ Afrịka ghara inwe ohere nhata mgbe ha na-asọ mpi ịre ngwaahịa ha n'ahịa mba ndị ahụ. Traoré so n'ime ndị bịanyere aka n'akwụkwọ 'Porto Alegre Manifesto'—ma ọ bụ ndị so na 'Group of Nineteen'—nke e wepụtara n'oge nzukọ World Social Forum nke afọ 2005. Ọ gbachitere Ahmed Sékou Touré, onye bụbu onye isi ala nke [[Guinea]], na-ekwu na aha ọjọọ ya dị ka onye ọchịchị aka ike na mgbalị ya ikpochapụ ndị Fulas site na Futa Djalon na Guinea bụ n'ihi okwu nduhie na ozi na-ezighị ezi. == Ọrụ ndị e bipụtara == * 1999 ''Ihe mgbochi. '' ''Afrịka n'ime ụwa na-enweghị ókèala''. Babel Actes South. * 2002 Nri nke Echiche. Fayard/Actes Sud. * 2005 ''Akwụkwọ ozi e degaara onye isi ala France banyere Côte d'Ivoire na Africa n'ozuzu ya''. Fayard * 2008 ''E wedara Afrịka ala''. Fayard * 2012 E merụrụ Afrịka ahụ. [Ihe e dere n'ala ala peeji] == Onyinye == * 1995 - Ihe nrite Ciwara nke Ịdị Mma * 1996 - Knight nke Usoro Mba nke Mali * 2004 - Prince Claus Cultural Award (Netherlands) * 2006 - Onye isi nke Usoro Mba nke Mali * 2008 - Onye na-akọwa Usoro Mba nke Mali == Edensibịa ==    == Njikọ mpụga == * [http://www.oecd.org/dataoecd/5/63/41682765.pdf Aminata Dramane Traoré Nnupụisi na-emegide ụwa 21 Mee 2008, Bamako Mali. (ajụjụ ọnụ)] Sadou Yattara na Anne Perrin. Akụkọ West Africa 2007-2008, OECD. Disemba 2008. * Aminata Traoré Ajụjụ ọnụ Politis.fr (n'asụsụ French) * [https://web.archive.org/web/20080829204149/http://www.princeclausfund.org/en/what_we_do/awards/2004traore.shtml Nchịkọta nke Prince Claus Award 2004] [[Otú:Mmadụ ndi di ndụ]] 78japg5e8roa3f1bmlhcc60swrd0n6f 736702 736701 2026-10-07T12:59:02Z Iwuala Judith Chinenyenwa 24940 Fixed reference error 736702 wikitext text/x-wiki {{Infobox officeholder | name = Aminata Traoré | native_name = <!--The person's name in their own language, if different.--> | native_name_lang = <!--ISO 639-1 code, e.g., "fr" for French. If more than one, use {{lang}} in |native_name= instead.--> | image = Aminata Traore IMG 0245.jpg | alt = | caption = Aminata Traoré in 2008 at the [[Libération]] forum in [[Grenoble]] | office = [[Ministry of Tourism, Arts & Culture Ghana|Minister of Culture and Tourism of Mali]] | term_start = 1997 | term_end = 2000 | president = [[Alpha Oumar Konaré]] | primeminister = [[Ibrahim Boubacar Keïta]] | predecessor = | successor = <!-- should not be filled until the successor takes office--> | birth_name = Aminata Dramane Traoré | birth_date = {{Birth year and age|1947}} | birth_place = [[Bamako]], [[Mali]] | death_date = <!-- {{Death date and age|YYYY|MM|DD|YYYY|MM|DD}} --> | death_place = | party = | otherparty = <!--For additional political affiliations--> | spouse = | partner = <!--For those with a domestic partner and not married--> | children = | parents = <!-- overrides mother and father parameters --> | education = | alma_mater = | awards = <!-- For civilian awards – appears as "Awards" if |mawards= is not set --> }} <templatestyles src="Reflist/styles.css" />'''Aminata Dramane Traoré''' (amụrụ n'afọ 1947) bụ onye odee [[Mali]] na onye ndọrọ ndọrọ ọchịchị. Ọ rụrụ ọrụ dị ka Minista na-ahụ maka omenala na njem nleta nke Mali site na 1997 ruo 2000 ma rụọkwa ọrụ dị ka onye nhazi nke United Nations Development Programme. Ọ bụ onye nhazi nke Forum pour l'autre Mali ugbua na onye otu onye nhazi nke [[International Network for Cultural Diversity]] ma ahọpụtara ya na bọọdụ nke International Press Service na July 2005. Ọ bụ onye otu kọmitii sayensị nke Fundacion IDEAS, otu ndị ọkachamara na-enye ndụmọdụ nye pati Socialist nke Spain. == Nlele == Traoré bụ onye a ma ama na-akatọ usoro ijikọ ụwa ọnụ (globalization) na atụmatụ akụ na ụba nke mba ndị kacha nwee ọganihu. Karịsịa, o gosipụtara mmegide ya megide omume mba ndị dị n'Ebe Ọdịda Anyanwụ Ụwa nke inye ndị ọrụ ugbo owu nke ha aka ego (subsidies), ihe na-eme ka mba ndị dị n'Ebe Ọdịda Anyanwụ Afrịka ghara inwe ohere nhata mgbe ha na-asọ mpi ịre ngwaahịa ha n'ahịa mba ndị ahụ. Traoré so n'ime ndị bịanyere aka n'akwụkwọ 'Porto Alegre Manifesto'—ma ọ bụ ndị so na 'Group of Nineteen'—nke e wepụtara n'oge nzukọ World Social Forum nke afọ 2005. Ọ gbachitere Ahmed Sékou Touré, onye bụbu onye isi ala nke [[Guinea]], na-ekwu na aha ọjọọ ya dị ka onye ọchịchị aka ike na mgbalị ya ikpochapụ ndị Fulas site na Futa Djalon na Guinea bụ n'ihi okwu nduhie na ozi na-ezighị ezi. == Ọrụ ndị e bipụtara == * 1999 ''Ihe mgbochi. '' ''Afrịka n'ime ụwa na-enweghị ókèala''. Babel Actes South. * 2002 Nri nke Echiche. Fayard/Actes Sud. * 2005 ''Akwụkwọ ozi e degaara onye isi ala France banyere Côte d'Ivoire na Africa n'ozuzu ya''. Fayard * 2008 ''E wedara Afrịka ala''. Fayard * 2012 E merụrụ Afrịka ahụ. [Ihe e dere n'ala ala peeji] == Onyinye == * 1995 - Ihe nrite Ciwara nke Ịdị Mma * 1996 - Knight nke Usoro Mba nke Mali * 2004 - Prince Claus Cultural Award (Netherlands) * 2006 - Onye isi nke Usoro Mba nke Mali * 2008 - Onye na-akọwa Usoro Mba nke Mali == Edensibịa ==    == Njikọ mpụga == * [http://www.oecd.org/dataoecd/5/63/41682765.pdf Aminata Dramane Traoré Nnupụisi na-emegide ụwa 21 Mee 2008, Bamako Mali. (ajụjụ ọnụ)] Sadou Yattara na Anne Perrin. Akụkọ West Africa 2007-2008, OECD. Disemba 2008. * Aminata Traoré Ajụjụ ọnụ Politis.fr (n'asụsụ French) * [https://web.archive.org/web/20080829204149/http://www.princeclausfund.org/en/what_we_do/awards/2004traore.shtml Nchịkọta nke Prince Claus Award 2004] [[Otú:Mmadụ ndi di ndụ]] kppr20ydfoa3f77d4nj5au7ymg64h9u Module:Cs1 828 81178 736708 2026-07-23T14:07:35Z HouseBlaster 15538 HouseBlaster moved page [[Template:Cs1]] to [[Template:Citation Style 1 link]]: Change to standard English spelling, spacing, and capitalization ([[WP:TPN]]) 736708 wikitext text/x-wiki #REDIRECT [[Template:Citation Style 1 link]] {{Redirect category shell| {{R from move}} }} f35nii4kg93goxaeyrgy4g1v8mr06hj 736709 736708 2026-10-07T14:40:42Z King ChristLike 13051 1 revision imported from [[:en:Template:Cs1]] 736708 wikitext text/x-wiki #REDIRECT [[Template:Citation Style 1 link]] {{Redirect category shell| {{R from move}} }} f35nii4kg93goxaeyrgy4g1v8mr06hj Module:Cs2 828 81179 736710 2026-07-23T14:07:56Z HouseBlaster 15538 HouseBlaster moved page [[Template:Cs2]] to [[Template:Citation Style 2 link]]: Change to standard English spelling, spacing, and capitalization ([[WP:TPN]]) 736710 wikitext text/x-wiki #REDIRECT [[Template:Citation Style 2 link]] {{Redirect category shell| {{R from move}} }} 9pimhfrd2ov5bbamx0c9y9emdybmma4 736711 736710 2026-10-07T14:40:42Z King ChristLike 13051 1 revision imported from [[:en:Template:Cs2]] 736710 wikitext text/x-wiki #REDIRECT [[Template:Citation Style 2 link]] {{Redirect category shell| {{R from move}} }} 9pimhfrd2ov5bbamx0c9y9emdybmma4 Module:Citation Style 1 828 81180 736718 2026-10-07T14:32:32Z Trappist the monk 14640 /* Update bibcode URL to SciX */ 736718 wikitext text/x-wiki <!-- Deny citation bot April 2015 because we often post broken citations here intentionally and do not want them to be "fixed". To avoid AnomieBOT substing, use |demo= or |nosubst= instead of adding it here. -->{{bots|deny=Citation bot,SporkBot,Cewbot}}<!-- -->{{skip to bottom}}<!-- -->{{talk header|display_title=Help:Citation Style 1 and the CS1 templates|WT:CS1}} {{central|text=the talk pages for all Citation Style 1 and Citation Style 2 templates and modules redirect here. A list of those talk pages and their historical archives can be found [[Help talk:Citation Style 1/Centralized discussions|here]].}} {{WikiProject banner shell|collapsed=yes|1= {{Wikipedia Help Project|importance=High}} {{WikiProject Academic Journals}} {{WikiProject Magazines}} }} {{User:ClueBot III/ArchiveThis |archiveprefix=Help talk:Citation Style 1/Archive |format= %%i |age=480 |header={{Automatic archive navigator}} |headerlevel=2 |maxarchsize=200000 |minkeepthreads=6 |numberstart=69 |minarchthreads=2 |archivenow=<nowiki>{{User:ClueBot III/ArchiveNow}},{{resolved}},{{done}}</nowiki> }} {{FAQ|page=Help talk:Citation Style 1/FAQ}} ==Cite book: Year of publication== Year of publication states "Year of the source being referenced" Shouldn't this be "Year of source"/"Year of writing" or something like this? Publication date seems to already be used for date when something is published...I think cite book should be clearer about which fields are referring to Publication, and which fields are referring to Writing [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 07:36, 15 July 2026 (UTC) :I've never understood why {{para|publication-date}} exists, {{para|date}} should be used for publication date and {{para|orig-date}} for original date. It seems overly complex to have a third field that needlessly complicates things. -- <small>LCU</small> '''[[User:ActivelyDisinterested|A<small>ctively</small>D<small>isinterested</small>]]''' <small>''«[[User talk:ActivelyDisinterested|@]]» °[[Special:Contributions/ActivelyDisinterested|∆t]]°''</small> 12:56, 15 July 2026 (UTC) ::Since at least April 2020, I have believed that {{para|publication-date}} should go away ([[Help_talk:Citation_Style_1/Archive_65#c-Trappist_the_monk-2020-04-05T21:59:00.000Z-Francis_Schonken-2020-04-06T10:07:00.000Z|here]]). Similarly, I hold that {{para|publication-place}} should go away. There have been several discussions on this topic which are collected at {{slink|Help_talk:Citation_Style_1/Archive_86#place,_when_publication-place_is_redundant_with_work}}. ::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 14:04, 15 July 2026 (UTC) :::Agree, both simply confuse the matter and are redundant. -- <small>LCU</small> '''[[User:ActivelyDisinterested|A<small>ctively</small>D<small>isinterested</small>]]''' <small>''«[[User talk:ActivelyDisinterested|@]]» °[[Special:Contributions/ActivelyDisinterested|∆t]]°''</small> 15:24, 15 July 2026 (UTC) ::Can it not be useful if there are several editions or versions of a work? {{para|date}} for the year of the edition quoted, {{para|orig-date}} for the 1st edition, {{para|publication-date}} for the publication date if it is a later re-edition, publication in another series etc. [[User:Keriluamox|Keriluamox]] ([[User talk:Keriluamox|talk]]) 16:51, 15 July 2026 (UTC) :::References exist for verification, you only need to give details of the work you have not it's publication history. -- <small>LCU</small> '''[[User:ActivelyDisinterested|A<small>ctively</small>D<small>isinterested</small>]]''' <small>''«[[User talk:ActivelyDisinterested|@]]» °[[Special:Contributions/ActivelyDisinterested|∆t]]°''</small> 17:15, 15 July 2026 (UTC) ::::Taking that argument to the extreme, the sole ISBN would suffice. I find it useful to give ''some'' information about the work. Dating a 1900 work from 2020 because that’s the edition used feels off, if not slightly misleading. [[User:Keriluamox|Keriluamox]] ([[User talk:Keriluamox|talk]]) 06:49, 16 July 2026 (UTC) :::::The date is the date of the edition you are using. If the version from 2020 is a facsimile of the 1900 edition, you could cite it as 1900. Otherwise, if it's a new edition it will have new page numbers, etc. –[[user:jacobolus|jacobolus]] [[user_talk:jacobolus|(t)]] 17:48, 30 July 2026 (UTC) ::Take [[Crime and Punishment]] or many other books from around that time. They single volume is different than when the installment was published. More so light novels which are often written in installments on a website, then bought and printed by a publisher. Given that many books take time to publish, especially anthologies, having all three are useful. date is for the creation, orig-date is for when it was originally released, and publication-date is for when this exact publication was made. [[User:Jerodlycett|Jerod Lycett]] ([[User talk:Jerodlycett|talk]]) 06:30, 21 July 2026 (UTC) :::Wouldn't it then make sense to rename 'date' to 'creation-date'? [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 07:56, 30 July 2026 (UTC) ::::The use of {{para|publication-date}} is quite rare, in most cases {{para|date}} is used for current date and {{para|orig-date}} for the original publication date. So it wouldn't make sense to change {{para|date}}. -- <small>LCU</small> '''[[User:ActivelyDisinterested|A<small>ctively</small>D<small>isinterested</small>]]''' <small>''«[[User talk:ActivelyDisinterested|@]]» °[[Special:Contributions/ActivelyDisinterested|∆t]]°''</small> 14:22, 30 July 2026 (UTC) :This is about the <code>&lt;skeptical air quotes></code>documentation<code>&lt;/skeptical air quotes></code> at {{slink|Template:Cite_book#TemplateData}}? The template's actual documentation for {{para|publication-date}} is at {{slink|Template:Cite_book#Date}}. The template data are not protected so if you think that it can be improved, please improve it. :—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 14:04, 15 July 2026 (UTC) ::It's actually at [[Template:Cite book#Publisher]], or more specifically, [[Template:Cite book#csdoc_publication-date]]. --[[User:Redrose64|<span style="color:#a80000; background:#ffeeee; text-decoration:inherit">Red</span>rose64]] &#x1f339; ([[User talk:Redrose64|talk]]) 21:31, 15 July 2026 (UTC) ::{{replyto|ActivelyDisinterested}} {{para|publication-date}} is mainly for non-daily periodicals where the cover date is often later than the date when the periodical goes on sale. For example, a magazine with cover date August 2026 might be on sale already. --[[User:Redrose64|<span style="color:#a80000; background:#ffeeee; text-decoration:inherit">Red</span>rose64]] &#x1f339; ([[User talk:Redrose64|talk]]) 21:01, 15 July 2026 (UTC) :::In taxonomy, the date when a book or journal was first published can be very important to establish precedence. For various reasons the year/date on the title page is not always the year/date when the work was first distributed. In such cases I use date= for the date on the title page and publication-date= for the date when the work was first distributed. - [[User:Aa77zz|Aa77zz]] ([[User talk:Aa77zz|talk]]) 21:23, 15 July 2026 (UTC) ::::How do you know when it was first distributed? [[User:JMF|𝕁𝕄𝔽]] ([[User talk:JMF|talk]]) 22:05, 15 July 2026 (UTC) ::::Date/publication-date are exactly the same thing. If you want the original date use {{para|orig-date}}. &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 16:04, 30 July 2026 (UTC) :::::This is also what I thought, when looking at the documentation ([[Template:Cite book#TemplateData]]): :::::parameter 'date' = 'Date of publication' :::::parameter 'publication-date' = 'Publication date' :::::To me, this looks exactly the same. :::::Given that other people have already expressed that 'publication-date' should go away, I'm just not gonna use 'publication-date' anymore (I don't care this much about dates of book publishing), and try to put the info I have in the fields 'date' and 'orig-date'. Thanks for clearing this up. [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 16:57, 30 July 2026 (UTC) :::::{{ec}} :::::Just to be pedantic, {{para|date}} and {{para|publication-date}} are {{em|only}} {{tq|exactly the same thing}} when they are used alone. Then both are used in the same template they are treated as the same thing when they hold the same value in which case, {{para|publication-date}} is ignored: ::::::<syntaxhighlight lang="wikitext" inline="1">{{cite book |title=Title |date=2026 |publication-date=2026}}</syntaxhighlight> → {{cite book |title=Title |date=2026 |publication-date=2026}} :::::when {{para|date}} and {{para|publication-date}} hold different values: ::::::<syntaxhighlight lang="wikitext" inline="1">{{cite book |title=Title |date=2026 |publication-date=2025}}</syntaxhighlight> → {{cite book |title=Title |date=2026 |publication-date=2025}} :::::Do we really, {{em|really}}, need both? I think that we don't and that we should make {{para|date}} and {{para|publication-date}} exact aliases of one another {{small|({{para|location}} / {{para|place}} and {{para|publication-place}} should also be exact aliases of one another)}}. :::::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 17:12, 30 July 2026 (UTC) ::::::+1 support for that. &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 17:38, 30 July 2026 (UTC) ::::::I agree 'date' and 'publication-date' should be aliases of each other [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 14:27, 3 August 2026 (UTC) ::::::As for <code>location</code>/<code>place</code> and <code>publication-place</code>, that's what I came here for.<br/> ::::::The [[Template:Cite_book/doc]] is quite complex, probably contradictory… <br/> ::::::But in [[Template:Cite_book/doc#Publisher|#Publisher]] it says "Place: In earlier versions was the publication place; for compatibility will be treated as such if publication-place is absent"<br/> ::::::So aliasing those will be OK for older{{when?}} entries, but possibly not for newer; could we count{{how many?}} newer with both present? :::::::So paralleling with <code>date</code> and <code>publication-date</code>, which I suppose would have been introduced at the same time, how much will it fudge? ::::::[[User:Ponken|Ponken]] ([[User talk:Ponken|talk]]) 09:02, 19 August 2026 (UTC) :::::::I like the idea of creation-date. Isn't the template not all about this? :::::::"Title (published 2025). 2026" - is just not clearly understandable, instead rather a wtf (the postscript would be place for such curiosities when they are specifically relevant). :::::::Sorry, if the discussion here is already closed. I just saw now how long the page goes down, wow. (There I will ask a question, for which I am here.) [[User:MenkinAlRire|MenkinAlRire]] 14:10, 31 August 2026 (UTC) ::::::::"Isn't the template not all about this?" I don't think so. The template, and citations in academic works generally, are about identifying the publication that is mentioned in the citing work. If the source says "July 2026" on the cover, that's what someone who wants to read the source will check to make sure they picked up the right issue of the magazine. If some Wikipedian in the magazine business happens to know it was printed April 15, 2026, and first offered for sale May 2, 2026, WE DON'T CARE! [[User:Jc3s5h|Jc3s5h]] ([[User talk:Jc3s5h|talk]]) 14:33, 31 August 2026 (UTC) :::::::::That wasn't my point (that I find irrelevant, too). The template is called speech, and there are several date one could consider: when it was written (there is only a ''location'' for this which translates to "written at"), when the speech was held, and when the text was published (better printed). With "all about this" I meant that a speech was once spoken, I guess, and that is its prime date. Historically, in many, if not the most cases, the impact of a speech came with its distribution in print. But today many lectcures ar recorded and published online. They are preserved as original oral documents as video or audio. So the event where the speech happened gains more importance versus its printed form (if there is one). (Below I discussed some points.) [[User:MenkinAlRire|MenkinAlRire]] 15:54, 31 August 2026 (UTC) ::::::::::"The template is called speech" – You should be aware that this talk-page serves as the talk-page of several templates which use *this* (sub-)template "Citation Style 1". That is: if you click these templates' talk-page link, you end up here. ''edit'' ALSO you are in the thread [[#Cite_book:_Year_of_publication]] here. / [[User:Ponken|Ponken]] ([[User talk:Ponken|talk]]) 09:46, 1 September 2026 (UTC) :::::::::::I also don’t get why this one talk page serves for several templates, instead of each template just having it’s own talk page [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 09:54, 1 September 2026 (UTC) :I have hacked the module sandboxen to make {{para|date}} and {{para|publication-date}} exact aliases. When used alone, {{para|date}} and {{para|publication-date}} have always performed the same function: <div style="margin-left:3.2em>{{cite compare |template=book |title=Title |date=2026}} {{cite compare |template=book |title=Title |publication-date=2026}}</div> :When paired and holding the same dates, {{para|publication-date}} was ignored <div style="margin-left:3.2em>{{cite compare |template=book |title=Title |date=2026 |publication-date=2026}}</div> :When paired with different dates, {{para|publication-date}} modified the publisher string; that no longer happens: <div style="margin-left:3.2em>{{cite compare |template=book |title=Title |date=2026 |publication-date=2025}} {{cite compare |template=book |title=Title |date=2026 |location=Location |publication-date=2025}} {{cite compare |template=book |title=Title |date=2026 |publisher=Publisher |publication-date=2025}} {{cite compare |template=book |title=Title |date=2026 |location=Location |publisher=Publisher |publication-date=2025}}</div> :If we are to believe [https://en.wikipedia.org/w/index.php?search=hastemplate%3A%22Module%3ACitation%2FCS1%22+insource%3A%22publication-date%22+insource%3A%2F%5C%7B+*%5BCc%5Dit%5Bae%5D%5B%5E%5C%7D%5D*%5C%7C+*date%5B%5E%5C%7D%5D*%5C%7C+*publication%5C-date%2F&ns0=1 this search], there are about 10,500 articles with cs1|2 templates that use both {{para|date}} and {{para|publication-date}}. : :Keep? Discard? :—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 16:36, 18 September 2026 (UTC) ::Plus another [https://en.wikipedia.org/w/index.php?search=hastemplate%3A%22Module%3ACitation%2FCS1%22+insource%3A%22publication-date%22+insource%3A%2F%5C%7B%5Cs*%5BCc%5Dit%5Bae%5D%5B%5E%5C%7D%5D*%5C%7C%5Cs*publication-date%5B%5E%5C%7D%5D*%5C%7C%5Cs*date%2F&title=Special%3ASearch&profile=advanced&fulltext=1&ns0=1 1200]. [[User:Izno|Izno]] ([[User talk:Izno|talk]]) 23:38, 18 September 2026 (UTC) ::If so many articles see a difference between the two fields, why merge them? They obviously serve some purpose in some cases. [[User:Keriluamox|Keriluamox]] ([[User talk:Keriluamox|talk]]) 05:10, 19 September 2026 (UTC) :::The question is wether the 'served purpose' in these cases corresponds with the documented intended use of the field. [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 13:18, 19 September 2026 (UTC) :::{{ec}} :::Not so many, really. As I write this, [[Module:Citation/CS1]] is used on [https://en.wikipedia.org/w/index.php?search=hastemplate%3A%22Module%3ACitation%2FCS1%22&go=Go&ns0=1 5,871,549 articles]. If {{para|date}} and {{para|publication-date}} are used on ~10,500 + ~1,200 = ~11,700 articles, that is {{#expr:(((10500+1200)/5871549)*100) round 3}}%. Not so many in the scheme of things. ::: :::If I understand the sense of all of the various discussions we've had on this topic, multiple 'publication' dates in a single cs1|2 template are not needed to meet the citation's primary purpose: to identify the source that supports the text in an en.wiki article. :::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 13:27, 19 September 2026 (UTC) ::::So publication-date is only used on 1.200 pages? That's not a lot. ::::I wouldn't make date and publication-date aliases of each other. I would just remove publication-date from the template, and have Wikipedia showing a 'undocumented/unsupported/deprecated parameter' error whenever publication-date is used (like with citeseerx parameter currently). Then people can decide for themselves what to do with it. ::::I don't know how this would work out for place and publication-place, but you might be able to do the same there. [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 06:14, 21 September 2026 (UTC) :::: :::::I think that you are mistook. The '1200' number is the number of articles that have cs1|2 templates with both {{para|publication-date}} and {{para|date}} in that order (left to right). The 10,500 number is the number of articles that have cs1|2 templates with both {{para|date}} and {{para|publication-date}} in that order (left to right). ::::: :::::[https://en.wikipedia.org/w/index.php?search=hastemplate%3A%22Module%3ACitation%2FCS1%22+insource%3A%22publication-date%22+insource%3A%2F%5C%7B%5Cs*%5BCc%5Dit%5Bae%5D%5B%5E%5C%7D%5D*%5C%7C%5Cs*publication-date%5Cs*%3D%2F&ns0=1 This search] suggests that there are ~38,400 articles that have cs1|2 templates with {{para|publication-date}} (alone or paired). ::::: :::::For comparison, [https://en.wikipedia.org/w/index.php?search=hastemplate%3A%22Module%3ACitation%2FCS1%22+insource%3A%22date%22+insource%3A%2F%5C%7B%5Cs*%5BCc%5Dit%5Bae%5D%5B%5E%5C%7D%5D*%5C%7C%5Cs*date%5Cs*%3D%2F&ns0=1 this search] (times out) suggests that there are ~1,004,800 articles that have cs1|2 templates with {{para|date}} (alone or paired). ::::: :::::One thing that we've overlooked is {{para|year}} paired with {{para|publication-date}}. So two more searches: :::::*{{para|year}} precedes {{para|publication-date}}: [https://en.wikipedia.org/w/index.php?search=hastemplate%3A%22Module%3ACitation%2FCS1%22+insource%3A%22publication-date%22+insource%3A%2F%5C%7B+*%5BCc%5Dit%5Bae%5D%5B%5E%5C%7D%5D*%5C%7C+*year%5B%5E%5C%7D%5D*%5C%7C+*publication%5C-date%2F&ns0=1 ~9,500 articles] :::::*{{para|year}} follows {{para|publication-date}}: [https://en.wikipedia.org/w/index.php?search=hastemplate%3A%22Module%3ACitation%2FCS1%22+insource%3A%22publication-date%22+insource%3A%2F%5C%7B%5Cs*%5BCc%5Dit%5Bae%5D%5B%5E%5C%7D%5D*%5C%7C%5Cs*publication-date%5B%5E%5C%7D%5D*%5C%7C%5Cs*year%2F&ns0=1 ~1,400 articles] :::::Still not so many... As I write this, [[Module:Citation/CS1]] is used on [https://en.wikipedia.org/w/index.php?search=hastemplate%3A%22Module%3ACitation%2FCS1%22&go=Go&ns0=1 5,872,789 articles]. If {{para|date}} and {{para|publication-date}} are used on ~10,500 + ~1,200 + ~9,500 + ~1,400 = ~22,600 articles, that is {{#expr:(((10500+1200+9500+1400)/5872789)*100) round 3}}%. :::::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 13:36, 21 September 2026 (UTC) ::::::You could turn date into a multi-valued/nested field, and then have date and publication-date indeed be aliases of each other. Then the field date can have multiple values, without specifying the difference between the values, and then date and publication-date will both be values of the same date field. [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 14:16, 21 September 2026 (UTC) :::::::Could, but I don't think that we should. I think that such a mechanism would just cause confusion; especially so when rendering {{tq|multiple values... without specifying the difference between the values}}: ::::::::Author Name (2025, 2026). ''Book Title''. Publisher Name. :::::::And, in cs1|2, a parameter that is an alias of a parameter already in the template is not allowed – {{para|publication-date}} and {{para|publication-place}} violate that rule for little or no benefit. :::::::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 15:41, 21 September 2026 (UTC) ::::::::Is there documentation about how date and publication-date are rendered? [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 15:49, 21 September 2026 (UTC) :::::::::Did you look in the template documentation? [[Template:Cite_book#Date|here]]? and [[Template:Cite_book#Publisher|here]]? And see the '''Live''' examples in the comparisons above. :::::::::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 16:01, 21 September 2026 (UTC) ::::::::::“If date (or year) is not defined, publication-date is displayed as date.” ::::::::::i think this is really confusing. Maybe it should be configured that publication-date can only be used if date is also/already defined [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 16:10, 21 September 2026 (UTC) :::::::::::Yes, it is confusing and it is unnecessary. We don't need two publication dates to identify a source that supports en.wiki article text. When this change goes live, the [[Template:Cite_book#Publisher|{{para|publication-date}} documentation]] will go away and {{para|publication-date}} will be added to the [[Template:Cite_book#Date|{{para|date}} documentation]] as a simple alias of {{para|date}}. :::::::::::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 17:02, 21 September 2026 (UTC) == Cite document, paper, journal, and web == I am confused as to why {{t|cite document}} does not support URL parameters. I have on multiple occasions been caught off guard when attempting to use {{t|cite paper}} and getting a missing {{para|journal}} error thrown at me, as it is currently a redirect to {{t|cite journal}}. ''Paper'' and ''document'' are much closer semantically, so it seems reasonable to expect {{t|cite paper}} to redirect to {{t|cite document}}, but in replacing a call of the former to the latter, I get hit with an unknown parameter {{para|url}} error. Instead, I have to use {{t|cite web}}, which in many cases seems an inappropriate template to use for what I am citing. The particular example that caused me to bring this up here is the following: <syntaxhighlight lang="wikitext"> {{cite web |last=Jones |first=Daniel |author-link=Daniel Jones (phonetician) |year=1956 |title=Cardinal Vowels Spoken by Daniel Jones: Text of Records with Explanatory Notes by Professor Jones |location=London |publisher=Linguaphone Institute |url=https://s3-eu-west-1.amazonaws.com/s3-euw1-ap-pe-ws4-cws-streaming.ri-prod/9781444183092/cardinal.pdf }} </syntaxhighlight> The url is merely a scan of a {{tq|short, stand-alone, offline document}} exactly as described in the documentation of {{t|cite document}}, so the fact that I get an error makes little sense to me. I was going to create an RfD for {{t|cite paper}} to retarget it to {{t|cite document}}, but this is preventing me from doing so. ~ [[User:Oklopfer|<span style="color: #e3308a">oklopfer</span>]] ([[User talk:Oklopfer|💬︎]]) 22:39, 21 August 2026 (UTC) :IIRC the reason for {{-r|Template:Cite paper}} being a redirect to [[Template:Cite journal]] is because for an academic paper to be acceptable for verifiability purposes, it must have been published; and the usual place for academic papers to be published is in an academic journal. --[[User:Redrose64|<span style="color:#a80000; background:#ffeeee; text-decoration:inherit">Red</span>rose64]] &#x1f339; ([[User talk:Redrose64|talk]]) 22:49, 21 August 2026 (UTC) :I agree that cite document should support URLs. An offline document just means a physical document. There's no reason why there can't be online scans/PDFs of them. &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 23:22, 21 August 2026 (UTC) :Sorry but it's clearly not a {{tq|short, stand-alone, offline document}} as it's online. It can't be offline if it has a URL. Cite Document's documentation would clearer if it was "{{tq|short, stand-alone document, that is not available online}}". -- <small>LCU</small> '''[[User:ActivelyDisinterested|A<small>ctively</small>D<small>isinterested</small>]]''' <small>''«[[User talk:ActivelyDisinterested|@]]» °[[Special:Contributions/ActivelyDisinterested|∆t]]°''</small> 11:29, 22 August 2026 (UTC) ::Which it shouldn't be. Cite document should be for any generic document. That something is available online is completely irrelevant. &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 12:18, 22 August 2026 (UTC) :::I could see the argument for that, but that's not how it's currently setup. -- <small>LCU</small> '''[[User:ActivelyDisinterested|A<small>ctively</small>D<small>isinterested</small>]]''' <small>''«[[User talk:ActivelyDisinterested|@]]» °[[Special:Contributions/ActivelyDisinterested|∆t]]°''</small> 12:33, 22 August 2026 (UTC) :::Like {{tl|Citation}} for CS1? You'd probably need broad consensus for that since the other CS1 templates all describe a type of source. I think {{tl|cite document}} was a [https://en.wikipedia.org/w/index.php?title=Template%3ACite_document&diff=1170021118&oldid=1095569050 redirect] to {{tl|cite journal}} prior to this discussion: {{format link|Help_talk:Citation_Style_1/Archive_81#"Cite_document"_needs_its_own_template._Redirecting_to_cite_journal_is_illogical_and_unfriendly.}} [[User:Rjjiii|<span style="font-variant:small-caps;">Rjj<sup>iii</sup></span>]] ([[User talk:Rjjiii|talk]]) 15:38, 22 August 2026 (UTC) ::::Ah, that helps to explain the incongruence of {{t|cite paper}} and {{t|cite document}}, then. ~ [[User:Oklopfer|<span style="color: #e3308a">oklopfer</span>]] ([[User talk:Oklopfer|💬︎]]) 18:37, 22 August 2026 (UTC) ::In my opinion, a "document" is a [[pamphlet]], a small version of book, so we should be able to use all parameters of {{tl|cite book}} other than {{para|chapter}} and related params. --[[User:FlatLanguage|FlatLanguage]] ([[User talk:FlatLanguage|talk]]) 02:09, 26 August 2026 (UTC) :Cite document is specifically provided to support URL-less lesser works that appear in no other greater works. That is the point of the template. [[User:Izno|Izno]] ([[User talk:Izno|talk]]) 21:51, 31 August 2026 (UTC) ::And if a digitized version of that document suddenly appears, it doesn't cease to be a document. URL should be supported. &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 15:10, 19 September 2026 (UTC) == Speedy deletion for citeseerx CS1 error category? == Is [[:Category:CS1 errors: citeseerx]] still being used in some fashion? Since all instances of citeseerx are now a [[:Category:CS1 errors: deprecated parameters|deprecated parameter]] error anyway, I don't see any use for this anymore. I would flag it as [[Wikipedia:C4|C4]] for speedy deletion but I want confirmation that this isn't being used anywhere else before proceeding. [[User:BlaqWiedow|BlaqWiedow]] ([[User talk:BlaqWiedow|talk]]) 16:24, 14 September 2026 (UTC) :{{para|citeseerx}} is deprecated but still supported. {{cl|CS1 errors: citeseerx}} will be deleted when support for {{para|citeseerx}} is withdrawn. Don't hold your breath for that to happen soon. :—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 16:30, 14 September 2026 (UTC) == "always include ISBN, if one has been assigned" == This is appalling advice. The utility of littering pages with visually distracting ISBN links to nowhere would be moot even if the ISBNs were correct. Because many Wiki editors do not understand that an ISBN identifies an edition rather than a work, thousands of the ISBNs on the site are wrong. Editors should be advised to consider what purpose an ISBN serves, and, if they decide to include one, to ensure that it is '''the right ISBN for the edition cited'''. (The field is so pointless and troublesome that it would be better to remove it from the template completely.) [[User:Utilisateur19911|Utilisateur19911]] ([[User talk:Utilisateur19911|talk]]) 08:04, 15 September 2026 (UTC) :Yes, the ISBN must be correct for the edition. While that is ''an'' issue, it is a fairly minor one and certainly does not make "the field so pointless and troublesome that it would be better to remove from the template completely". &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 13:14, 15 September 2026 (UTC) ::ISBN is incredibly useful when trying to hunt down the correct work, especially for something obscure. Updating the documentation to advice on ensuring the correct ISBN is used can be done by anyone. -- <small>LCU</small> '''[[User:ActivelyDisinterested|A<small>ctively</small>D<small>isinterested</small>]]''' <small>''«[[User talk:ActivelyDisinterested|@]]» °[[Special:Contributions/ActivelyDisinterested|∆t]]°''</small> 14:02, 15 September 2026 (UTC) :::{{+1}} on updating documentation. '''[[User:Icepinner|Icepinner]]''' ([[User talk:Icepinner|Come to Hakurei Shrine!]]) 16:27, 17 September 2026 (UTC) == Please update SC2ID limit == In this [[Köthe conjecture]] page, one of the sources used a journal with SC2ID more than 290000000 which is 291870068 (and it is the right journal). Please update the limit. [[User:Lowyat Slyder|Lowyat Slyder]] ([[User talk:Lowyat Slyder|talk]]) 16:02, 17 September 2026 (UTC) == Listing a committee == The documentation for 'author1' says "this parameter is used to hold the name of an organizational author (e.g. a committee)", but using it for that purpose generates an error. As an example: : {{Cite book | title=Review and Assessment of Planetary Protection Policy Development Processes | author1=Committee on the Review of Planetary Protection Policy Development Processes | author2=Space Studies Board | author3=Division on Engineering and Physical Sciences | author4=National Academies of Sciences, Engineering, and Medicine | date=September 17, 2018 | publisher=National Academies Press | isbn=978-0-309-47865-6 | location=Washington, D.C. | doi=10.17226/25172 | url=https://www.nationalacademies.org/publications/25172}} Does the documentation need to be revised? [[User:Praemonitus|Praemonitus]] ([[User talk:Praemonitus|talk]]) 15:43, 18 September 2026 (UTC) :Use {{para|author''n''|((Committee on the Review of ...))}} &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 18:19, 18 September 2026 (UTC) :: I'm aware of the work-around, thanks. My question was regarding the documentation. [[User:Praemonitus|Praemonitus]] ([[User talk:Praemonitus|talk]]) 20:22, 18 September 2026 (UTC) ::{{re|Praemonitus}} Your citation got flagged by [[Module:Citation/CS1/Configuration]] because it contains the word "policy". I have [[Special:Diff/1376078963|edited the documentation for this error]] to be a little more informative. I'm not sure what led to that particular pattern being added, but I wonder if it was related to [[privacy policy]]. ::I think the current set of patterns is overzealous and produces too many [[false positive]]s. I propose removing at least "policy" and "bureau" as relatively common organizational names that are likely appropriate collective authors. ::My efforts to craft a [https://en.wikipedia.org/w/index.php?title=Special%3ASearch&ns0=1&fulltext=Search&search=insource%3A%2F|\s*author\d%3F\s*%3D%5B%5E%7C%7B%7D%5D*policy%2F regular expression to review existing uses] are timing out. Perhaps someone here knows a better way to query. [[User:Daask|Daask]] ([[User talk:Daask|talk]]) 18:01, 26 September 2026 (UTC) :::Here's a better one [https://en.wikipedia.org/w/index.php?search=insource%3A%2F%5C%7C%5Cs*%28author%7Clast%29-%3F%5Cd%3F%5Cs*%3D%5Cs*%5B%5E%5C%7C%5C%7D%5D*policy%2Fi&title=Special%3ASearch&profile=advanced&fulltext=1&ns0=1] &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 18:16, 26 September 2026 (UTC) ::: Thanks. [[User:Praemonitus|Praemonitus]] ([[User talk:Praemonitus|talk]]) 18:43, 26 September 2026 (UTC) {{edit fully-protected|Module:Citation/CS1/Configuration|answered=yes}} Please remove the lines containing '^[Bb]ureau$' and 'policy', due to excessive false positives as described above. [[User:Daask|Daask]] ([[User talk:Daask|talk]]) 15:09, 29 September 2026 (UTC) :Not done. When we constrain the searches to just those uses that trigger the error messaging, there aren't really that many: ::[https://en.wikipedia.org/w/index.php?search=incategory%3A%22CS1+errors%3A+generic+name%22+insource%3A%2F%5C%7C%5Cs*%28author%7Clast%29-%3F%5Cd%3F%5Cs*%3D%5Cs*%5B%5E%5C%7C%5C%7D%5D*policy%2Fi&ns0=1 'contains 'policy': ~260 articles] ::[https://en.wikipedia.org/w/index.php?ns0=1&search=incategory%3A%22CS1+errors%3A+generic+name%22+insource%3A%2F%5C%7C%5Cs*%28author%7Clast%29-%3F%5Cd%3F%5Cs*%3D%5Cs*%5BBb%5Dureau%5Cs*%5B%5C%7C%5C%7D%5D%2Fi is 'Bureau' or 'bureau': ~510 articles] :—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 23:55, 4 October 2026 (UTC) ::{{re|Trappist the monk}} My review of the citations found in your search query for "policy" indicates that the author is accurate in the overwhelming majority of these citations (although many are split into last= and first= inappropriately). Why are we flagging these as errors? I understand that these queries are only causing false positives for some hundreds or perhaps thousands of citations (including those using accept-as-written markup), which you find trivial. Yet this still appears to be significantly more than the number of true positives they are finding. This thread indicates that flagging false positives is causing editor confusion, and it isn't obvious to me why showing an error message on the rare and obviously-wrong author of "Policy, Privacy" is worth the trouble. ::I'm happy to withdraw my request regarding <code>^[Bb]ureau$</code>, because it is anchored to the beginning and ending of the author name. Perhaps we could do the same and replace this with <code>^[Pp]olicy$</code> ? [[User:Daask|Daask]] ([[User talk:Daask|talk]]) 16:05, 5 October 2026 (UTC) == Foreign-language journal with separate URLs for original article and third-party translation == I have a {{tl|cite journal}} for an article that's in French. It's fairly old (no DOI or other modern identifier) but there is an electronic scan available. That means I need to use {{para|url}} to link it. There is also an English translation available for the whole article. How do I also link that as well? I'm currently using an extlink in {{para|trans-title}}, but that's obviously a CS1 error. [[User:DMacks|DMacks]] ([[User talk:DMacks|talk]]) 10:31, 20 September 2026 (UTC) :You include the secondary URL outside of the template, but before the close ref tags. -- <small>LCU</small> '''[[User:ActivelyDisinterested|A<small>ctively</small>D<small>isinterested</small>]]''' <small>''«[[User talk:ActivelyDisinterested|@]]» °[[Special:Contributions/ActivelyDisinterested|∆t]]°''</small> 13:55, 20 September 2026 (UTC) ::or write a separate cs1|2 template for the translation; especially if the bibliographic details or the translation differ from those of the translated source. ::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 14:11, 20 September 2026 (UTC) :::Thank you both. [[User:DMacks|DMacks]] ([[User talk:DMacks|talk]]) 17:15, 20 September 2026 (UTC) == Generic author name "Staff" == Propose that "Staff" and variations such as "[Name of Publication] Staff" and "Staff Writer[s]" be added to the [[Help:CS1 errors#Cite uses generic name|list of generic names]] for <code>|author=</code> and similar fields. These turn up a lot in various online publications. Thank you. <span class="nowrap">~[[User:Sangdeboeuf|Sangdeboeuf]]</span> ([[User talk:Sangdeboeuf|talk]]) 14:04, 20 September 2026 (UTC) * [[Staff (name)]] is a viable surname - this will create false positives - for example for books like {{cite book |last = Staff |first = Gary |title = German Battlecruisers of World War One: Their Design, Construction and Operations |publisher = Seaforth Publishing |location = Oxford |date = 2014 |isbn = 978-1-84832-308-7|ref=none}}[[User:Nigel Ish|Nigel Ish]] ([[User talk:Nigel Ish|talk]]) 14:06, 20 September 2026 (UTC) *:OK, I wasn't aware of that. <span class="nowrap">~[[User:Sangdeboeuf|Sangdeboeuf]]</span> ([[User talk:Sangdeboeuf|talk]]) 01:05, 21 September 2026 (UTC) * I find the use of these terms reassures readers and editors that the author hasn't been omitted or forgotten, so I think they're useful. -- [[User:Michael Bednarek|Michael Bednarek]] ([[User talk:Michael Bednarek|talk]]) 15:25, 20 September 2026 (UTC) == |location=, |place=, and |publication-place= == Because of their similar peculiarities, {{para|location}}, {{para|place}}, and {{para|publication-place}} are often mentioned when we have been discussing {{para|date}} and {{para|publication-date}}; most recently at [[Help talk:Citation Style 1#Cite book: Year of publication]]. When used in isolation, {{para|publication-date}} is an equal alias of {{para|location}} and {{para|place}}. When {{para|publication-date}} is paired with either of {{para|location}} or {{para|place}}, the latter parameter causes cs1|2 to emit 'written at' static text. My sense from our previous discussions is that where a source was written is not needed when the purpose of a citation is to identify the source that supports text in an en.wiki article. So, I have hacked the module sandboxen to make {{para|location}}, {{para|place}}, and {{para|publication-place}} equal aliases at all times. Since December 2019, we have maintained a properties category {{cl|CS1 location test}} which accumulates articles that have cs1|2 templates with {{para|publication-place}} and either of {{para|location}} or {{para|place}}. At this writing, the category lists ~1,800 articles. When used in isolation, {{para|location}}, {{para|place}}, and {{para|publication-place}} have been and will remain equal aliases of each other: <div style="margin-left:1.6em">{{cite compare |template=citation |title=Title |location=Austin, Texas |newspaper=The Villager}}</div> <div style="margin-left:1.6em">{{cite compare |template=citation |title=Title |place=Manhattan |newspaper=The Villager}}</div> <div style="margin-left:1.6em">{{cite compare |template=citation |title=Title |publication-place=The Woodlands, Texas |newspaper=The Villager}}</div> When {{para|publication-place}} is paired with either of {{para|location}} or {{para|place}}, the 'written at' static text will no longer be rendered and [[Module:Citation/CS1]] will render a duplicate parameter error message: <div style="margin-left:1.6em">{{cite compare |template=citation |title=Title |publication-place=Manhattan |location=London |newspaper=The Villager}}</div> <div style="margin-left:1.6em">{{cite compare |template=citation |title=Title |publication-place=Manhattan |place=London |newspaper=The Villager}}</div> <div style="margin-left:1.6em">{{cite compare |template=citation |title=Title |publication-place=Manhattan |location=Manhattan |newspaper=The Villager}}</div> Module:Citation/CS1 will no longer link to {{cl|CS1 location test}}. The category will automatically empty at which point it may be deleted. Keep? Discard? —[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 14:09, 21 September 2026 (UTC) :Looking at an example, we currently have in [[...Lu]] :*<pre>{{cite book|last=Hinz|first=W.|translator-last=Barnes|translator-first=J.|year=1972|title=The Lost World of Elam: Re-creation of a Vanished Civilization|url=https://books.google.com/books?id=DGkKAQAAIAAJ|location=United Kingdom|publisher=[[Sidgwick & Jackson]]|publication-place=University of California|isbn=9780283978630}}</pre> :rendering as :*{{cite book|last=Hinz|first=W.|translator-last=Barnes|translator-first=J.|year=1972|title=The Lost World of Elam: Re-creation of a Vanished Civilization|url=https://books.google.com/books?id=DGkKAQAAIAAJ|location=United Kingdom|publisher=[[Sidgwick & Jackson]]|publication-place=University of California|isbn=9780283978630}} :This is clearly nonsense. No one cares that Hinz wrote it in the UK (which is an [https://de-wikipedia-org.translate.goog/wiki/Walther_Hinz?_x_tr_sl=fr&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=wapp extremely dubious proposition] given he spent the vast majority of his academic life in Germany and Iran and probably never even sat foot in the UK), or that Barnes translated it in California. The only thing that bibliographically matters is what is the location of [https://books.google.com/books?id=DGkKAQAAIAAJ Sidgwick & Jackson, which here is UK (London)], or [https://books.google.ca/books?redir_esc=y&id=DGkKAQAAIAAJ&focus=searchwithinvolume&q=New+York+University NYU Press (New York)]. :So the category is useful to find the nonsense. But if another category exists... *shrugs*. &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 15:40, 21 September 2026 (UTC) ::We do have another category: {{cl|CS1 errors: redundant parameter}} and we will have visible error messages so the properties category {{cl|CS1 location test}} (properties cats are not associated with a visible messaging) becomes redundant. ::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 15:53, 21 September 2026 (UTC) == Citing YouTube == Please direct me to somewhere that can teach me how to cite YouTube. (I've been editing for 20 years, and I've never cited YouTube.) Tried using {{tl|Cite YouTube}} but this redirects to {{tl|Cite AV Media}} which doesn't seem to have the parameters I need. I'm sure someone has worked this out. Where do I go? This is the URL: [https://www.youtube.com/watch?v=jrK3PsD3APk]. I want to mention the interviewee (Hinton), the interviewer (Jon Stewart), the channel, (The Weekly Show with Jon Stewart), the time-stamp of the thing I'm citing and the website (YouTube). ---- [[User:CharlesTGillingham|CharlesTGillingham]] ([[User talk:CharlesTGillingham|talk]]) 19:41, 21 September 2026 (UTC) :Here is one way (assuming that the timestamp is at the 30 minute mark): ::<syntaxhighlight lang="wikitext" inline="1">{{cite av media |subject=Geoffrey Hinton |interviewer=Jon Stewart |title=AI: What Could Go Wrong? with Geoffrey Hinton |time=0:30 |publisher=The Weekly Show with Jon Stewart |url=https://www.youtube.com/watch?v=jrK3PsD3AP |via=YouTube}}</syntaxhighlight> :::{{cite av media |subject=Geoffrey Hinton |interviewer=Jon Stewart |title=AI: What Could Go Wrong? with Geoffrey Hinton |time=0:30 |publisher=The Weekly Show with Jon Stewart |url=https://www.youtube.com/watch?v=jrK3PsD3AP |via=YouTube}} :You can also use {{para|minutes|30}} for a slightly different rendering: ::<syntaxhighlight lang="wikitext" inline="1">{{cite av media |subject=Geoffrey Hinton |interviewer=Jon Stewart |title=AI: What Could Go Wrong? with Geoffrey Hinton |minutes=30 |publisher=The Weekly Show with Jon Stewart |url=https://www.youtube.com/watch?v=jrK3PsD3AP |via=YouTube}}</syntaxhighlight> :::{{cite av media |subject=Geoffrey Hinton |interviewer=Jon Stewart |chapter=AI: What Could Go Wrong? with Geoffrey Hinton |minutes=30 |title=The Weekly Show with Jon Stewart |chapter-url=https://www.youtube.com/watch?v=jrK3PsD3AP |via=YouTube}} :—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 19:54, 21 September 2026 (UTC) ::::<pre>{{cite av media |subject=Geoffrey Hinton |interviewer=Jon Stewart |chapter=AI: What Could Go Wrong? with Geoffrey Hinton |minutes=30 |title=The Weekly Show with Jon Stewart |chapter-url=https://www.youtube.com/watch?v=jrK3PsD3AP |via=YouTube}}</pre> rendering as ::::*{{cite av media |subject=Geoffrey Hinton |interviewer=Jon Stewart |chapter=AI: What Could Go Wrong? with Geoffrey Hinton |minutes=30 |title=The Weekly Show with Jon Stewart |chapter-url=https://www.youtube.com/watch?v=jrK3PsD3AP |via=YouTube}} ::::seems better to me. Parameter names could be better though, but this correctly put things as minor/major works and doesn't wrongly state that the Weekly Show is a publisher. &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 03:53, 22 September 2026 (UTC) :::Thanks, much appreciated. This citation is in [[artificial intelligence]] ---- [[User:CharlesTGillingham|CharlesTGillingham]] ([[User talk:CharlesTGillingham|talk]]) 03:42, 22 September 2026 (UTC) == Request for language override: Tetun language == [[Tetum language]] has been [https://en.wikipedia.org/w/index.php?curid=66305487#Requested_move_1_March_2026 moved] to [[Tetun language]]. [[Module:ISO 639 name/ISO 639-3]] still shows "Tetum" (with an "m"), because [https://iso639-3.sil.org/code/tet sil still shows "Tetum"] (and Ethnologue shows "Tetun"). It looks like we need an override for "tet" at [[Module:Citation/CS1/Configuration]]. – [[User:Jonesey95|Jonesey95]] ([[User talk:Jonesey95|talk]]) 14:34, 23 September 2026 (UTC) :In the sandbox: <div style="margin-left:3.2em>{{cite compare |template=book |title=Title |language=tet}} {{cite compare |template=book |title=Title |language=tetum}} {{cite compare |template=book |title=Title |language=tetun}}</div> :—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 15:44, 23 September 2026 (UTC) :If anyone is interested in the reasoning, the original discussion is at [[Talk:Tetun#Requested move 1 March 2026]]. It boils down to a quirk of Portuguese spelling. <span class="nowrap">[[User:ChompyTheGogoat|<span style="font-weight: bold; color:#BB6BD1">ChompyTheGogoat</span>]]&nbsp;[&nbsp;[[User talk:ChompyTheGogoat|<span style="color:#D72D85">Bleat</span>]]&nbsp;&#124;&nbsp;[[Special:Contributions/ChompyTheGogoat|<span style="color: #2da86c;">Munched</span>]]&nbsp;]</span> 15:51, 23 September 2026 (UTC) == Typo in the description of template [[Template:Cite journal]] == In the description of the <code>journal</code> option in the template [[Template:Cite journal]] there is (what I believe to be) a typo. The example reads "<nowiki>[[Nature (journal)|]]</nowiki>" instead of "<nowiki>[[Nature (journal)]]</nowiki>" (note the additional bar). [[Wikipedia:Wiki_Workers_United_solidarity|In solidarity with Wiki Workers United]], [[User:Zvavybir|zvavybir]] ([[User talk:Zvavybir|talk]]) 21:43, 26 September 2026 (UTC) :That is the result of [[Special:Diff/1366631846|this edit]] by Editor [[User:Cremastra|Cremastra]] ostensibly to {{tq|[allow] us to demonstrate the use of the pipe trick in the example}} like this: ::<syntaxhighlight lang="wikitext" inline="1">{{cite journal |title=Title |journal=[[Nature (journal)|]]}}</syntaxhighlight> :::{{cite journal |title=Title |journal=[[Nature (journal)|Nature]]}} :But, the pipe trick does not work in {{tag|ref}} tags: ::<syntaxhighlight lang="wikitext" inline="1"><ref>{{cite journal |title=Title |journal=[[Nature (journal)|]]}}</ref></syntaxhighlight><ref>{{cite journal |title=Title |journal=[[Nature (journal)|]]}}</ref> <div style="margin-left:4.8em">{{reflist talk}}</div> :Feel free to fix it. :—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 22:01, 26 September 2026 (UTC) == [[Template:Cite journal|Cite journal]] deprecated <code>|citeseerx=</code>: rationale and migration path? == I'm encountering warnings for a deprecated <code>|citeseerx=</code> parameter, for example, on [[Minority interpretations of quantum mechanics#cite_note-27|this citation]]. However, it's not clear from the template documentation precisely ''why'' the parameter is deprecated, or how to eliminate this warning by migrating to features with ongoing support. These warrant an explanation in the obvious place editors will look to resolve the warning. [[User:EnronEvolved|EnronEvolved]]<sup>[[User talk:EnronEvolved|My Talk Page]]</sup> 14:29, 2 October 2026 (UTC) :This parameter is deprecated. See [[Help_talk:Citation_Style_1/Archive_102#deprecate %7Cciteseerx= ?|discussion]].––[[User:KEmel49|<span style="color: #000099; font-weight: bold; font-family: Georgia;">KE</span>mel<span style="color: red;">49</span>]]([[User talk:KEmel49|📝]],[[Special:Contributions/KEmel49|📋]]) 15:13, 2 October 2026 (UTC) == Update bibcode URL to SciX == ADS is scheduled to be shutdown on 16 November 2026. It's replacement, SciX, has been available for some time. See {{slink|Template talk:Bibcode#ADS to SciX migration}} for details. {{edit request|Module:Citation/CS1/Configuration|level=full|answered=yes}} In [[Module:Citation/CS1/Configuration]], please replace the line: <syntaxhighlight>prefix = 'https://ui.adsabs.harvard.edu/abs/',</syntaxhighlight> with <syntaxhighlight> prefix = 'https://scixplorer.org/abs/', suffix = '/abstract', </syntaxhighlight> [[User:Daask|Daask]] ([[User talk:Daask|talk]]) 17:30, 5 October 2026 (UTC) :This should be done in the sandbox, and deployed with the rest of the changes. So long as it's live before Nov 16th or so. &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 19:26, 5 October 2026 (UTC) ::{{donetask}} Implemented in sandbox in [[Special:Diff/1378836392|Diff/1378836392]]. [[User:Daask|Daask]] ([[User talk:Daask|talk]]) 11:37, 6 October 2026 (UTC) :::You should always provide evidence that the changes you make actually work. <div style="margin-left:6.4em">{{cite compare |template=book |title=Keck Speckle Imaging of the White Dwarf G29-38: No Brown Dwarf Companion Detected |bibcode=1998ApJ...508L..81K}}</div> :::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 14:32, 7 October 2026 (UTC) == Cite sign - content only, or also things like location? == Hi all, Is {{tl|Cite Sign}} supposed to be used only for, say, the text of a sign, or can it also be used for things like the specific location of a sign? Say if a construction plaque or gravestone was moved, even if the text was the same, would that be within the scope or not? Or could a sign's presence or lack thereof be used, e.g. if a builder's plate on an object went missing at some point, and that fact was somehow relevant to an article about falsified or altered products or devices etc? (I'm aiming for a generalised guideline, but the specific example that got me thinking about this is for two very similar railway wagon types; the easiest way to differentiate between them is whether the builder's plate is centred or at one end of the wagon (and that can be established separately from [[WP:RS]]'s). So I'd be "referencing" both types of sign, but based on the location not the content.) [[User:Anothersignalman|Anothersignalman]] ([[User talk:Anothersignalman|talk]]) 15:16, 6 October 2026 (UTC) == "Verifying your browser" should be a generic title == Seen at [[Special:Diff/1378865138]] [[User:Pppery|* Pppery *]] [[User talk:Pppery|<sub style="color:#800000">it has begun...</sub>]] 16:12, 6 October 2026 (UTC) bk01bild65jgjldyv5otraje24eo87p 736719 736718 2026-10-07T14:40:42Z King ChristLike 13051 1 revision imported from [[:en:Help_talk:Citation_Style_1]] 736718 wikitext text/x-wiki <!-- Deny citation bot April 2015 because we often post broken citations here intentionally and do not want them to be "fixed". To avoid AnomieBOT substing, use |demo= or |nosubst= instead of adding it here. -->{{bots|deny=Citation bot,SporkBot,Cewbot}}<!-- -->{{skip to bottom}}<!-- -->{{talk header|display_title=Help:Citation Style 1 and the CS1 templates|WT:CS1}} {{central|text=the talk pages for all Citation Style 1 and Citation Style 2 templates and modules redirect here. A list of those talk pages and their historical archives can be found [[Help talk:Citation Style 1/Centralized discussions|here]].}} {{WikiProject banner shell|collapsed=yes|1= {{Wikipedia Help Project|importance=High}} {{WikiProject Academic Journals}} {{WikiProject Magazines}} }} {{User:ClueBot III/ArchiveThis |archiveprefix=Help talk:Citation Style 1/Archive |format= %%i |age=480 |header={{Automatic archive navigator}} |headerlevel=2 |maxarchsize=200000 |minkeepthreads=6 |numberstart=69 |minarchthreads=2 |archivenow=<nowiki>{{User:ClueBot III/ArchiveNow}},{{resolved}},{{done}}</nowiki> }} {{FAQ|page=Help talk:Citation Style 1/FAQ}} ==Cite book: Year of publication== Year of publication states "Year of the source being referenced" Shouldn't this be "Year of source"/"Year of writing" or something like this? Publication date seems to already be used for date when something is published...I think cite book should be clearer about which fields are referring to Publication, and which fields are referring to Writing [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 07:36, 15 July 2026 (UTC) :I've never understood why {{para|publication-date}} exists, {{para|date}} should be used for publication date and {{para|orig-date}} for original date. It seems overly complex to have a third field that needlessly complicates things. -- <small>LCU</small> '''[[User:ActivelyDisinterested|A<small>ctively</small>D<small>isinterested</small>]]''' <small>''«[[User talk:ActivelyDisinterested|@]]» °[[Special:Contributions/ActivelyDisinterested|∆t]]°''</small> 12:56, 15 July 2026 (UTC) ::Since at least April 2020, I have believed that {{para|publication-date}} should go away ([[Help_talk:Citation_Style_1/Archive_65#c-Trappist_the_monk-2020-04-05T21:59:00.000Z-Francis_Schonken-2020-04-06T10:07:00.000Z|here]]). Similarly, I hold that {{para|publication-place}} should go away. There have been several discussions on this topic which are collected at {{slink|Help_talk:Citation_Style_1/Archive_86#place,_when_publication-place_is_redundant_with_work}}. ::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 14:04, 15 July 2026 (UTC) :::Agree, both simply confuse the matter and are redundant. -- <small>LCU</small> '''[[User:ActivelyDisinterested|A<small>ctively</small>D<small>isinterested</small>]]''' <small>''«[[User talk:ActivelyDisinterested|@]]» °[[Special:Contributions/ActivelyDisinterested|∆t]]°''</small> 15:24, 15 July 2026 (UTC) ::Can it not be useful if there are several editions or versions of a work? {{para|date}} for the year of the edition quoted, {{para|orig-date}} for the 1st edition, {{para|publication-date}} for the publication date if it is a later re-edition, publication in another series etc. [[User:Keriluamox|Keriluamox]] ([[User talk:Keriluamox|talk]]) 16:51, 15 July 2026 (UTC) :::References exist for verification, you only need to give details of the work you have not it's publication history. -- <small>LCU</small> '''[[User:ActivelyDisinterested|A<small>ctively</small>D<small>isinterested</small>]]''' <small>''«[[User talk:ActivelyDisinterested|@]]» °[[Special:Contributions/ActivelyDisinterested|∆t]]°''</small> 17:15, 15 July 2026 (UTC) ::::Taking that argument to the extreme, the sole ISBN would suffice. I find it useful to give ''some'' information about the work. Dating a 1900 work from 2020 because that’s the edition used feels off, if not slightly misleading. [[User:Keriluamox|Keriluamox]] ([[User talk:Keriluamox|talk]]) 06:49, 16 July 2026 (UTC) :::::The date is the date of the edition you are using. If the version from 2020 is a facsimile of the 1900 edition, you could cite it as 1900. Otherwise, if it's a new edition it will have new page numbers, etc. –[[user:jacobolus|jacobolus]] [[user_talk:jacobolus|(t)]] 17:48, 30 July 2026 (UTC) ::Take [[Crime and Punishment]] or many other books from around that time. They single volume is different than when the installment was published. More so light novels which are often written in installments on a website, then bought and printed by a publisher. Given that many books take time to publish, especially anthologies, having all three are useful. date is for the creation, orig-date is for when it was originally released, and publication-date is for when this exact publication was made. [[User:Jerodlycett|Jerod Lycett]] ([[User talk:Jerodlycett|talk]]) 06:30, 21 July 2026 (UTC) :::Wouldn't it then make sense to rename 'date' to 'creation-date'? [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 07:56, 30 July 2026 (UTC) ::::The use of {{para|publication-date}} is quite rare, in most cases {{para|date}} is used for current date and {{para|orig-date}} for the original publication date. So it wouldn't make sense to change {{para|date}}. -- <small>LCU</small> '''[[User:ActivelyDisinterested|A<small>ctively</small>D<small>isinterested</small>]]''' <small>''«[[User talk:ActivelyDisinterested|@]]» °[[Special:Contributions/ActivelyDisinterested|∆t]]°''</small> 14:22, 30 July 2026 (UTC) :This is about the <code>&lt;skeptical air quotes></code>documentation<code>&lt;/skeptical air quotes></code> at {{slink|Template:Cite_book#TemplateData}}? The template's actual documentation for {{para|publication-date}} is at {{slink|Template:Cite_book#Date}}. The template data are not protected so if you think that it can be improved, please improve it. :—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 14:04, 15 July 2026 (UTC) ::It's actually at [[Template:Cite book#Publisher]], or more specifically, [[Template:Cite book#csdoc_publication-date]]. --[[User:Redrose64|<span style="color:#a80000; background:#ffeeee; text-decoration:inherit">Red</span>rose64]] &#x1f339; ([[User talk:Redrose64|talk]]) 21:31, 15 July 2026 (UTC) ::{{replyto|ActivelyDisinterested}} {{para|publication-date}} is mainly for non-daily periodicals where the cover date is often later than the date when the periodical goes on sale. For example, a magazine with cover date August 2026 might be on sale already. --[[User:Redrose64|<span style="color:#a80000; background:#ffeeee; text-decoration:inherit">Red</span>rose64]] &#x1f339; ([[User talk:Redrose64|talk]]) 21:01, 15 July 2026 (UTC) :::In taxonomy, the date when a book or journal was first published can be very important to establish precedence. For various reasons the year/date on the title page is not always the year/date when the work was first distributed. In such cases I use date= for the date on the title page and publication-date= for the date when the work was first distributed. - [[User:Aa77zz|Aa77zz]] ([[User talk:Aa77zz|talk]]) 21:23, 15 July 2026 (UTC) ::::How do you know when it was first distributed? [[User:JMF|𝕁𝕄𝔽]] ([[User talk:JMF|talk]]) 22:05, 15 July 2026 (UTC) ::::Date/publication-date are exactly the same thing. If you want the original date use {{para|orig-date}}. &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 16:04, 30 July 2026 (UTC) :::::This is also what I thought, when looking at the documentation ([[Template:Cite book#TemplateData]]): :::::parameter 'date' = 'Date of publication' :::::parameter 'publication-date' = 'Publication date' :::::To me, this looks exactly the same. :::::Given that other people have already expressed that 'publication-date' should go away, I'm just not gonna use 'publication-date' anymore (I don't care this much about dates of book publishing), and try to put the info I have in the fields 'date' and 'orig-date'. Thanks for clearing this up. [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 16:57, 30 July 2026 (UTC) :::::{{ec}} :::::Just to be pedantic, {{para|date}} and {{para|publication-date}} are {{em|only}} {{tq|exactly the same thing}} when they are used alone. Then both are used in the same template they are treated as the same thing when they hold the same value in which case, {{para|publication-date}} is ignored: ::::::<syntaxhighlight lang="wikitext" inline="1">{{cite book |title=Title |date=2026 |publication-date=2026}}</syntaxhighlight> → {{cite book |title=Title |date=2026 |publication-date=2026}} :::::when {{para|date}} and {{para|publication-date}} hold different values: ::::::<syntaxhighlight lang="wikitext" inline="1">{{cite book |title=Title |date=2026 |publication-date=2025}}</syntaxhighlight> → {{cite book |title=Title |date=2026 |publication-date=2025}} :::::Do we really, {{em|really}}, need both? I think that we don't and that we should make {{para|date}} and {{para|publication-date}} exact aliases of one another {{small|({{para|location}} / {{para|place}} and {{para|publication-place}} should also be exact aliases of one another)}}. :::::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 17:12, 30 July 2026 (UTC) ::::::+1 support for that. &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 17:38, 30 July 2026 (UTC) ::::::I agree 'date' and 'publication-date' should be aliases of each other [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 14:27, 3 August 2026 (UTC) ::::::As for <code>location</code>/<code>place</code> and <code>publication-place</code>, that's what I came here for.<br/> ::::::The [[Template:Cite_book/doc]] is quite complex, probably contradictory… <br/> ::::::But in [[Template:Cite_book/doc#Publisher|#Publisher]] it says "Place: In earlier versions was the publication place; for compatibility will be treated as such if publication-place is absent"<br/> ::::::So aliasing those will be OK for older{{when?}} entries, but possibly not for newer; could we count{{how many?}} newer with both present? :::::::So paralleling with <code>date</code> and <code>publication-date</code>, which I suppose would have been introduced at the same time, how much will it fudge? ::::::[[User:Ponken|Ponken]] ([[User talk:Ponken|talk]]) 09:02, 19 August 2026 (UTC) :::::::I like the idea of creation-date. Isn't the template not all about this? :::::::"Title (published 2025). 2026" - is just not clearly understandable, instead rather a wtf (the postscript would be place for such curiosities when they are specifically relevant). :::::::Sorry, if the discussion here is already closed. I just saw now how long the page goes down, wow. (There I will ask a question, for which I am here.) [[User:MenkinAlRire|MenkinAlRire]] 14:10, 31 August 2026 (UTC) ::::::::"Isn't the template not all about this?" I don't think so. The template, and citations in academic works generally, are about identifying the publication that is mentioned in the citing work. If the source says "July 2026" on the cover, that's what someone who wants to read the source will check to make sure they picked up the right issue of the magazine. If some Wikipedian in the magazine business happens to know it was printed April 15, 2026, and first offered for sale May 2, 2026, WE DON'T CARE! [[User:Jc3s5h|Jc3s5h]] ([[User talk:Jc3s5h|talk]]) 14:33, 31 August 2026 (UTC) :::::::::That wasn't my point (that I find irrelevant, too). The template is called speech, and there are several date one could consider: when it was written (there is only a ''location'' for this which translates to "written at"), when the speech was held, and when the text was published (better printed). With "all about this" I meant that a speech was once spoken, I guess, and that is its prime date. Historically, in many, if not the most cases, the impact of a speech came with its distribution in print. But today many lectcures ar recorded and published online. They are preserved as original oral documents as video or audio. So the event where the speech happened gains more importance versus its printed form (if there is one). (Below I discussed some points.) [[User:MenkinAlRire|MenkinAlRire]] 15:54, 31 August 2026 (UTC) ::::::::::"The template is called speech" – You should be aware that this talk-page serves as the talk-page of several templates which use *this* (sub-)template "Citation Style 1". That is: if you click these templates' talk-page link, you end up here. ''edit'' ALSO you are in the thread [[#Cite_book:_Year_of_publication]] here. / [[User:Ponken|Ponken]] ([[User talk:Ponken|talk]]) 09:46, 1 September 2026 (UTC) :::::::::::I also don’t get why this one talk page serves for several templates, instead of each template just having it’s own talk page [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 09:54, 1 September 2026 (UTC) :I have hacked the module sandboxen to make {{para|date}} and {{para|publication-date}} exact aliases. When used alone, {{para|date}} and {{para|publication-date}} have always performed the same function: <div style="margin-left:3.2em>{{cite compare |template=book |title=Title |date=2026}} {{cite compare |template=book |title=Title |publication-date=2026}}</div> :When paired and holding the same dates, {{para|publication-date}} was ignored <div style="margin-left:3.2em>{{cite compare |template=book |title=Title |date=2026 |publication-date=2026}}</div> :When paired with different dates, {{para|publication-date}} modified the publisher string; that no longer happens: <div style="margin-left:3.2em>{{cite compare |template=book |title=Title |date=2026 |publication-date=2025}} {{cite compare |template=book |title=Title |date=2026 |location=Location |publication-date=2025}} {{cite compare |template=book |title=Title |date=2026 |publisher=Publisher |publication-date=2025}} {{cite compare |template=book |title=Title |date=2026 |location=Location |publisher=Publisher |publication-date=2025}}</div> :If we are to believe [https://en.wikipedia.org/w/index.php?search=hastemplate%3A%22Module%3ACitation%2FCS1%22+insource%3A%22publication-date%22+insource%3A%2F%5C%7B+*%5BCc%5Dit%5Bae%5D%5B%5E%5C%7D%5D*%5C%7C+*date%5B%5E%5C%7D%5D*%5C%7C+*publication%5C-date%2F&ns0=1 this search], there are about 10,500 articles with cs1|2 templates that use both {{para|date}} and {{para|publication-date}}. : :Keep? Discard? :—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 16:36, 18 September 2026 (UTC) ::Plus another [https://en.wikipedia.org/w/index.php?search=hastemplate%3A%22Module%3ACitation%2FCS1%22+insource%3A%22publication-date%22+insource%3A%2F%5C%7B%5Cs*%5BCc%5Dit%5Bae%5D%5B%5E%5C%7D%5D*%5C%7C%5Cs*publication-date%5B%5E%5C%7D%5D*%5C%7C%5Cs*date%2F&title=Special%3ASearch&profile=advanced&fulltext=1&ns0=1 1200]. [[User:Izno|Izno]] ([[User talk:Izno|talk]]) 23:38, 18 September 2026 (UTC) ::If so many articles see a difference between the two fields, why merge them? They obviously serve some purpose in some cases. [[User:Keriluamox|Keriluamox]] ([[User talk:Keriluamox|talk]]) 05:10, 19 September 2026 (UTC) :::The question is wether the 'served purpose' in these cases corresponds with the documented intended use of the field. [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 13:18, 19 September 2026 (UTC) :::{{ec}} :::Not so many, really. As I write this, [[Module:Citation/CS1]] is used on [https://en.wikipedia.org/w/index.php?search=hastemplate%3A%22Module%3ACitation%2FCS1%22&go=Go&ns0=1 5,871,549 articles]. If {{para|date}} and {{para|publication-date}} are used on ~10,500 + ~1,200 = ~11,700 articles, that is {{#expr:(((10500+1200)/5871549)*100) round 3}}%. Not so many in the scheme of things. ::: :::If I understand the sense of all of the various discussions we've had on this topic, multiple 'publication' dates in a single cs1|2 template are not needed to meet the citation's primary purpose: to identify the source that supports the text in an en.wiki article. :::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 13:27, 19 September 2026 (UTC) ::::So publication-date is only used on 1.200 pages? That's not a lot. ::::I wouldn't make date and publication-date aliases of each other. I would just remove publication-date from the template, and have Wikipedia showing a 'undocumented/unsupported/deprecated parameter' error whenever publication-date is used (like with citeseerx parameter currently). Then people can decide for themselves what to do with it. ::::I don't know how this would work out for place and publication-place, but you might be able to do the same there. [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 06:14, 21 September 2026 (UTC) :::: :::::I think that you are mistook. The '1200' number is the number of articles that have cs1|2 templates with both {{para|publication-date}} and {{para|date}} in that order (left to right). The 10,500 number is the number of articles that have cs1|2 templates with both {{para|date}} and {{para|publication-date}} in that order (left to right). ::::: :::::[https://en.wikipedia.org/w/index.php?search=hastemplate%3A%22Module%3ACitation%2FCS1%22+insource%3A%22publication-date%22+insource%3A%2F%5C%7B%5Cs*%5BCc%5Dit%5Bae%5D%5B%5E%5C%7D%5D*%5C%7C%5Cs*publication-date%5Cs*%3D%2F&ns0=1 This search] suggests that there are ~38,400 articles that have cs1|2 templates with {{para|publication-date}} (alone or paired). ::::: :::::For comparison, [https://en.wikipedia.org/w/index.php?search=hastemplate%3A%22Module%3ACitation%2FCS1%22+insource%3A%22date%22+insource%3A%2F%5C%7B%5Cs*%5BCc%5Dit%5Bae%5D%5B%5E%5C%7D%5D*%5C%7C%5Cs*date%5Cs*%3D%2F&ns0=1 this search] (times out) suggests that there are ~1,004,800 articles that have cs1|2 templates with {{para|date}} (alone or paired). ::::: :::::One thing that we've overlooked is {{para|year}} paired with {{para|publication-date}}. So two more searches: :::::*{{para|year}} precedes {{para|publication-date}}: [https://en.wikipedia.org/w/index.php?search=hastemplate%3A%22Module%3ACitation%2FCS1%22+insource%3A%22publication-date%22+insource%3A%2F%5C%7B+*%5BCc%5Dit%5Bae%5D%5B%5E%5C%7D%5D*%5C%7C+*year%5B%5E%5C%7D%5D*%5C%7C+*publication%5C-date%2F&ns0=1 ~9,500 articles] :::::*{{para|year}} follows {{para|publication-date}}: [https://en.wikipedia.org/w/index.php?search=hastemplate%3A%22Module%3ACitation%2FCS1%22+insource%3A%22publication-date%22+insource%3A%2F%5C%7B%5Cs*%5BCc%5Dit%5Bae%5D%5B%5E%5C%7D%5D*%5C%7C%5Cs*publication-date%5B%5E%5C%7D%5D*%5C%7C%5Cs*year%2F&ns0=1 ~1,400 articles] :::::Still not so many... As I write this, [[Module:Citation/CS1]] is used on [https://en.wikipedia.org/w/index.php?search=hastemplate%3A%22Module%3ACitation%2FCS1%22&go=Go&ns0=1 5,872,789 articles]. If {{para|date}} and {{para|publication-date}} are used on ~10,500 + ~1,200 + ~9,500 + ~1,400 = ~22,600 articles, that is {{#expr:(((10500+1200+9500+1400)/5872789)*100) round 3}}%. :::::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 13:36, 21 September 2026 (UTC) ::::::You could turn date into a multi-valued/nested field, and then have date and publication-date indeed be aliases of each other. Then the field date can have multiple values, without specifying the difference between the values, and then date and publication-date will both be values of the same date field. [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 14:16, 21 September 2026 (UTC) :::::::Could, but I don't think that we should. I think that such a mechanism would just cause confusion; especially so when rendering {{tq|multiple values... without specifying the difference between the values}}: ::::::::Author Name (2025, 2026). ''Book Title''. Publisher Name. :::::::And, in cs1|2, a parameter that is an alias of a parameter already in the template is not allowed – {{para|publication-date}} and {{para|publication-place}} violate that rule for little or no benefit. :::::::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 15:41, 21 September 2026 (UTC) ::::::::Is there documentation about how date and publication-date are rendered? [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 15:49, 21 September 2026 (UTC) :::::::::Did you look in the template documentation? [[Template:Cite_book#Date|here]]? and [[Template:Cite_book#Publisher|here]]? And see the '''Live''' examples in the comparisons above. :::::::::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 16:01, 21 September 2026 (UTC) ::::::::::“If date (or year) is not defined, publication-date is displayed as date.” ::::::::::i think this is really confusing. Maybe it should be configured that publication-date can only be used if date is also/already defined [[User:Lcporschen|Lcporschen]] ([[User talk:Lcporschen|talk]]) 16:10, 21 September 2026 (UTC) :::::::::::Yes, it is confusing and it is unnecessary. We don't need two publication dates to identify a source that supports en.wiki article text. When this change goes live, the [[Template:Cite_book#Publisher|{{para|publication-date}} documentation]] will go away and {{para|publication-date}} will be added to the [[Template:Cite_book#Date|{{para|date}} documentation]] as a simple alias of {{para|date}}. :::::::::::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 17:02, 21 September 2026 (UTC) == Cite document, paper, journal, and web == I am confused as to why {{t|cite document}} does not support URL parameters. I have on multiple occasions been caught off guard when attempting to use {{t|cite paper}} and getting a missing {{para|journal}} error thrown at me, as it is currently a redirect to {{t|cite journal}}. ''Paper'' and ''document'' are much closer semantically, so it seems reasonable to expect {{t|cite paper}} to redirect to {{t|cite document}}, but in replacing a call of the former to the latter, I get hit with an unknown parameter {{para|url}} error. Instead, I have to use {{t|cite web}}, which in many cases seems an inappropriate template to use for what I am citing. The particular example that caused me to bring this up here is the following: <syntaxhighlight lang="wikitext"> {{cite web |last=Jones |first=Daniel |author-link=Daniel Jones (phonetician) |year=1956 |title=Cardinal Vowels Spoken by Daniel Jones: Text of Records with Explanatory Notes by Professor Jones |location=London |publisher=Linguaphone Institute |url=https://s3-eu-west-1.amazonaws.com/s3-euw1-ap-pe-ws4-cws-streaming.ri-prod/9781444183092/cardinal.pdf }} </syntaxhighlight> The url is merely a scan of a {{tq|short, stand-alone, offline document}} exactly as described in the documentation of {{t|cite document}}, so the fact that I get an error makes little sense to me. I was going to create an RfD for {{t|cite paper}} to retarget it to {{t|cite document}}, but this is preventing me from doing so. ~ [[User:Oklopfer|<span style="color: #e3308a">oklopfer</span>]] ([[User talk:Oklopfer|💬︎]]) 22:39, 21 August 2026 (UTC) :IIRC the reason for {{-r|Template:Cite paper}} being a redirect to [[Template:Cite journal]] is because for an academic paper to be acceptable for verifiability purposes, it must have been published; and the usual place for academic papers to be published is in an academic journal. --[[User:Redrose64|<span style="color:#a80000; background:#ffeeee; text-decoration:inherit">Red</span>rose64]] &#x1f339; ([[User talk:Redrose64|talk]]) 22:49, 21 August 2026 (UTC) :I agree that cite document should support URLs. An offline document just means a physical document. There's no reason why there can't be online scans/PDFs of them. &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 23:22, 21 August 2026 (UTC) :Sorry but it's clearly not a {{tq|short, stand-alone, offline document}} as it's online. It can't be offline if it has a URL. Cite Document's documentation would clearer if it was "{{tq|short, stand-alone document, that is not available online}}". -- <small>LCU</small> '''[[User:ActivelyDisinterested|A<small>ctively</small>D<small>isinterested</small>]]''' <small>''«[[User talk:ActivelyDisinterested|@]]» °[[Special:Contributions/ActivelyDisinterested|∆t]]°''</small> 11:29, 22 August 2026 (UTC) ::Which it shouldn't be. Cite document should be for any generic document. That something is available online is completely irrelevant. &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 12:18, 22 August 2026 (UTC) :::I could see the argument for that, but that's not how it's currently setup. -- <small>LCU</small> '''[[User:ActivelyDisinterested|A<small>ctively</small>D<small>isinterested</small>]]''' <small>''«[[User talk:ActivelyDisinterested|@]]» °[[Special:Contributions/ActivelyDisinterested|∆t]]°''</small> 12:33, 22 August 2026 (UTC) :::Like {{tl|Citation}} for CS1? You'd probably need broad consensus for that since the other CS1 templates all describe a type of source. I think {{tl|cite document}} was a [https://en.wikipedia.org/w/index.php?title=Template%3ACite_document&diff=1170021118&oldid=1095569050 redirect] to {{tl|cite journal}} prior to this discussion: {{format link|Help_talk:Citation_Style_1/Archive_81#"Cite_document"_needs_its_own_template._Redirecting_to_cite_journal_is_illogical_and_unfriendly.}} [[User:Rjjiii|<span style="font-variant:small-caps;">Rjj<sup>iii</sup></span>]] ([[User talk:Rjjiii|talk]]) 15:38, 22 August 2026 (UTC) ::::Ah, that helps to explain the incongruence of {{t|cite paper}} and {{t|cite document}}, then. ~ [[User:Oklopfer|<span style="color: #e3308a">oklopfer</span>]] ([[User talk:Oklopfer|💬︎]]) 18:37, 22 August 2026 (UTC) ::In my opinion, a "document" is a [[pamphlet]], a small version of book, so we should be able to use all parameters of {{tl|cite book}} other than {{para|chapter}} and related params. --[[User:FlatLanguage|FlatLanguage]] ([[User talk:FlatLanguage|talk]]) 02:09, 26 August 2026 (UTC) :Cite document is specifically provided to support URL-less lesser works that appear in no other greater works. That is the point of the template. [[User:Izno|Izno]] ([[User talk:Izno|talk]]) 21:51, 31 August 2026 (UTC) ::And if a digitized version of that document suddenly appears, it doesn't cease to be a document. URL should be supported. &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 15:10, 19 September 2026 (UTC) == Speedy deletion for citeseerx CS1 error category? == Is [[:Category:CS1 errors: citeseerx]] still being used in some fashion? Since all instances of citeseerx are now a [[:Category:CS1 errors: deprecated parameters|deprecated parameter]] error anyway, I don't see any use for this anymore. I would flag it as [[Wikipedia:C4|C4]] for speedy deletion but I want confirmation that this isn't being used anywhere else before proceeding. [[User:BlaqWiedow|BlaqWiedow]] ([[User talk:BlaqWiedow|talk]]) 16:24, 14 September 2026 (UTC) :{{para|citeseerx}} is deprecated but still supported. {{cl|CS1 errors: citeseerx}} will be deleted when support for {{para|citeseerx}} is withdrawn. Don't hold your breath for that to happen soon. :—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 16:30, 14 September 2026 (UTC) == "always include ISBN, if one has been assigned" == This is appalling advice. The utility of littering pages with visually distracting ISBN links to nowhere would be moot even if the ISBNs were correct. Because many Wiki editors do not understand that an ISBN identifies an edition rather than a work, thousands of the ISBNs on the site are wrong. Editors should be advised to consider what purpose an ISBN serves, and, if they decide to include one, to ensure that it is '''the right ISBN for the edition cited'''. (The field is so pointless and troublesome that it would be better to remove it from the template completely.) [[User:Utilisateur19911|Utilisateur19911]] ([[User talk:Utilisateur19911|talk]]) 08:04, 15 September 2026 (UTC) :Yes, the ISBN must be correct for the edition. While that is ''an'' issue, it is a fairly minor one and certainly does not make "the field so pointless and troublesome that it would be better to remove from the template completely". &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 13:14, 15 September 2026 (UTC) ::ISBN is incredibly useful when trying to hunt down the correct work, especially for something obscure. Updating the documentation to advice on ensuring the correct ISBN is used can be done by anyone. -- <small>LCU</small> '''[[User:ActivelyDisinterested|A<small>ctively</small>D<small>isinterested</small>]]''' <small>''«[[User talk:ActivelyDisinterested|@]]» °[[Special:Contributions/ActivelyDisinterested|∆t]]°''</small> 14:02, 15 September 2026 (UTC) :::{{+1}} on updating documentation. '''[[User:Icepinner|Icepinner]]''' ([[User talk:Icepinner|Come to Hakurei Shrine!]]) 16:27, 17 September 2026 (UTC) == Please update SC2ID limit == In this [[Köthe conjecture]] page, one of the sources used a journal with SC2ID more than 290000000 which is 291870068 (and it is the right journal). Please update the limit. [[User:Lowyat Slyder|Lowyat Slyder]] ([[User talk:Lowyat Slyder|talk]]) 16:02, 17 September 2026 (UTC) == Listing a committee == The documentation for 'author1' says "this parameter is used to hold the name of an organizational author (e.g. a committee)", but using it for that purpose generates an error. As an example: : {{Cite book | title=Review and Assessment of Planetary Protection Policy Development Processes | author1=Committee on the Review of Planetary Protection Policy Development Processes | author2=Space Studies Board | author3=Division on Engineering and Physical Sciences | author4=National Academies of Sciences, Engineering, and Medicine | date=September 17, 2018 | publisher=National Academies Press | isbn=978-0-309-47865-6 | location=Washington, D.C. | doi=10.17226/25172 | url=https://www.nationalacademies.org/publications/25172}} Does the documentation need to be revised? [[User:Praemonitus|Praemonitus]] ([[User talk:Praemonitus|talk]]) 15:43, 18 September 2026 (UTC) :Use {{para|author''n''|((Committee on the Review of ...))}} &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 18:19, 18 September 2026 (UTC) :: I'm aware of the work-around, thanks. My question was regarding the documentation. [[User:Praemonitus|Praemonitus]] ([[User talk:Praemonitus|talk]]) 20:22, 18 September 2026 (UTC) ::{{re|Praemonitus}} Your citation got flagged by [[Module:Citation/CS1/Configuration]] because it contains the word "policy". I have [[Special:Diff/1376078963|edited the documentation for this error]] to be a little more informative. I'm not sure what led to that particular pattern being added, but I wonder if it was related to [[privacy policy]]. ::I think the current set of patterns is overzealous and produces too many [[false positive]]s. I propose removing at least "policy" and "bureau" as relatively common organizational names that are likely appropriate collective authors. ::My efforts to craft a [https://en.wikipedia.org/w/index.php?title=Special%3ASearch&ns0=1&fulltext=Search&search=insource%3A%2F|\s*author\d%3F\s*%3D%5B%5E%7C%7B%7D%5D*policy%2F regular expression to review existing uses] are timing out. Perhaps someone here knows a better way to query. [[User:Daask|Daask]] ([[User talk:Daask|talk]]) 18:01, 26 September 2026 (UTC) :::Here's a better one [https://en.wikipedia.org/w/index.php?search=insource%3A%2F%5C%7C%5Cs*%28author%7Clast%29-%3F%5Cd%3F%5Cs*%3D%5Cs*%5B%5E%5C%7C%5C%7D%5D*policy%2Fi&title=Special%3ASearch&profile=advanced&fulltext=1&ns0=1] &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 18:16, 26 September 2026 (UTC) ::: Thanks. [[User:Praemonitus|Praemonitus]] ([[User talk:Praemonitus|talk]]) 18:43, 26 September 2026 (UTC) {{edit fully-protected|Module:Citation/CS1/Configuration|answered=yes}} Please remove the lines containing '^[Bb]ureau$' and 'policy', due to excessive false positives as described above. [[User:Daask|Daask]] ([[User talk:Daask|talk]]) 15:09, 29 September 2026 (UTC) :Not done. When we constrain the searches to just those uses that trigger the error messaging, there aren't really that many: ::[https://en.wikipedia.org/w/index.php?search=incategory%3A%22CS1+errors%3A+generic+name%22+insource%3A%2F%5C%7C%5Cs*%28author%7Clast%29-%3F%5Cd%3F%5Cs*%3D%5Cs*%5B%5E%5C%7C%5C%7D%5D*policy%2Fi&ns0=1 'contains 'policy': ~260 articles] ::[https://en.wikipedia.org/w/index.php?ns0=1&search=incategory%3A%22CS1+errors%3A+generic+name%22+insource%3A%2F%5C%7C%5Cs*%28author%7Clast%29-%3F%5Cd%3F%5Cs*%3D%5Cs*%5BBb%5Dureau%5Cs*%5B%5C%7C%5C%7D%5D%2Fi is 'Bureau' or 'bureau': ~510 articles] :—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 23:55, 4 October 2026 (UTC) ::{{re|Trappist the monk}} My review of the citations found in your search query for "policy" indicates that the author is accurate in the overwhelming majority of these citations (although many are split into last= and first= inappropriately). Why are we flagging these as errors? I understand that these queries are only causing false positives for some hundreds or perhaps thousands of citations (including those using accept-as-written markup), which you find trivial. Yet this still appears to be significantly more than the number of true positives they are finding. This thread indicates that flagging false positives is causing editor confusion, and it isn't obvious to me why showing an error message on the rare and obviously-wrong author of "Policy, Privacy" is worth the trouble. ::I'm happy to withdraw my request regarding <code>^[Bb]ureau$</code>, because it is anchored to the beginning and ending of the author name. Perhaps we could do the same and replace this with <code>^[Pp]olicy$</code> ? [[User:Daask|Daask]] ([[User talk:Daask|talk]]) 16:05, 5 October 2026 (UTC) == Foreign-language journal with separate URLs for original article and third-party translation == I have a {{tl|cite journal}} for an article that's in French. It's fairly old (no DOI or other modern identifier) but there is an electronic scan available. That means I need to use {{para|url}} to link it. There is also an English translation available for the whole article. How do I also link that as well? I'm currently using an extlink in {{para|trans-title}}, but that's obviously a CS1 error. [[User:DMacks|DMacks]] ([[User talk:DMacks|talk]]) 10:31, 20 September 2026 (UTC) :You include the secondary URL outside of the template, but before the close ref tags. -- <small>LCU</small> '''[[User:ActivelyDisinterested|A<small>ctively</small>D<small>isinterested</small>]]''' <small>''«[[User talk:ActivelyDisinterested|@]]» °[[Special:Contributions/ActivelyDisinterested|∆t]]°''</small> 13:55, 20 September 2026 (UTC) ::or write a separate cs1|2 template for the translation; especially if the bibliographic details or the translation differ from those of the translated source. ::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 14:11, 20 September 2026 (UTC) :::Thank you both. [[User:DMacks|DMacks]] ([[User talk:DMacks|talk]]) 17:15, 20 September 2026 (UTC) == Generic author name "Staff" == Propose that "Staff" and variations such as "[Name of Publication] Staff" and "Staff Writer[s]" be added to the [[Help:CS1 errors#Cite uses generic name|list of generic names]] for <code>|author=</code> and similar fields. These turn up a lot in various online publications. Thank you. <span class="nowrap">~[[User:Sangdeboeuf|Sangdeboeuf]]</span> ([[User talk:Sangdeboeuf|talk]]) 14:04, 20 September 2026 (UTC) * [[Staff (name)]] is a viable surname - this will create false positives - for example for books like {{cite book |last = Staff |first = Gary |title = German Battlecruisers of World War One: Their Design, Construction and Operations |publisher = Seaforth Publishing |location = Oxford |date = 2014 |isbn = 978-1-84832-308-7|ref=none}}[[User:Nigel Ish|Nigel Ish]] ([[User talk:Nigel Ish|talk]]) 14:06, 20 September 2026 (UTC) *:OK, I wasn't aware of that. <span class="nowrap">~[[User:Sangdeboeuf|Sangdeboeuf]]</span> ([[User talk:Sangdeboeuf|talk]]) 01:05, 21 September 2026 (UTC) * I find the use of these terms reassures readers and editors that the author hasn't been omitted or forgotten, so I think they're useful. -- [[User:Michael Bednarek|Michael Bednarek]] ([[User talk:Michael Bednarek|talk]]) 15:25, 20 September 2026 (UTC) == |location=, |place=, and |publication-place= == Because of their similar peculiarities, {{para|location}}, {{para|place}}, and {{para|publication-place}} are often mentioned when we have been discussing {{para|date}} and {{para|publication-date}}; most recently at [[Help talk:Citation Style 1#Cite book: Year of publication]]. When used in isolation, {{para|publication-date}} is an equal alias of {{para|location}} and {{para|place}}. When {{para|publication-date}} is paired with either of {{para|location}} or {{para|place}}, the latter parameter causes cs1|2 to emit 'written at' static text. My sense from our previous discussions is that where a source was written is not needed when the purpose of a citation is to identify the source that supports text in an en.wiki article. So, I have hacked the module sandboxen to make {{para|location}}, {{para|place}}, and {{para|publication-place}} equal aliases at all times. Since December 2019, we have maintained a properties category {{cl|CS1 location test}} which accumulates articles that have cs1|2 templates with {{para|publication-place}} and either of {{para|location}} or {{para|place}}. At this writing, the category lists ~1,800 articles. When used in isolation, {{para|location}}, {{para|place}}, and {{para|publication-place}} have been and will remain equal aliases of each other: <div style="margin-left:1.6em">{{cite compare |template=citation |title=Title |location=Austin, Texas |newspaper=The Villager}}</div> <div style="margin-left:1.6em">{{cite compare |template=citation |title=Title |place=Manhattan |newspaper=The Villager}}</div> <div style="margin-left:1.6em">{{cite compare |template=citation |title=Title |publication-place=The Woodlands, Texas |newspaper=The Villager}}</div> When {{para|publication-place}} is paired with either of {{para|location}} or {{para|place}}, the 'written at' static text will no longer be rendered and [[Module:Citation/CS1]] will render a duplicate parameter error message: <div style="margin-left:1.6em">{{cite compare |template=citation |title=Title |publication-place=Manhattan |location=London |newspaper=The Villager}}</div> <div style="margin-left:1.6em">{{cite compare |template=citation |title=Title |publication-place=Manhattan |place=London |newspaper=The Villager}}</div> <div style="margin-left:1.6em">{{cite compare |template=citation |title=Title |publication-place=Manhattan |location=Manhattan |newspaper=The Villager}}</div> Module:Citation/CS1 will no longer link to {{cl|CS1 location test}}. The category will automatically empty at which point it may be deleted. Keep? Discard? —[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 14:09, 21 September 2026 (UTC) :Looking at an example, we currently have in [[...Lu]] :*<pre>{{cite book|last=Hinz|first=W.|translator-last=Barnes|translator-first=J.|year=1972|title=The Lost World of Elam: Re-creation of a Vanished Civilization|url=https://books.google.com/books?id=DGkKAQAAIAAJ|location=United Kingdom|publisher=[[Sidgwick & Jackson]]|publication-place=University of California|isbn=9780283978630}}</pre> :rendering as :*{{cite book|last=Hinz|first=W.|translator-last=Barnes|translator-first=J.|year=1972|title=The Lost World of Elam: Re-creation of a Vanished Civilization|url=https://books.google.com/books?id=DGkKAQAAIAAJ|location=United Kingdom|publisher=[[Sidgwick & Jackson]]|publication-place=University of California|isbn=9780283978630}} :This is clearly nonsense. No one cares that Hinz wrote it in the UK (which is an [https://de-wikipedia-org.translate.goog/wiki/Walther_Hinz?_x_tr_sl=fr&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=wapp extremely dubious proposition] given he spent the vast majority of his academic life in Germany and Iran and probably never even sat foot in the UK), or that Barnes translated it in California. The only thing that bibliographically matters is what is the location of [https://books.google.com/books?id=DGkKAQAAIAAJ Sidgwick & Jackson, which here is UK (London)], or [https://books.google.ca/books?redir_esc=y&id=DGkKAQAAIAAJ&focus=searchwithinvolume&q=New+York+University NYU Press (New York)]. :So the category is useful to find the nonsense. But if another category exists... *shrugs*. &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 15:40, 21 September 2026 (UTC) ::We do have another category: {{cl|CS1 errors: redundant parameter}} and we will have visible error messages so the properties category {{cl|CS1 location test}} (properties cats are not associated with a visible messaging) becomes redundant. ::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 15:53, 21 September 2026 (UTC) == Citing YouTube == Please direct me to somewhere that can teach me how to cite YouTube. (I've been editing for 20 years, and I've never cited YouTube.) Tried using {{tl|Cite YouTube}} but this redirects to {{tl|Cite AV Media}} which doesn't seem to have the parameters I need. I'm sure someone has worked this out. Where do I go? This is the URL: [https://www.youtube.com/watch?v=jrK3PsD3APk]. I want to mention the interviewee (Hinton), the interviewer (Jon Stewart), the channel, (The Weekly Show with Jon Stewart), the time-stamp of the thing I'm citing and the website (YouTube). ---- [[User:CharlesTGillingham|CharlesTGillingham]] ([[User talk:CharlesTGillingham|talk]]) 19:41, 21 September 2026 (UTC) :Here is one way (assuming that the timestamp is at the 30 minute mark): ::<syntaxhighlight lang="wikitext" inline="1">{{cite av media |subject=Geoffrey Hinton |interviewer=Jon Stewart |title=AI: What Could Go Wrong? with Geoffrey Hinton |time=0:30 |publisher=The Weekly Show with Jon Stewart |url=https://www.youtube.com/watch?v=jrK3PsD3AP |via=YouTube}}</syntaxhighlight> :::{{cite av media |subject=Geoffrey Hinton |interviewer=Jon Stewart |title=AI: What Could Go Wrong? with Geoffrey Hinton |time=0:30 |publisher=The Weekly Show with Jon Stewart |url=https://www.youtube.com/watch?v=jrK3PsD3AP |via=YouTube}} :You can also use {{para|minutes|30}} for a slightly different rendering: ::<syntaxhighlight lang="wikitext" inline="1">{{cite av media |subject=Geoffrey Hinton |interviewer=Jon Stewart |title=AI: What Could Go Wrong? with Geoffrey Hinton |minutes=30 |publisher=The Weekly Show with Jon Stewart |url=https://www.youtube.com/watch?v=jrK3PsD3AP |via=YouTube}}</syntaxhighlight> :::{{cite av media |subject=Geoffrey Hinton |interviewer=Jon Stewart |chapter=AI: What Could Go Wrong? with Geoffrey Hinton |minutes=30 |title=The Weekly Show with Jon Stewart |chapter-url=https://www.youtube.com/watch?v=jrK3PsD3AP |via=YouTube}} :—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 19:54, 21 September 2026 (UTC) ::::<pre>{{cite av media |subject=Geoffrey Hinton |interviewer=Jon Stewart |chapter=AI: What Could Go Wrong? with Geoffrey Hinton |minutes=30 |title=The Weekly Show with Jon Stewart |chapter-url=https://www.youtube.com/watch?v=jrK3PsD3AP |via=YouTube}}</pre> rendering as ::::*{{cite av media |subject=Geoffrey Hinton |interviewer=Jon Stewart |chapter=AI: What Could Go Wrong? with Geoffrey Hinton |minutes=30 |title=The Weekly Show with Jon Stewart |chapter-url=https://www.youtube.com/watch?v=jrK3PsD3AP |via=YouTube}} ::::seems better to me. Parameter names could be better though, but this correctly put things as minor/major works and doesn't wrongly state that the Weekly Show is a publisher. &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 03:53, 22 September 2026 (UTC) :::Thanks, much appreciated. This citation is in [[artificial intelligence]] ---- [[User:CharlesTGillingham|CharlesTGillingham]] ([[User talk:CharlesTGillingham|talk]]) 03:42, 22 September 2026 (UTC) == Request for language override: Tetun language == [[Tetum language]] has been [https://en.wikipedia.org/w/index.php?curid=66305487#Requested_move_1_March_2026 moved] to [[Tetun language]]. [[Module:ISO 639 name/ISO 639-3]] still shows "Tetum" (with an "m"), because [https://iso639-3.sil.org/code/tet sil still shows "Tetum"] (and Ethnologue shows "Tetun"). It looks like we need an override for "tet" at [[Module:Citation/CS1/Configuration]]. – [[User:Jonesey95|Jonesey95]] ([[User talk:Jonesey95|talk]]) 14:34, 23 September 2026 (UTC) :In the sandbox: <div style="margin-left:3.2em>{{cite compare |template=book |title=Title |language=tet}} {{cite compare |template=book |title=Title |language=tetum}} {{cite compare |template=book |title=Title |language=tetun}}</div> :—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 15:44, 23 September 2026 (UTC) :If anyone is interested in the reasoning, the original discussion is at [[Talk:Tetun#Requested move 1 March 2026]]. It boils down to a quirk of Portuguese spelling. <span class="nowrap">[[User:ChompyTheGogoat|<span style="font-weight: bold; color:#BB6BD1">ChompyTheGogoat</span>]]&nbsp;[&nbsp;[[User talk:ChompyTheGogoat|<span style="color:#D72D85">Bleat</span>]]&nbsp;&#124;&nbsp;[[Special:Contributions/ChompyTheGogoat|<span style="color: #2da86c;">Munched</span>]]&nbsp;]</span> 15:51, 23 September 2026 (UTC) == Typo in the description of template [[Template:Cite journal]] == In the description of the <code>journal</code> option in the template [[Template:Cite journal]] there is (what I believe to be) a typo. The example reads "<nowiki>[[Nature (journal)|]]</nowiki>" instead of "<nowiki>[[Nature (journal)]]</nowiki>" (note the additional bar). [[Wikipedia:Wiki_Workers_United_solidarity|In solidarity with Wiki Workers United]], [[User:Zvavybir|zvavybir]] ([[User talk:Zvavybir|talk]]) 21:43, 26 September 2026 (UTC) :That is the result of [[Special:Diff/1366631846|this edit]] by Editor [[User:Cremastra|Cremastra]] ostensibly to {{tq|[allow] us to demonstrate the use of the pipe trick in the example}} like this: ::<syntaxhighlight lang="wikitext" inline="1">{{cite journal |title=Title |journal=[[Nature (journal)|]]}}</syntaxhighlight> :::{{cite journal |title=Title |journal=[[Nature (journal)|Nature]]}} :But, the pipe trick does not work in {{tag|ref}} tags: ::<syntaxhighlight lang="wikitext" inline="1"><ref>{{cite journal |title=Title |journal=[[Nature (journal)|]]}}</ref></syntaxhighlight><ref>{{cite journal |title=Title |journal=[[Nature (journal)|]]}}</ref> <div style="margin-left:4.8em">{{reflist talk}}</div> :Feel free to fix it. :—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 22:01, 26 September 2026 (UTC) == [[Template:Cite journal|Cite journal]] deprecated <code>|citeseerx=</code>: rationale and migration path? == I'm encountering warnings for a deprecated <code>|citeseerx=</code> parameter, for example, on [[Minority interpretations of quantum mechanics#cite_note-27|this citation]]. However, it's not clear from the template documentation precisely ''why'' the parameter is deprecated, or how to eliminate this warning by migrating to features with ongoing support. These warrant an explanation in the obvious place editors will look to resolve the warning. [[User:EnronEvolved|EnronEvolved]]<sup>[[User talk:EnronEvolved|My Talk Page]]</sup> 14:29, 2 October 2026 (UTC) :This parameter is deprecated. See [[Help_talk:Citation_Style_1/Archive_102#deprecate %7Cciteseerx= ?|discussion]].––[[User:KEmel49|<span style="color: #000099; font-weight: bold; font-family: Georgia;">KE</span>mel<span style="color: red;">49</span>]]([[User talk:KEmel49|📝]],[[Special:Contributions/KEmel49|📋]]) 15:13, 2 October 2026 (UTC) == Update bibcode URL to SciX == ADS is scheduled to be shutdown on 16 November 2026. It's replacement, SciX, has been available for some time. See {{slink|Template talk:Bibcode#ADS to SciX migration}} for details. {{edit request|Module:Citation/CS1/Configuration|level=full|answered=yes}} In [[Module:Citation/CS1/Configuration]], please replace the line: <syntaxhighlight>prefix = 'https://ui.adsabs.harvard.edu/abs/',</syntaxhighlight> with <syntaxhighlight> prefix = 'https://scixplorer.org/abs/', suffix = '/abstract', </syntaxhighlight> [[User:Daask|Daask]] ([[User talk:Daask|talk]]) 17:30, 5 October 2026 (UTC) :This should be done in the sandbox, and deployed with the rest of the changes. So long as it's live before Nov 16th or so. &#32;<span style="font-variant:small-caps; whitespace:nowrap;">[[User:Headbomb|Headbomb]] {[[User talk:Headbomb|t]] · [[Special:Contributions/Headbomb|c]] · [[WP:PHYS|p]] · [[WP:WBOOKS|b]]}</span> 19:26, 5 October 2026 (UTC) ::{{donetask}} Implemented in sandbox in [[Special:Diff/1378836392|Diff/1378836392]]. [[User:Daask|Daask]] ([[User talk:Daask|talk]]) 11:37, 6 October 2026 (UTC) :::You should always provide evidence that the changes you make actually work. <div style="margin-left:6.4em">{{cite compare |template=book |title=Keck Speckle Imaging of the White Dwarf G29-38: No Brown Dwarf Companion Detected |bibcode=1998ApJ...508L..81K}}</div> :::—[[User:Trappist the monk|Trappist the monk]] ([[User talk:Trappist the monk|talk]]) 14:32, 7 October 2026 (UTC) == Cite sign - content only, or also things like location? == Hi all, Is {{tl|Cite Sign}} supposed to be used only for, say, the text of a sign, or can it also be used for things like the specific location of a sign? Say if a construction plaque or gravestone was moved, even if the text was the same, would that be within the scope or not? Or could a sign's presence or lack thereof be used, e.g. if a builder's plate on an object went missing at some point, and that fact was somehow relevant to an article about falsified or altered products or devices etc? (I'm aiming for a generalised guideline, but the specific example that got me thinking about this is for two very similar railway wagon types; the easiest way to differentiate between them is whether the builder's plate is centred or at one end of the wagon (and that can be established separately from [[WP:RS]]'s). So I'd be "referencing" both types of sign, but based on the location not the content.) [[User:Anothersignalman|Anothersignalman]] ([[User talk:Anothersignalman|talk]]) 15:16, 6 October 2026 (UTC) == "Verifying your browser" should be a generic title == Seen at [[Special:Diff/1378865138]] [[User:Pppery|* Pppery *]] [[User talk:Pppery|<sub style="color:#800000">it has begun...</sub>]] 16:12, 6 October 2026 (UTC) bk01bild65jgjldyv5otraje24eo87p Module:Citation Style 1 link 828 81181 736722 2026-07-23T14:08:42Z HouseBlaster 15538 tsh 736722 wikitext text/x-wiki [[Help:Citation Style 1|Citation Style 1]]<noinclude>{{tsh|Cs1}} [[Category:Documentation assistance templates]] </noinclude> 6awezyz3mkfz82bnsllyewpxu6zn6cc 736723 736722 2026-10-07T14:40:43Z King ChristLike 13051 1 revision imported from [[:en:Template:Citation_Style_1_link]] 736722 wikitext text/x-wiki [[Help:Citation Style 1|Citation Style 1]]<noinclude>{{tsh|Cs1}} [[Category:Documentation assistance templates]] </noinclude> 6awezyz3mkfz82bnsllyewpxu6zn6cc Module:Citation Style 2 link 828 81182 736724 2026-07-23T14:08:19Z HouseBlaster 15538 tsh 736724 wikitext text/x-wiki [[Help:Citation Style 2|Citation Style 2]]<noinclude>{{tsh|Cs2}} [[Category:Documentation assistance templates]] </noinclude> newt7gxb92w6fp9lyd0b9gidisd48z5 736725 736724 2026-10-07T14:40:43Z King ChristLike 13051 1 revision imported from [[:en:Template:Citation_Style_2_link]] 736724 wikitext text/x-wiki [[Help:Citation Style 2|Citation Style 2]]<noinclude>{{tsh|Cs2}} [[Category:Documentation assistance templates]] </noinclude> newt7gxb92w6fp9lyd0b9gidisd48z5 Module:Citation/CS1/Suggestions 828 81183 736735 2023-01-14T14:43:32Z Trappist the monk 14640 sync from sandbox; 736735 Scribunto text/plain -- Please insert new suggestions in alphabetical order -- The form is ['incorrect'] = 'correct', suggestions = { ['ASIN-TLD'] = 'asin-tld', -- old parameter name ['abruf'] = 'access-date', -- German ['abruf-verborgen'] = 'access-date', -- German ['accessmonth'] = 'access-date', ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', ['acessodata'] = 'access-date', -- Brazilian Portuguese ['ad'] = 'first', -- Turkish ['address'] = 'location', ['anno'] = 'date', -- Italian ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['annooriginale'] = 'orig-date', -- Italian ['année'] = 'date', -- French ['apellido'] = 'last', -- Spanish ['apellidos'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archiv-url'] = 'archive-url', -- German ['archive date'] = 'archive-date', -- misspelling ['archive url'] = 'archive-url', -- misspelling ['archive-link'] = 'archive-url', -- old parameter name ['archiv-url'] = 'archive-url', -- German ['arkivdatum'] = 'archive-date', -- Swedish, Norwegian ['arkivurl'] = 'archive-url', -- Swedish, Norwegian ['artist'] = 'others', ['arşiv-tarihi'] = 'archive-date', -- Turkish ['arşiv-url'] = 'archive-url', -- Turkish ['arşivtarihi'] = 'archive-date', -- Turkish ['arşivurl'] = 'archive-url', -- Turkish ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', -- misspelling ['author link'] = 'author-link', -- Polish ['authorfirst'] = 'author-first', -- old parameter name ['authorgiven'] = 'author-given', -- old parameter name ['authorlast'] = 'author-last', -- old parameter name ['authormask'] = 'author-mask', -- old parameter name ['authorsurname'] = 'author-surname', -- old parameter name ['autor'] = 'author', -- Spanish, German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', -- misspelling ['ay'] = 'month', -- Turkish ['año'] = 'date', -- Spanish ['año-original'] = 'orig-date', -- Spanish ['añoacceso'] = 'access-date', -- Spanish ['añooriginal'] = 'orig-date', -- Spanish ['band'] = 'volume', -- German ['bandreihe'] = 'volume', -- German ['baskı'] = 'edition', -- Turkish ['başlık'] = 'title', -- Turkish ['began'] = 'date', -- old parameter name (cite serial only); or orig-date= ['booktitle'] = 'book-title', -- old parameter name ['ch'] = 'language', -- German (as 'language=de-CH') ['chapter_title'] = 'chapter', ['chapterurl'] = 'chapter-url', -- old parameter name ['cid'] = 'ref', -- Italian ['cilt'] = 'volume', -- Turkish ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['città'] = 'location', -- Italian ['city'] = 'location', -- old parameter name (cite serial only) ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['conferenceurl'] = 'conference-url', -- old parameter name ['consulté le'] = 'access-date', -- French ['contributionurl'] = 'contribution-url', -- old parameter name ['curatore'] = 'publisher', -- Italian ['czasopismo'] = 'journal', -- Polish ['data dostępu'] = 'access-date', -- Polish ['data'] = 'date', -- Polish, Italian ['dataaccesso'] = 'access-date', -- Italian ['dataarchivio'] = 'archive-date', -- Italian ['datum'] = 'date', -- German, Swedish ['dead-url'] = 'url-status', -- old parameter name ['deadlink'] = 'url-status', -- old parameter name ['deadurl'] = 'url-status', -- old parameter name ['dergi'] = 'work', -- Turkish ['dil'] = 'language', -- Turkish ['displayauthors'] = 'display-authors', -- old parameter name ['displayeditors'] = 'display-editors', -- old parameter name ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') ['doi-broken'] = 'doi-broken-date', -- old parameter alias ['doi-inactive'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-inactive-date'] = 'doi-broken-date', -- old parameter alias ['doi_brokendate'] = 'doi-broken-date', -- old parameter alias ['doi_inactivedate'] = 'doi-inactive-date', -- old parameter alias ['doibroken'] = 'doi-broken-date', -- invalid name found in mainspace ['doiinactive'] = 'doi-broken-date', -- invalid name found in mainspace ['e-print'] = 'eprint', -- misspelling -- ['ed'] = 'edition', -- avoid suggestion as in English this could be short for editor or edition -- ['editora'] = 'publisher', -- can be either editor or publisher -- ['editore'] = 'agency', -- can be either publisher or agency -- ['editori'] = 'editor', -- can be either editor or publisher -- ['editorial'] = 'publisher', -- can be either publisher or work ['editoin'] = 'edition', -- misspelling ['editon'] = 'edition', -- misspelling ['editorfirst'] = 'editor-first', -- old parameter name ['editorgiven'] = 'editor-given', -- old parameter name ['editorlast'] = 'editor-last', -- old parameter name ['editorlink'] = 'editor-link', -- old parameter name ['editormask'] = 'editor-mask', -- old parameter name ['editors'] = 'editor', -- old parameter name (can be emulated using multiple singular |editor= params) ['editorsurname'] = 'editor-surname', -- old parameter name ['edizione'] = 'edition', -- Italian ['embargo'] = 'pmc-embargo-date', -- old parameter name ['ended'] = 'date', -- old parameter name (cite serial only) ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['enlaceroto'] = 'url-status', -- Spanish ['episodelink'] = 'episode-link', -- old parameter name ['erişimtarihi'] = 'access-date', -- Turkish ['eser'] = 'work', -- Turkish ['family'] = 'surname', -- misguess ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['foramt'] = 'format', -- misspelling ['fore-name'] = 'given', -- misguess/misspelling ['forename'] = 'given', -- misguess ['författare'] = 'author', -- Swedish, Norwegian ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', -- misspelling ['fundstelle'] = 'at', -- German ['gazete'] = 'work', -- Turkish ['giornale'] = 'journal', -- Italian ['hämtdatum'] = 'access-date', -- Swedish ['herausgeber'] = 'editor', -- German (singular and plural) ['hrsg'] = 'publisher', -- German ['hrsgreihe'] = 'editor', -- German ['idioma'] = 'language', -- Spanish ['ignore-isbn-error'] = 'isbn', -- old parameter (can be fully emulated using ((syntax))) ['ignoreisbnerror'] = 'isbn', -- old parameter alias (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['imię'] = 'first', -- Polish ['in-set'] = 'inset', -- misspelling ['interviewerlink'] = 'interviewer-link', -- old parameter alias ['interviewermask'] = 'interviewer-mask', -- old parameter alias ['isbndefekt'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnistformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isnb'] = 'isbn', -- misspelling ['issnformalfalsch'] = 'issn', -- German (can be fully emulated using ((syntax))) ['jahr'] = 'date', -- German ['jahrea'] = 'orig-date', -- German (not a direct replacement, but can be emulated) ['kapitel'] = 'chapter', -- German ['langauge'] = 'language', -- misspelling ['langue'] = 'language', -- French ['last-author-amp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['lastauthoramp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License No. ...') ['loaction'] = 'location', -- misspelling ['local'] = 'location', -- Brazilian Portuguese ['locatoin'] = 'location', -- misspelling ['lugar'] = 'location', -- Spanish ['mailinglist'] = 'mailing-list', -- old parameter name ['mapurl'] = 'map-url', -- old parameter name ['mes'] = 'date', -- Spanish (not a direct replacement) ['mese'] = 'date', -- Italian (not a direct replacement) ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['name-list-format'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', -- misspelling ['net-work'] = 'network', -- misspelling ['newpaper'] = 'newspaper', -- misspelling ['news'] = 'newspaper', ['news-group'] = 'newsgroup', -- misspelling ['news-paper'] = 'newspaper', -- misspelling ['no-cat'] = 'no-tracking', -- old parameter ['nocat'] = 'no-tracking', -- old parameter ['nom'] = 'last', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['nopp'] = 'no-pp', -- old parameter name ['notracking'] = 'no-tracking', -- old parameter ['numero'] = 'number', -- Italian, Spanish ['nummer'] = 'number', -- German ['nummerreihe'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'url-status', -- German (as 'url-status=dead') ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opera'] = 'work', -- Italian ['opublikowany'] = 'agency', -- Polish ['origdate'] = 'orig-date', -- misspelling ['originaljahr'] = 'orig-date', -- German ['originalort'] = 'publication-place', -- German ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'publication-place', -- German ['ortea'] = 'publication-place', -- German (not a direct replacement, but can be emulated) ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', -- misspelling ['pagina'] = 'page', -- Italian ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['passage'] = 'pages', -- French ['periodico'] = 'magazine', -- Spanish ['plublisher'] = 'publisher', -- misspelling ['pmcid'] = 'pmc', ['post-script'] = 'postscript', -- misspelling ['praca'] = 'work', -- Polish ['primero'] = 'first', -- Spanish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubblicazione'] = 'magazine', -- could be any kind of work -- ['publicación'] = 'journal', -- could be any kind of work ['publicationdate'] = 'publication-date', -- old parameter name -- ['published'] = 'publisher', -- could be date, location, or name of publisher ['publicationplace'] = 'publication-place', -- old parameter name ['pulbication-place'] = 'publication-place', -- misspelling ['página'] = 'page', -- Spanish ['páginas'] = 'pages', -- Spanish ['périodique'] = 'publisher', -- French ['registration'] = 'url-access', -- old parameter name ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', -- old parameter name ['richiestasottoscrizione'] = 'url-access', -- Italian (as |url-access=subscription) ['rivista'] = 'magazine', -- Italian ['rok'] = 'date', -- Polish ['rubrik'] = 'title', -- Swedish ['sammelwerk'] = 'work', -- German ['sayfa'] = 'page', -- Turkish ['sayfalar'] = 'pages', -- Turkish ['sayı'] = 'issue', -- Turkish ['script-post'] = 'postscript', -- misspelling ['script-trans'] = 'transcript', -- misspelling ['season'] = 'date', -- old parameter name (cite serial only) ['sectionurl'] = 'section-url', -- old parameter name ['seiten'] = 'pages', -- German ['seria'] = 'series', -- Spanish, Polish ['serie'] = 'series', -- Italian ['série'] = 'series', -- French ['serieslink'] = 'series-link', -- old parameter name ['seriesno'] = 'series-number', -- old parameter name ['service'] = 'agency', ['sitioweb'] = 'website', -- Spanish ['sito'] = 'website', -- Italian ['soyadı'] = 'last', -- Turkish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['språk'] = 'language', -- Swedish, Norwegian ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['subjectlink'] = 'subject-link', -- old parameter name ['subscription'] = 'url-access', -- old parameter name (emulated as |url-access=subscription) ['sur-name'] = 'surname', -- misspelling ['suscripción'] = 'url-access', -- Spanish, Polish (as |url-access=subscription) ['tag'] = 'date', -- German ['tarih'] = 'date', -- Turkish ['template doc demo'] = 'no-tracking', -- old parameter alias ['tidning'] = 'work', -- Swedish ['tile'] = 'title', -- misspelling ['timecaption'] = 'time-caption', -- old parameter name ['titlelink'] = 'title-link', -- old parameter name ['tipo'] = 'type', -- Italian ['tite'] = 'title', -- misspelling ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titled'] = 'title', -- Brazilian Portuguese ['titolo'] = 'title', -- Italian ['titre'] = 'title', -- French ['trans-script'] = 'transcript', -- misspelling ['trans_chapter'] = 'trans-chapter', -- old parameter alias ['trans_title'] = 'trans-title', -- old parameter alias ['transchapter'] = 'trans-chapter', ['transcripturl'] = 'transcript-url', -- old parameter name ['transscript'] = 'transcript', -- misspelling ['transscript-format'] = 'transcript-format', -- misspelling ['transscript-url'] = 'transcript-url', -- misspelling ['transscripturl'] = 'transcript-url', -- misspelling ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['títle'] = 'title', ['título'] = 'title', -- Spanish ['ubicación'] = 'location', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urlarchivo'] = 'archive-url', -- Spanish ['urlmorto'] = 'url-status', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') ['v-authors'] = 'vauthors', -- misspelling ['v-editors'] = 'veditors', -- misspelling ['verlag'] = 'publisher', -- German ['verlagea'] = 'publisher', -- German (not a direct replacement, but can be emulated) ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['yardımcıyazarlar'] = 'author', -- Turkish ['yayımcı'] = 'publisher', -- Turkish ['yayıncı'] = 'publisher', -- Turkish ['yazar'] = 'author', -- Turkish ['yazarbağı'] = 'author-link', -- Turkish ['yer'] = 'location', -- Turkish ['yıl'] = 'date', -- Turkish ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German ['éditeur'] = 'editor', -- French ['ölüurl'] = 'url-status', -- Turkish ['übersetzer'] = 'translator', -- German (singular and plural) } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not REGEX though they are similar. The escape character is '%', not '\'. For more information about Lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', -- misspelling ['^apellido[s]?(%d+)$'] = 'last$1', -- Spanish, enumerated ['^a[utho]+r$'] = 'author', -- misspelling ['^a[utho]+r(%d+)$'] = 'author$1', -- misspelling, enumerated ['^author link(%d+)$'] = 'author-link$1', -- Polish, enumerated ['^autor[e]?(%d+)$'] = 'author$1', -- Italian/Spanish/German, enumerated ['^authorfirst(%d+)$'] = 'author-first$1', -- old parameter name, enumerated ['^author(%d+)first$'] = 'author-first$1', -- old parameter name, enumerated ['^authorgiven(%d+)$'] = 'author-given$1', -- old parameter name, enumerated ['^author(%d+)given$'] = 'author-given$1', -- old parameter name, enumerated ['^authorlast(%d+)$'] = 'author-last$1', -- old parameter name, enumerated ['^author(%d+)last$'] = 'author-last$1', -- old parameter name, enumerated ['^authormask(%d+)$'] = 'author-mask$1', -- old parameter name, enumerated ['^author(%d+)mask$'] = 'author-mask$1', -- old parameter name, enumerated ['^authorsurname(%d+)$'] = 'author-surname$1', -- old parameter name, enumerated ['^author(%d+)surname$'] = 'author-surname$1', -- old parameter name, enumerated ['^cognome(%d+)$'] = 'last$1', -- Italian, enumerated ['^editorfirst(%d+)$'] = 'editor-first$1', -- old parameter name, enumerated ['^editor(%d+)first$'] = 'editor-first$1', -- old parameter name, enumerated ['^editorgiven(%d+)$'] = 'editor-given$1', -- old parameter name, enumerated ['^editor(%d+)given$'] = 'editor-given$1', -- old parameter name, enumerated ['^editorlast(%d+)$'] = 'editor-last$1', -- old parameter name, enumerated ['^editor(%d+)last$'] = 'editor-last$1', -- old parameter name, enumerated ['^editorlink(%d+)$'] = 'editor-link$1', -- old parameter name, enumerated ['^editor(%d+)link$'] = 'editor-link$1', -- old parameter name, enumerated ['^editormask(%d+)$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editor(%d+)mask$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editorsurname(%d+)$'] = 'editor-surname$1', -- old parameter name, enumerated ['^editor(%d+)surname$'] = 'editor-surname$1', -- old parameter name, enumerated ['^enlaceautore(%d+)$'] = 'author-link$1', -- Spanish, enumerated ['^first (%d+)$'] = 'first$1', -- enumerated ['^last (%d+)$'] = 'last$1', -- enumerated ['^nom[e]?(%d+)$'] = 'last$1', -- Italian/French, enumerated ['^nombre(%d+)$'] = 'first$1', -- Spanish, enumerated ['^primero(%d+)$'] = 'first$1', -- Spanish, enumerated ['^pu[blish]+ers?$'] = 'publisher', -- misspelling ['^subjectlink(%d+)$'] = 'subject-link$1', -- old parameter name, enumerated ['^subject(%d+)link$'] = 'subject-link$1', -- old parameter name, enumerated ['^wkautore(%d+)$'] = 'author-link$1', -- Italian, enumerated } return {suggestions = suggestions, patterns=patterns}; 2ijnwqp0v6qxv0w5m0mwrt72z46ubhu 736736 736735 2026-10-07T15:16:03Z King ChristLike 13051 1 revision imported from [[:en:Module:Citation/CS1/Suggestions]] 736735 Scribunto text/plain -- Please insert new suggestions in alphabetical order -- The form is ['incorrect'] = 'correct', suggestions = { ['ASIN-TLD'] = 'asin-tld', -- old parameter name ['abruf'] = 'access-date', -- German ['abruf-verborgen'] = 'access-date', -- German ['accessmonth'] = 'access-date', ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', ['acessodata'] = 'access-date', -- Brazilian Portuguese ['ad'] = 'first', -- Turkish ['address'] = 'location', ['anno'] = 'date', -- Italian ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['annooriginale'] = 'orig-date', -- Italian ['année'] = 'date', -- French ['apellido'] = 'last', -- Spanish ['apellidos'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archiv-url'] = 'archive-url', -- German ['archive date'] = 'archive-date', -- misspelling ['archive url'] = 'archive-url', -- misspelling ['archive-link'] = 'archive-url', -- old parameter name ['archiv-url'] = 'archive-url', -- German ['arkivdatum'] = 'archive-date', -- Swedish, Norwegian ['arkivurl'] = 'archive-url', -- Swedish, Norwegian ['artist'] = 'others', ['arşiv-tarihi'] = 'archive-date', -- Turkish ['arşiv-url'] = 'archive-url', -- Turkish ['arşivtarihi'] = 'archive-date', -- Turkish ['arşivurl'] = 'archive-url', -- Turkish ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', -- misspelling ['author link'] = 'author-link', -- Polish ['authorfirst'] = 'author-first', -- old parameter name ['authorgiven'] = 'author-given', -- old parameter name ['authorlast'] = 'author-last', -- old parameter name ['authormask'] = 'author-mask', -- old parameter name ['authorsurname'] = 'author-surname', -- old parameter name ['autor'] = 'author', -- Spanish, German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', -- misspelling ['ay'] = 'month', -- Turkish ['año'] = 'date', -- Spanish ['año-original'] = 'orig-date', -- Spanish ['añoacceso'] = 'access-date', -- Spanish ['añooriginal'] = 'orig-date', -- Spanish ['band'] = 'volume', -- German ['bandreihe'] = 'volume', -- German ['baskı'] = 'edition', -- Turkish ['başlık'] = 'title', -- Turkish ['began'] = 'date', -- old parameter name (cite serial only); or orig-date= ['booktitle'] = 'book-title', -- old parameter name ['ch'] = 'language', -- German (as 'language=de-CH') ['chapter_title'] = 'chapter', ['chapterurl'] = 'chapter-url', -- old parameter name ['cid'] = 'ref', -- Italian ['cilt'] = 'volume', -- Turkish ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['città'] = 'location', -- Italian ['city'] = 'location', -- old parameter name (cite serial only) ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['conferenceurl'] = 'conference-url', -- old parameter name ['consulté le'] = 'access-date', -- French ['contributionurl'] = 'contribution-url', -- old parameter name ['curatore'] = 'publisher', -- Italian ['czasopismo'] = 'journal', -- Polish ['data dostępu'] = 'access-date', -- Polish ['data'] = 'date', -- Polish, Italian ['dataaccesso'] = 'access-date', -- Italian ['dataarchivio'] = 'archive-date', -- Italian ['datum'] = 'date', -- German, Swedish ['dead-url'] = 'url-status', -- old parameter name ['deadlink'] = 'url-status', -- old parameter name ['deadurl'] = 'url-status', -- old parameter name ['dergi'] = 'work', -- Turkish ['dil'] = 'language', -- Turkish ['displayauthors'] = 'display-authors', -- old parameter name ['displayeditors'] = 'display-editors', -- old parameter name ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') ['doi-broken'] = 'doi-broken-date', -- old parameter alias ['doi-inactive'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-inactive-date'] = 'doi-broken-date', -- old parameter alias ['doi_brokendate'] = 'doi-broken-date', -- old parameter alias ['doi_inactivedate'] = 'doi-inactive-date', -- old parameter alias ['doibroken'] = 'doi-broken-date', -- invalid name found in mainspace ['doiinactive'] = 'doi-broken-date', -- invalid name found in mainspace ['e-print'] = 'eprint', -- misspelling -- ['ed'] = 'edition', -- avoid suggestion as in English this could be short for editor or edition -- ['editora'] = 'publisher', -- can be either editor or publisher -- ['editore'] = 'agency', -- can be either publisher or agency -- ['editori'] = 'editor', -- can be either editor or publisher -- ['editorial'] = 'publisher', -- can be either publisher or work ['editoin'] = 'edition', -- misspelling ['editon'] = 'edition', -- misspelling ['editorfirst'] = 'editor-first', -- old parameter name ['editorgiven'] = 'editor-given', -- old parameter name ['editorlast'] = 'editor-last', -- old parameter name ['editorlink'] = 'editor-link', -- old parameter name ['editormask'] = 'editor-mask', -- old parameter name ['editors'] = 'editor', -- old parameter name (can be emulated using multiple singular |editor= params) ['editorsurname'] = 'editor-surname', -- old parameter name ['edizione'] = 'edition', -- Italian ['embargo'] = 'pmc-embargo-date', -- old parameter name ['ended'] = 'date', -- old parameter name (cite serial only) ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['enlaceroto'] = 'url-status', -- Spanish ['episodelink'] = 'episode-link', -- old parameter name ['erişimtarihi'] = 'access-date', -- Turkish ['eser'] = 'work', -- Turkish ['family'] = 'surname', -- misguess ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['foramt'] = 'format', -- misspelling ['fore-name'] = 'given', -- misguess/misspelling ['forename'] = 'given', -- misguess ['författare'] = 'author', -- Swedish, Norwegian ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', -- misspelling ['fundstelle'] = 'at', -- German ['gazete'] = 'work', -- Turkish ['giornale'] = 'journal', -- Italian ['hämtdatum'] = 'access-date', -- Swedish ['herausgeber'] = 'editor', -- German (singular and plural) ['hrsg'] = 'publisher', -- German ['hrsgreihe'] = 'editor', -- German ['idioma'] = 'language', -- Spanish ['ignore-isbn-error'] = 'isbn', -- old parameter (can be fully emulated using ((syntax))) ['ignoreisbnerror'] = 'isbn', -- old parameter alias (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['imię'] = 'first', -- Polish ['in-set'] = 'inset', -- misspelling ['interviewerlink'] = 'interviewer-link', -- old parameter alias ['interviewermask'] = 'interviewer-mask', -- old parameter alias ['isbndefekt'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnistformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isnb'] = 'isbn', -- misspelling ['issnformalfalsch'] = 'issn', -- German (can be fully emulated using ((syntax))) ['jahr'] = 'date', -- German ['jahrea'] = 'orig-date', -- German (not a direct replacement, but can be emulated) ['kapitel'] = 'chapter', -- German ['langauge'] = 'language', -- misspelling ['langue'] = 'language', -- French ['last-author-amp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['lastauthoramp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License No. ...') ['loaction'] = 'location', -- misspelling ['local'] = 'location', -- Brazilian Portuguese ['locatoin'] = 'location', -- misspelling ['lugar'] = 'location', -- Spanish ['mailinglist'] = 'mailing-list', -- old parameter name ['mapurl'] = 'map-url', -- old parameter name ['mes'] = 'date', -- Spanish (not a direct replacement) ['mese'] = 'date', -- Italian (not a direct replacement) ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['name-list-format'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', -- misspelling ['net-work'] = 'network', -- misspelling ['newpaper'] = 'newspaper', -- misspelling ['news'] = 'newspaper', ['news-group'] = 'newsgroup', -- misspelling ['news-paper'] = 'newspaper', -- misspelling ['no-cat'] = 'no-tracking', -- old parameter ['nocat'] = 'no-tracking', -- old parameter ['nom'] = 'last', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['nopp'] = 'no-pp', -- old parameter name ['notracking'] = 'no-tracking', -- old parameter ['numero'] = 'number', -- Italian, Spanish ['nummer'] = 'number', -- German ['nummerreihe'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'url-status', -- German (as 'url-status=dead') ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opera'] = 'work', -- Italian ['opublikowany'] = 'agency', -- Polish ['origdate'] = 'orig-date', -- misspelling ['originaljahr'] = 'orig-date', -- German ['originalort'] = 'publication-place', -- German ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'publication-place', -- German ['ortea'] = 'publication-place', -- German (not a direct replacement, but can be emulated) ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', -- misspelling ['pagina'] = 'page', -- Italian ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['passage'] = 'pages', -- French ['periodico'] = 'magazine', -- Spanish ['plublisher'] = 'publisher', -- misspelling ['pmcid'] = 'pmc', ['post-script'] = 'postscript', -- misspelling ['praca'] = 'work', -- Polish ['primero'] = 'first', -- Spanish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubblicazione'] = 'magazine', -- could be any kind of work -- ['publicación'] = 'journal', -- could be any kind of work ['publicationdate'] = 'publication-date', -- old parameter name -- ['published'] = 'publisher', -- could be date, location, or name of publisher ['publicationplace'] = 'publication-place', -- old parameter name ['pulbication-place'] = 'publication-place', -- misspelling ['página'] = 'page', -- Spanish ['páginas'] = 'pages', -- Spanish ['périodique'] = 'publisher', -- French ['registration'] = 'url-access', -- old parameter name ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', -- old parameter name ['richiestasottoscrizione'] = 'url-access', -- Italian (as |url-access=subscription) ['rivista'] = 'magazine', -- Italian ['rok'] = 'date', -- Polish ['rubrik'] = 'title', -- Swedish ['sammelwerk'] = 'work', -- German ['sayfa'] = 'page', -- Turkish ['sayfalar'] = 'pages', -- Turkish ['sayı'] = 'issue', -- Turkish ['script-post'] = 'postscript', -- misspelling ['script-trans'] = 'transcript', -- misspelling ['season'] = 'date', -- old parameter name (cite serial only) ['sectionurl'] = 'section-url', -- old parameter name ['seiten'] = 'pages', -- German ['seria'] = 'series', -- Spanish, Polish ['serie'] = 'series', -- Italian ['série'] = 'series', -- French ['serieslink'] = 'series-link', -- old parameter name ['seriesno'] = 'series-number', -- old parameter name ['service'] = 'agency', ['sitioweb'] = 'website', -- Spanish ['sito'] = 'website', -- Italian ['soyadı'] = 'last', -- Turkish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['språk'] = 'language', -- Swedish, Norwegian ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['subjectlink'] = 'subject-link', -- old parameter name ['subscription'] = 'url-access', -- old parameter name (emulated as |url-access=subscription) ['sur-name'] = 'surname', -- misspelling ['suscripción'] = 'url-access', -- Spanish, Polish (as |url-access=subscription) ['tag'] = 'date', -- German ['tarih'] = 'date', -- Turkish ['template doc demo'] = 'no-tracking', -- old parameter alias ['tidning'] = 'work', -- Swedish ['tile'] = 'title', -- misspelling ['timecaption'] = 'time-caption', -- old parameter name ['titlelink'] = 'title-link', -- old parameter name ['tipo'] = 'type', -- Italian ['tite'] = 'title', -- misspelling ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titled'] = 'title', -- Brazilian Portuguese ['titolo'] = 'title', -- Italian ['titre'] = 'title', -- French ['trans-script'] = 'transcript', -- misspelling ['trans_chapter'] = 'trans-chapter', -- old parameter alias ['trans_title'] = 'trans-title', -- old parameter alias ['transchapter'] = 'trans-chapter', ['transcripturl'] = 'transcript-url', -- old parameter name ['transscript'] = 'transcript', -- misspelling ['transscript-format'] = 'transcript-format', -- misspelling ['transscript-url'] = 'transcript-url', -- misspelling ['transscripturl'] = 'transcript-url', -- misspelling ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['títle'] = 'title', ['título'] = 'title', -- Spanish ['ubicación'] = 'location', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urlarchivo'] = 'archive-url', -- Spanish ['urlmorto'] = 'url-status', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') ['v-authors'] = 'vauthors', -- misspelling ['v-editors'] = 'veditors', -- misspelling ['verlag'] = 'publisher', -- German ['verlagea'] = 'publisher', -- German (not a direct replacement, but can be emulated) ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['yardımcıyazarlar'] = 'author', -- Turkish ['yayımcı'] = 'publisher', -- Turkish ['yayıncı'] = 'publisher', -- Turkish ['yazar'] = 'author', -- Turkish ['yazarbağı'] = 'author-link', -- Turkish ['yer'] = 'location', -- Turkish ['yıl'] = 'date', -- Turkish ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German ['éditeur'] = 'editor', -- French ['ölüurl'] = 'url-status', -- Turkish ['übersetzer'] = 'translator', -- German (singular and plural) } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not REGEX though they are similar. The escape character is '%', not '\'. For more information about Lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', -- misspelling ['^apellido[s]?(%d+)$'] = 'last$1', -- Spanish, enumerated ['^a[utho]+r$'] = 'author', -- misspelling ['^a[utho]+r(%d+)$'] = 'author$1', -- misspelling, enumerated ['^author link(%d+)$'] = 'author-link$1', -- Polish, enumerated ['^autor[e]?(%d+)$'] = 'author$1', -- Italian/Spanish/German, enumerated ['^authorfirst(%d+)$'] = 'author-first$1', -- old parameter name, enumerated ['^author(%d+)first$'] = 'author-first$1', -- old parameter name, enumerated ['^authorgiven(%d+)$'] = 'author-given$1', -- old parameter name, enumerated ['^author(%d+)given$'] = 'author-given$1', -- old parameter name, enumerated ['^authorlast(%d+)$'] = 'author-last$1', -- old parameter name, enumerated ['^author(%d+)last$'] = 'author-last$1', -- old parameter name, enumerated ['^authormask(%d+)$'] = 'author-mask$1', -- old parameter name, enumerated ['^author(%d+)mask$'] = 'author-mask$1', -- old parameter name, enumerated ['^authorsurname(%d+)$'] = 'author-surname$1', -- old parameter name, enumerated ['^author(%d+)surname$'] = 'author-surname$1', -- old parameter name, enumerated ['^cognome(%d+)$'] = 'last$1', -- Italian, enumerated ['^editorfirst(%d+)$'] = 'editor-first$1', -- old parameter name, enumerated ['^editor(%d+)first$'] = 'editor-first$1', -- old parameter name, enumerated ['^editorgiven(%d+)$'] = 'editor-given$1', -- old parameter name, enumerated ['^editor(%d+)given$'] = 'editor-given$1', -- old parameter name, enumerated ['^editorlast(%d+)$'] = 'editor-last$1', -- old parameter name, enumerated ['^editor(%d+)last$'] = 'editor-last$1', -- old parameter name, enumerated ['^editorlink(%d+)$'] = 'editor-link$1', -- old parameter name, enumerated ['^editor(%d+)link$'] = 'editor-link$1', -- old parameter name, enumerated ['^editormask(%d+)$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editor(%d+)mask$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editorsurname(%d+)$'] = 'editor-surname$1', -- old parameter name, enumerated ['^editor(%d+)surname$'] = 'editor-surname$1', -- old parameter name, enumerated ['^enlaceautore(%d+)$'] = 'author-link$1', -- Spanish, enumerated ['^first (%d+)$'] = 'first$1', -- enumerated ['^last (%d+)$'] = 'last$1', -- enumerated ['^nom[e]?(%d+)$'] = 'last$1', -- Italian/French, enumerated ['^nombre(%d+)$'] = 'first$1', -- Spanish, enumerated ['^primero(%d+)$'] = 'first$1', -- Spanish, enumerated ['^pu[blish]+ers?$'] = 'publisher', -- misspelling ['^subjectlink(%d+)$'] = 'subject-link$1', -- old parameter name, enumerated ['^subject(%d+)link$'] = 'subject-link$1', -- old parameter name, enumerated ['^wkautore(%d+)$'] = 'author-link$1', -- Italian, enumerated } return {suggestions = suggestions, patterns=patterns}; 2ijnwqp0v6qxv0w5m0mwrt72z46ubhu 736739 2016-03-13T16:17:15Z RussBot 522 Bot: Fixing double redirect to [[Help talk:Citation Style 1]] 736739 wikitext text/x-wiki #REDIRECT [[Help talk:Citation Style 1]] n56v5kja3y9wbb138wdgaw81sdske3d 736740 736736 2026-10-07T15:16:04Z King ChristLike 13051 1 revision imported from [[:en:Module_talk:Citation/CS1/Suggestions]] 736735 Scribunto text/plain -- Please insert new suggestions in alphabetical order -- The form is ['incorrect'] = 'correct', suggestions = { ['ASIN-TLD'] = 'asin-tld', -- old parameter name ['abruf'] = 'access-date', -- German ['abruf-verborgen'] = 'access-date', -- German ['accessmonth'] = 'access-date', ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', ['acessodata'] = 'access-date', -- Brazilian Portuguese ['ad'] = 'first', -- Turkish ['address'] = 'location', ['anno'] = 'date', -- Italian ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['annooriginale'] = 'orig-date', -- Italian ['année'] = 'date', -- French ['apellido'] = 'last', -- Spanish ['apellidos'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archiv-url'] = 'archive-url', -- German ['archive date'] = 'archive-date', -- misspelling ['archive url'] = 'archive-url', -- misspelling ['archive-link'] = 'archive-url', -- old parameter name ['archiv-url'] = 'archive-url', -- German ['arkivdatum'] = 'archive-date', -- Swedish, Norwegian ['arkivurl'] = 'archive-url', -- Swedish, Norwegian ['artist'] = 'others', ['arşiv-tarihi'] = 'archive-date', -- Turkish ['arşiv-url'] = 'archive-url', -- Turkish ['arşivtarihi'] = 'archive-date', -- Turkish ['arşivurl'] = 'archive-url', -- Turkish ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', -- misspelling ['author link'] = 'author-link', -- Polish ['authorfirst'] = 'author-first', -- old parameter name ['authorgiven'] = 'author-given', -- old parameter name ['authorlast'] = 'author-last', -- old parameter name ['authormask'] = 'author-mask', -- old parameter name ['authorsurname'] = 'author-surname', -- old parameter name ['autor'] = 'author', -- Spanish, German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', -- misspelling ['ay'] = 'month', -- Turkish ['año'] = 'date', -- Spanish ['año-original'] = 'orig-date', -- Spanish ['añoacceso'] = 'access-date', -- Spanish ['añooriginal'] = 'orig-date', -- Spanish ['band'] = 'volume', -- German ['bandreihe'] = 'volume', -- German ['baskı'] = 'edition', -- Turkish ['başlık'] = 'title', -- Turkish ['began'] = 'date', -- old parameter name (cite serial only); or orig-date= ['booktitle'] = 'book-title', -- old parameter name ['ch'] = 'language', -- German (as 'language=de-CH') ['chapter_title'] = 'chapter', ['chapterurl'] = 'chapter-url', -- old parameter name ['cid'] = 'ref', -- Italian ['cilt'] = 'volume', -- Turkish ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['città'] = 'location', -- Italian ['city'] = 'location', -- old parameter name (cite serial only) ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['conferenceurl'] = 'conference-url', -- old parameter name ['consulté le'] = 'access-date', -- French ['contributionurl'] = 'contribution-url', -- old parameter name ['curatore'] = 'publisher', -- Italian ['czasopismo'] = 'journal', -- Polish ['data dostępu'] = 'access-date', -- Polish ['data'] = 'date', -- Polish, Italian ['dataaccesso'] = 'access-date', -- Italian ['dataarchivio'] = 'archive-date', -- Italian ['datum'] = 'date', -- German, Swedish ['dead-url'] = 'url-status', -- old parameter name ['deadlink'] = 'url-status', -- old parameter name ['deadurl'] = 'url-status', -- old parameter name ['dergi'] = 'work', -- Turkish ['dil'] = 'language', -- Turkish ['displayauthors'] = 'display-authors', -- old parameter name ['displayeditors'] = 'display-editors', -- old parameter name ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') ['doi-broken'] = 'doi-broken-date', -- old parameter alias ['doi-inactive'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-inactive-date'] = 'doi-broken-date', -- old parameter alias ['doi_brokendate'] = 'doi-broken-date', -- old parameter alias ['doi_inactivedate'] = 'doi-inactive-date', -- old parameter alias ['doibroken'] = 'doi-broken-date', -- invalid name found in mainspace ['doiinactive'] = 'doi-broken-date', -- invalid name found in mainspace ['e-print'] = 'eprint', -- misspelling -- ['ed'] = 'edition', -- avoid suggestion as in English this could be short for editor or edition -- ['editora'] = 'publisher', -- can be either editor or publisher -- ['editore'] = 'agency', -- can be either publisher or agency -- ['editori'] = 'editor', -- can be either editor or publisher -- ['editorial'] = 'publisher', -- can be either publisher or work ['editoin'] = 'edition', -- misspelling ['editon'] = 'edition', -- misspelling ['editorfirst'] = 'editor-first', -- old parameter name ['editorgiven'] = 'editor-given', -- old parameter name ['editorlast'] = 'editor-last', -- old parameter name ['editorlink'] = 'editor-link', -- old parameter name ['editormask'] = 'editor-mask', -- old parameter name ['editors'] = 'editor', -- old parameter name (can be emulated using multiple singular |editor= params) ['editorsurname'] = 'editor-surname', -- old parameter name ['edizione'] = 'edition', -- Italian ['embargo'] = 'pmc-embargo-date', -- old parameter name ['ended'] = 'date', -- old parameter name (cite serial only) ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['enlaceroto'] = 'url-status', -- Spanish ['episodelink'] = 'episode-link', -- old parameter name ['erişimtarihi'] = 'access-date', -- Turkish ['eser'] = 'work', -- Turkish ['family'] = 'surname', -- misguess ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['foramt'] = 'format', -- misspelling ['fore-name'] = 'given', -- misguess/misspelling ['forename'] = 'given', -- misguess ['författare'] = 'author', -- Swedish, Norwegian ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', -- misspelling ['fundstelle'] = 'at', -- German ['gazete'] = 'work', -- Turkish ['giornale'] = 'journal', -- Italian ['hämtdatum'] = 'access-date', -- Swedish ['herausgeber'] = 'editor', -- German (singular and plural) ['hrsg'] = 'publisher', -- German ['hrsgreihe'] = 'editor', -- German ['idioma'] = 'language', -- Spanish ['ignore-isbn-error'] = 'isbn', -- old parameter (can be fully emulated using ((syntax))) ['ignoreisbnerror'] = 'isbn', -- old parameter alias (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['imię'] = 'first', -- Polish ['in-set'] = 'inset', -- misspelling ['interviewerlink'] = 'interviewer-link', -- old parameter alias ['interviewermask'] = 'interviewer-mask', -- old parameter alias ['isbndefekt'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnistformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isnb'] = 'isbn', -- misspelling ['issnformalfalsch'] = 'issn', -- German (can be fully emulated using ((syntax))) ['jahr'] = 'date', -- German ['jahrea'] = 'orig-date', -- German (not a direct replacement, but can be emulated) ['kapitel'] = 'chapter', -- German ['langauge'] = 'language', -- misspelling ['langue'] = 'language', -- French ['last-author-amp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['lastauthoramp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License No. ...') ['loaction'] = 'location', -- misspelling ['local'] = 'location', -- Brazilian Portuguese ['locatoin'] = 'location', -- misspelling ['lugar'] = 'location', -- Spanish ['mailinglist'] = 'mailing-list', -- old parameter name ['mapurl'] = 'map-url', -- old parameter name ['mes'] = 'date', -- Spanish (not a direct replacement) ['mese'] = 'date', -- Italian (not a direct replacement) ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['name-list-format'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', -- misspelling ['net-work'] = 'network', -- misspelling ['newpaper'] = 'newspaper', -- misspelling ['news'] = 'newspaper', ['news-group'] = 'newsgroup', -- misspelling ['news-paper'] = 'newspaper', -- misspelling ['no-cat'] = 'no-tracking', -- old parameter ['nocat'] = 'no-tracking', -- old parameter ['nom'] = 'last', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['nopp'] = 'no-pp', -- old parameter name ['notracking'] = 'no-tracking', -- old parameter ['numero'] = 'number', -- Italian, Spanish ['nummer'] = 'number', -- German ['nummerreihe'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'url-status', -- German (as 'url-status=dead') ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opera'] = 'work', -- Italian ['opublikowany'] = 'agency', -- Polish ['origdate'] = 'orig-date', -- misspelling ['originaljahr'] = 'orig-date', -- German ['originalort'] = 'publication-place', -- German ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'publication-place', -- German ['ortea'] = 'publication-place', -- German (not a direct replacement, but can be emulated) ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', -- misspelling ['pagina'] = 'page', -- Italian ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['passage'] = 'pages', -- French ['periodico'] = 'magazine', -- Spanish ['plublisher'] = 'publisher', -- misspelling ['pmcid'] = 'pmc', ['post-script'] = 'postscript', -- misspelling ['praca'] = 'work', -- Polish ['primero'] = 'first', -- Spanish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubblicazione'] = 'magazine', -- could be any kind of work -- ['publicación'] = 'journal', -- could be any kind of work ['publicationdate'] = 'publication-date', -- old parameter name -- ['published'] = 'publisher', -- could be date, location, or name of publisher ['publicationplace'] = 'publication-place', -- old parameter name ['pulbication-place'] = 'publication-place', -- misspelling ['página'] = 'page', -- Spanish ['páginas'] = 'pages', -- Spanish ['périodique'] = 'publisher', -- French ['registration'] = 'url-access', -- old parameter name ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', -- old parameter name ['richiestasottoscrizione'] = 'url-access', -- Italian (as |url-access=subscription) ['rivista'] = 'magazine', -- Italian ['rok'] = 'date', -- Polish ['rubrik'] = 'title', -- Swedish ['sammelwerk'] = 'work', -- German ['sayfa'] = 'page', -- Turkish ['sayfalar'] = 'pages', -- Turkish ['sayı'] = 'issue', -- Turkish ['script-post'] = 'postscript', -- misspelling ['script-trans'] = 'transcript', -- misspelling ['season'] = 'date', -- old parameter name (cite serial only) ['sectionurl'] = 'section-url', -- old parameter name ['seiten'] = 'pages', -- German ['seria'] = 'series', -- Spanish, Polish ['serie'] = 'series', -- Italian ['série'] = 'series', -- French ['serieslink'] = 'series-link', -- old parameter name ['seriesno'] = 'series-number', -- old parameter name ['service'] = 'agency', ['sitioweb'] = 'website', -- Spanish ['sito'] = 'website', -- Italian ['soyadı'] = 'last', -- Turkish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['språk'] = 'language', -- Swedish, Norwegian ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['subjectlink'] = 'subject-link', -- old parameter name ['subscription'] = 'url-access', -- old parameter name (emulated as |url-access=subscription) ['sur-name'] = 'surname', -- misspelling ['suscripción'] = 'url-access', -- Spanish, Polish (as |url-access=subscription) ['tag'] = 'date', -- German ['tarih'] = 'date', -- Turkish ['template doc demo'] = 'no-tracking', -- old parameter alias ['tidning'] = 'work', -- Swedish ['tile'] = 'title', -- misspelling ['timecaption'] = 'time-caption', -- old parameter name ['titlelink'] = 'title-link', -- old parameter name ['tipo'] = 'type', -- Italian ['tite'] = 'title', -- misspelling ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titled'] = 'title', -- Brazilian Portuguese ['titolo'] = 'title', -- Italian ['titre'] = 'title', -- French ['trans-script'] = 'transcript', -- misspelling ['trans_chapter'] = 'trans-chapter', -- old parameter alias ['trans_title'] = 'trans-title', -- old parameter alias ['transchapter'] = 'trans-chapter', ['transcripturl'] = 'transcript-url', -- old parameter name ['transscript'] = 'transcript', -- misspelling ['transscript-format'] = 'transcript-format', -- misspelling ['transscript-url'] = 'transcript-url', -- misspelling ['transscripturl'] = 'transcript-url', -- misspelling ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['títle'] = 'title', ['título'] = 'title', -- Spanish ['ubicación'] = 'location', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urlarchivo'] = 'archive-url', -- Spanish ['urlmorto'] = 'url-status', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') ['v-authors'] = 'vauthors', -- misspelling ['v-editors'] = 'veditors', -- misspelling ['verlag'] = 'publisher', -- German ['verlagea'] = 'publisher', -- German (not a direct replacement, but can be emulated) ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['yardımcıyazarlar'] = 'author', -- Turkish ['yayımcı'] = 'publisher', -- Turkish ['yayıncı'] = 'publisher', -- Turkish ['yazar'] = 'author', -- Turkish ['yazarbağı'] = 'author-link', -- Turkish ['yer'] = 'location', -- Turkish ['yıl'] = 'date', -- Turkish ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German ['éditeur'] = 'editor', -- French ['ölüurl'] = 'url-status', -- Turkish ['übersetzer'] = 'translator', -- German (singular and plural) } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not REGEX though they are similar. The escape character is '%', not '\'. For more information about Lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', -- misspelling ['^apellido[s]?(%d+)$'] = 'last$1', -- Spanish, enumerated ['^a[utho]+r$'] = 'author', -- misspelling ['^a[utho]+r(%d+)$'] = 'author$1', -- misspelling, enumerated ['^author link(%d+)$'] = 'author-link$1', -- Polish, enumerated ['^autor[e]?(%d+)$'] = 'author$1', -- Italian/Spanish/German, enumerated ['^authorfirst(%d+)$'] = 'author-first$1', -- old parameter name, enumerated ['^author(%d+)first$'] = 'author-first$1', -- old parameter name, enumerated ['^authorgiven(%d+)$'] = 'author-given$1', -- old parameter name, enumerated ['^author(%d+)given$'] = 'author-given$1', -- old parameter name, enumerated ['^authorlast(%d+)$'] = 'author-last$1', -- old parameter name, enumerated ['^author(%d+)last$'] = 'author-last$1', -- old parameter name, enumerated ['^authormask(%d+)$'] = 'author-mask$1', -- old parameter name, enumerated ['^author(%d+)mask$'] = 'author-mask$1', -- old parameter name, enumerated ['^authorsurname(%d+)$'] = 'author-surname$1', -- old parameter name, enumerated ['^author(%d+)surname$'] = 'author-surname$1', -- old parameter name, enumerated ['^cognome(%d+)$'] = 'last$1', -- Italian, enumerated ['^editorfirst(%d+)$'] = 'editor-first$1', -- old parameter name, enumerated ['^editor(%d+)first$'] = 'editor-first$1', -- old parameter name, enumerated ['^editorgiven(%d+)$'] = 'editor-given$1', -- old parameter name, enumerated ['^editor(%d+)given$'] = 'editor-given$1', -- old parameter name, enumerated ['^editorlast(%d+)$'] = 'editor-last$1', -- old parameter name, enumerated ['^editor(%d+)last$'] = 'editor-last$1', -- old parameter name, enumerated ['^editorlink(%d+)$'] = 'editor-link$1', -- old parameter name, enumerated ['^editor(%d+)link$'] = 'editor-link$1', -- old parameter name, enumerated ['^editormask(%d+)$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editor(%d+)mask$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editorsurname(%d+)$'] = 'editor-surname$1', -- old parameter name, enumerated ['^editor(%d+)surname$'] = 'editor-surname$1', -- old parameter name, enumerated ['^enlaceautore(%d+)$'] = 'author-link$1', -- Spanish, enumerated ['^first (%d+)$'] = 'first$1', -- enumerated ['^last (%d+)$'] = 'last$1', -- enumerated ['^nom[e]?(%d+)$'] = 'last$1', -- Italian/French, enumerated ['^nombre(%d+)$'] = 'first$1', -- Spanish, enumerated ['^primero(%d+)$'] = 'first$1', -- Spanish, enumerated ['^pu[blish]+ers?$'] = 'publisher', -- misspelling ['^subjectlink(%d+)$'] = 'subject-link$1', -- old parameter name, enumerated ['^subject(%d+)link$'] = 'subject-link$1', -- old parameter name, enumerated ['^wkautore(%d+)$'] = 'author-link$1', -- Italian, enumerated } return {suggestions = suggestions, patterns=patterns}; 2ijnwqp0v6qxv0w5m0mwrt72z46ubhu 736741 2013-04-07T21:02:47Z en>Dragons flight 0 [[WP:AES|←]]Created page with 'suggestions = { ['accessed'] = 'accessdate', ['accesdate'] = 'accessdate', ['acessdate'] = 'accessdate', } return suggestions;' 736741 Scribunto text/plain suggestions = { ['accessed'] = 'accessdate', ['accesdate'] = 'accessdate', ['acessdate'] = 'accessdate', } return suggestions; dyihgqm539rbnvvvds3fials1r2xmxm 736742 736741 2013-04-08T15:18:07Z en>Dragons flight 0 other examples from talk 736742 Scribunto text/plain suggestions = { ['accessed'] = 'accessdate', ['accesdate'] = 'accessdate', ['acessdate'] = 'accessdate', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', ['locatoin'] = 'location', ['loaction'] = 'location', } return suggestions; 30z0gi1kehaxfl4uohujplgl518wrsp 736743 736742 2013-04-09T16:04:48Z en>Trappist the monk 0 736743 Scribunto text/plain --Please insert new suggestions in alphabetical order suggestions = { ['accessed'] = 'accessdate', ['accesdate'] = 'accessdate', ['acessdate'] = 'accessdate', ['loaction'] = 'location', ['locatoin'] = 'location', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', } return suggestions; 5i2xlu71i2ixzjrcjzqtc94c5i7owsq 736744 736743 2013-04-09T16:06:16Z en>Trappist the monk 0 follow my own request; 736744 Scribunto text/plain --Please insert new suggestions in alphabetical order suggestions = { ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['loaction'] = 'location', ['locatoin'] = 'location', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', } return suggestions; ndhh0r2ia2pe9gvqlw6npw0sdmmekio 736745 736744 2013-04-10T01:00:27Z en>Trappist the monk 0 +1 736745 Scribunto text/plain --Please insert new suggestions in alphabetical order suggestions = { ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['autthor'] = 'author', ['loaction'] = 'location', ['locatoin'] = 'location', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', } return suggestions; ppqyoacu371erj5vew1lm356jk9f665 736746 736745 2013-04-13T23:49:02Z en>Dragons flight 0 plus one 736746 Scribunto text/plain --Please insert new suggestions in alphabetical order suggestions = { ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['autthor'] = 'author', ['loaction'] = 'location', ['locatoin'] = 'location', ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', } return suggestions; 9rpsirzd3e72rv5dxvkep39hdfp06bo 736747 736746 2013-04-16T15:16:00Z en>Trappist the monk 0 Move deprecated parameter 'access-date' from configuration; 736747 Scribunto text/plain --Please insert new suggestions in alphabetical order suggestions = { ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['access-date'] = 'accessdate', --deprecated parameter ['autthor'] = 'author', ['loaction'] = 'location', ['locatoin'] = 'location', ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', } return suggestions; fd2wgaxtfxhu51vwrozssa1c6il3ej1 736748 736747 2013-07-01T00:56:06Z en>Gadget850 0 acces date 736748 Scribunto text/plain --Please insert new suggestions in alphabetical order suggestions = { ['acces date'] = 'accessdate', ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['access-date'] = 'accessdate', --deprecated parameter ['autthor'] = 'author', ['loaction'] = 'location', ['locatoin'] = 'location', ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', } return suggestions; imle8hilmnu3jx4mjvovigvjmt3m7sk 736749 736748 2013-07-01T00:57:32Z en>Gadget850 0 access date 736749 Scribunto text/plain --Please insert new suggestions in alphabetical order suggestions = { ['access date'] = 'accessdate', ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['access-date'] = 'accessdate', --deprecated parameter ['autthor'] = 'author', ['loaction'] = 'location', ['locatoin'] = 'location', ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', } return suggestions; 8go2tfmp3xp948hf3vj6j3nibe9q5u2 736750 736749 2013-07-19T15:15:19Z en>Trappist the monk 0 736750 Scribunto text/plain --Please insert new suggestions in alphabetical order suggestions = { ['access date'] = 'accessdate', ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['access-date'] = 'accessdate', --deprecated parameter ['autthor'] = 'author', ['loaction'] = 'location', ['locatoin'] = 'location', ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', ['transtitle'] = 'trans-title', } return suggestions; 776iba71txev9zvmqbfdadxcml9e3ff 736751 736750 2013-08-18T13:50:37Z en>Trappist the monk 0 Add transchapter / trans-chapter; 736751 Scribunto text/plain --Please insert new suggestions in alphabetical order suggestions = { ['access date'] = 'accessdate', ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['access-date'] = 'accessdate', --deprecated parameter ['autthor'] = 'author', ['loaction'] = 'location', ['locatoin'] = 'location', ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', ['transchapter'] = 'trans-chapter', ['transtitle'] = 'trans-title', } return suggestions; dwhfpg1uggirpbxygcl5ul2d2nk7x9n 736752 736751 2013-08-18T14:03:47Z en>Trappist the monk 0 Add help text; 736752 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['access date'] = 'accessdate', ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['access-date'] = 'accessdate', --deprecated parameter ['autthor'] = 'author', ['loaction'] = 'location', ['locatoin'] = 'location', ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', ['transchapter'] = 'trans-chapter', ['transtitle'] = 'trans-title', } return suggestions; 0bm25ltjc3nsp22env9vf9215stv3pt 736753 736752 2013-11-06T14:09:57Z en>Eyesnore 0 +suggestion 736753 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['access date'] = 'accessdate', ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['access-date'] = 'accessdate', --deprecated parameter ['autthor'] = 'author', ['loaction'] = 'location', ['locatoin'] = 'location', ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['origmonth'] = 'origyear', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', ['transchapter'] = 'trans-chapter', ['transtitle'] = 'trans-title', } return suggestions; djrhzwyyah0zzapqct1td9n5df6tipy 736754 736753 2013-12-01T04:14:08Z en>Jonesey95 0 Adding some parameter misspellings I have seen in [[Category:Pages with citations using unsupported parameters]] 736754 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['access date'] = 'accessdate', ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['access-date'] = 'accessdate', --deprecated parameter ['auther'] = 'author', ['autthor'] = 'author', ['editorial'] = 'publisher', -- "editorial" is Spanish for "publisher" ['loaction'] = 'location', ['locatoin'] = 'location', ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['origmonth'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', } return suggestions; eynn6491h13w5eo3pmsyms58620met4 736755 736754 2013-12-01T04:22:44Z en>Jonesey95 0 Adding some parameter misspellings I have seen in [[Category:Pages with citations using unsupported parameters]] 736755 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['access date'] = 'accessdate', ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['access-date'] = 'accessdate', --deprecated parameter ['address'] = 'location', ['auther'] = 'author', ['autthor'] = 'author', ['editorial'] = 'publisher', -- "editorial" is Spanish for "publisher" ['loaction'] = 'location', ['locatoin'] = 'location', ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['origmonth'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', } return suggestions; fv15w7lyupvjx8zuh9yeb3dt0mp4mmf 736756 736755 2013-12-08T18:44:42Z en>GoingBatty 0 removed 'orignmonth' - sometimes it should be 'month' instead of 'origyear' 736756 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['access date'] = 'accessdate', ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['access-date'] = 'accessdate', --deprecated parameter ['address'] = 'location', ['auther'] = 'author', ['autthor'] = 'author', ['editorial'] = 'publisher', -- "editorial" is Spanish for "publisher" ['loaction'] = 'location', ['locatoin'] = 'location', ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', } return suggestions; pabcf1v7fo4udm0ziyuqo21abj1z1id 736757 736756 2013-12-13T23:27:14Z en>Jonesey95 0 adding 'distributor' 736757 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['access date'] = 'accessdate', ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['access-date'] = 'accessdate', --deprecated parameter ['address'] = 'location', ['auther'] = 'author', ['autthor'] = 'author', ['distributor'] = 'publisher', ['editorial'] = 'publisher', -- "editorial" is Spanish for "publisher" ['loaction'] = 'location', ['locatoin'] = 'location', ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', } return suggestions; l6l1mxmelkgzzv0nh8rq9r2n5mx84e5 736758 736757 2014-04-01T15:18:45Z en>Jonesey95 0 add "tile" 736758 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['access date'] = 'accessdate', ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['access-date'] = 'accessdate', --deprecated parameter ['address'] = 'location', ['auther'] = 'author', ['autthor'] = 'author', ['distributor'] = 'publisher', ['editorial'] = 'publisher', -- "editorial" is Spanish for "publisher" ['loaction'] = 'location', ['locatoin'] = 'location', ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', ['tile'] = 'title', ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', } return suggestions; kck07b9c5p6gmx80gkwh4la42i8z6l5 736759 736758 2014-04-08T18:18:26Z en>Jonesey95 0 adding a few 736759 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['access date'] = 'accessdate', ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['access-date'] = 'accessdate', --deprecated parameter ['address'] = 'location', ['auther'] = 'author', ['autthor'] = 'author', ['distributor'] = 'publisher', ['editorial'] = 'publisher', -- "editorial" is Spanish for "publisher" ['filetype'] = 'format', ['foramt'] = 'format', ['frist'] = 'first', ['loaction'] = 'location', ['locatoin'] = 'location', ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', ['service'] = 'agency', ['tile'] = 'title', ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', } return suggestions; gywb8e9gn2es36ocvwdtyusyjfndljj 736760 736759 2014-04-14T21:28:49Z en>Gadget850 0 lang 736760 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['access date'] = 'accessdate', ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['access-date'] = 'accessdate', --deprecated parameter ['address'] = 'location', ['auther'] = 'author', ['autthor'] = 'author', ['distributor'] = 'publisher', ['editorial'] = 'publisher', -- "editorial" is Spanish for "publisher" ['filetype'] = 'format', ['foramt'] = 'format', ['frist'] = 'first', ['lang'] = 'language', ['loaction'] = 'location', ['locatoin'] = 'location', ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', ['service'] = 'agency', ['tile'] = 'title', ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', } return suggestions; gcgeuguhpn84bfqs2m0m1g98fr5zim6 736761 736760 2014-04-14T22:03:24Z en>Jonesey95 0 adding "pub", which I have found in a few articles 736761 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['access date'] = 'accessdate', ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['access-date'] = 'accessdate', --deprecated parameter ['address'] = 'location', ['auther'] = 'author', ['autthor'] = 'author', ['distributor'] = 'publisher', ['editorial'] = 'publisher', -- "editorial" is Spanish for "publisher" ['filetype'] = 'format', ['foramt'] = 'format', ['frist'] = 'first', ['lang'] = 'language', ['loaction'] = 'location', ['locatoin'] = 'location', ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['pub'] = 'publisher', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', ['service'] = 'agency', ['tile'] = 'title', ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', } return suggestions; 68kp68tmtgya6mdrz8pul1gx9peubpm 736762 736761 2014-05-30T17:11:40Z en>D'Ranged 1 0 added deprecated parameters to the list so that a more specific error message is shown 736762 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['access date'] = 'accessdate', ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['access-date'] = 'accessdate', --deprecated parameter ['address'] = 'location', ['auther'] = 'author', ['autthor'] = 'author', ['coauthors'] = 'authors', -- deprecated paramater ['day'] = 'date', -- deprecated parameter ['distributor'] = 'publisher', ['editorial'] = 'publisher', -- "editorial" is Spanish for "publisher" ['filetype'] = 'format', ['foramt'] = 'format', ['frist'] = 'first', ['lang'] = 'language', ['loaction'] = 'location', ['locatoin'] = 'location', ['month'] = 'date', -- deprecated parameter ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['pub'] = 'publisher', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', ['service'] = 'agency', ['tile'] = 'title', ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', } return suggestions; jdoc2xpuo6jlns1ng2c5ggmwgvsvdnn 736763 736762 2014-05-30T19:20:46Z en>Jonesey95 0 Undid revision 610814123 by [[Special:Contributions/D'Ranged 1|D'Ranged 1]] ([[User talk:D'Ranged 1|talk]]). These suggestions display only for unsupported parameters. Create test citations using month/coauthors to see that there is no suggestion. 736763 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['access date'] = 'accessdate', ['accesdate'] = 'accessdate', ['accessed'] = 'accessdate', ['acessdate'] = 'accessdate', ['access-date'] = 'accessdate', --deprecated parameter ['address'] = 'location', ['auther'] = 'author', ['autthor'] = 'author', ['distributor'] = 'publisher', ['editorial'] = 'publisher', -- "editorial" is Spanish for "publisher" ['filetype'] = 'format', ['foramt'] = 'format', ['frist'] = 'first', ['lang'] = 'language', ['loaction'] = 'location', ['locatoin'] = 'location', ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['pub'] = 'publisher', ['pulbisher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['retrieved'] = 'accessdate', ['service'] = 'agency', ['tile'] = 'title', ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', } return suggestions; 68kp68tmtgya6mdrz8pul1gx9peubpm 736764 736763 2014-06-02T04:31:27Z en>Jonesey95 0 Boldly adding a bunch of suggestions. I have seen every one of these in actual articles in the past few months while cleaning up the "unsupported parameter" category. 736764 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'accessdate', ['accesdate'] = 'accessdate', ['access date'] = 'accessdate', ['access-date'] = 'accessdate', ['accessate'] = 'accessdate', ['accessdare'] = 'accessdate', ['accessdatte'] = 'accessdate', ['accessddate'] = 'accessdate', ['accessdte'] = 'accessdate', ['accessed'] = 'accessdate', ['accessedate'] = 'accessdate', ['accesssdate'] = 'accessdate', ['accssdate'] = 'accessdate', ['acessdate'] = 'accessdate', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'accessyear', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archivedate', ['archive url'] = 'archiveurl', -- Spanish, Italian ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'authorlink', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'accessdate', -- French ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editorial'] = 'publisher', ['en ligne le'] = 'archivedate', -- French ['enlaceautor'] = 'authorlink', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'accessdate', -- Spanish, Italian ['fechaarchivo'] = 'archivedate', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = ' language', -- Spanish, Italian ['lang'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['retrieved'] = 'accessdate', ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = ' title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archiveurl', -- Spanish, Italian } return suggestions; b1zvxwzxj6fx9ec1rs7w8y4mctj64ys 736765 736764 2014-06-02T09:34:22Z en>D'Ranged 1 0 removing extra space 736765 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'accessdate', ['accesdate'] = 'accessdate', ['access date'] = 'accessdate', ['access-date'] = 'accessdate', ['accessate'] = 'accessdate', ['accessdare'] = 'accessdate', ['accessdatte'] = 'accessdate', ['accessddate'] = 'accessdate', ['accessdte'] = 'accessdate', ['accessed'] = 'accessdate', ['accessedate'] = 'accessdate', ['accesssdate'] = 'accessdate', ['accssdate'] = 'accessdate', ['acessdate'] = 'accessdate', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'accessyear', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archivedate', ['archive url'] = 'archiveurl', -- Spanish, Italian ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'authorlink', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'accessdate', -- French ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editorial'] = 'publisher', ['en ligne le'] = 'archivedate', -- French ['enlaceautor'] = 'authorlink', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'accessdate', -- Spanish, Italian ['fechaarchivo'] = 'archivedate', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['lang'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['retrieved'] = 'accessdate', ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = ' title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archiveurl', -- Spanish, Italian } return suggestions; 5e7g5lempiamc2ynt9lo69v2khlwcnb 736766 736765 2014-06-16T05:08:13Z en>Jonesey95 0 another one I have seen twice today 736766 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'accessdate', ['accesdate'] = 'accessdate', ['access date'] = 'accessdate', ['access-date'] = 'accessdate', ['accessate'] = 'accessdate', ['accessdare'] = 'accessdate', ['accessdatte'] = 'accessdate', ['accessddate'] = 'accessdate', ['accessdte'] = 'accessdate', ['accessed'] = 'accessdate', ['accessedate'] = 'accessdate', ['accesssdate'] = 'accessdate', ['accssdate'] = 'accessdate', ['acessdate'] = 'accessdate', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'accessyear', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archivedate', ['archive url'] = 'archiveurl', -- Spanish, Italian ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'authorlink', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'accessdate', -- French ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editorial'] = 'publisher', ['en ligne le'] = 'archivedate', -- French ['enlaceautor'] = 'authorlink', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'accessdate', -- Spanish, Italian ['fechaarchivo'] = 'archivedate', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['lang'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publiser'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['retrieved'] = 'accessdate', ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = ' title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archiveurl', -- Spanish, Italian } return suggestions; s1e41t25xwf4zvn5jyscu7p7g5ptqbc 736767 736766 2014-06-18T03:55:25Z en>Jonesey95 0 adding "langauge", now that I've seen it twice in the last two days 736767 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'accessdate', ['accesdate'] = 'accessdate', ['access date'] = 'accessdate', ['access-date'] = 'accessdate', ['accessate'] = 'accessdate', ['accessdare'] = 'accessdate', ['accessdatte'] = 'accessdate', ['accessddate'] = 'accessdate', ['accessdte'] = 'accessdate', ['accessed'] = 'accessdate', ['accessedate'] = 'accessdate', ['accesssdate'] = 'accessdate', ['accssdate'] = 'accessdate', ['acessdate'] = 'accessdate', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'accessyear', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archivedate', ['archive url'] = 'archiveurl', -- Spanish, Italian ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'authorlink', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'accessdate', -- French ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editorial'] = 'publisher', ['en ligne le'] = 'archivedate', -- French ['enlaceautor'] = 'authorlink', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'accessdate', -- Spanish, Italian ['fechaarchivo'] = 'archivedate', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French ['name'] = 'author', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publiser'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['retrieved'] = 'accessdate', ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = ' title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archiveurl', -- Spanish, Italian } return suggestions; 1eenvhs2qmr7clmi0ul8irgi7ci72f8 736768 736767 2014-06-24T03:54:38Z en>Jonesey95 0 commenting out 'name' 736768 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'accessdate', ['accesdate'] = 'accessdate', ['access date'] = 'accessdate', ['access-date'] = 'accessdate', ['accessate'] = 'accessdate', ['accessdare'] = 'accessdate', ['accessdatte'] = 'accessdate', ['accessddate'] = 'accessdate', ['accessdte'] = 'accessdate', ['accessed'] = 'accessdate', ['accessedate'] = 'accessdate', ['accesssdate'] = 'accessdate', ['accssdate'] = 'accessdate', ['acessdate'] = 'accessdate', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'accessyear', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archivedate', ['archive url'] = 'archiveurl', -- Spanish, Italian ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'authorlink', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'accessdate', -- French ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editorial'] = 'publisher', ['en ligne le'] = 'archivedate', -- French ['enlaceautor'] = 'authorlink', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'accessdate', -- Spanish, Italian ['fechaarchivo'] = 'archivedate', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publiser'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['retrieved'] = 'accessdate', ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = ' title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archiveurl', -- Spanish, Italian } return suggestions; nn1vpbxw3l52td9socoha3ye4inal2t 736769 736768 2014-08-26T05:04:25Z en>Jonesey95 0 adding a few more that I have seen in the wild 736769 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'accessdate', ['accesdate'] = 'accessdate', ['access date'] = 'accessdate', ['access-date'] = 'accessdate', ['accessate'] = 'accessdate', ['accessdare'] = 'accessdate', ['accessdatte'] = 'accessdate', ['accessddate'] = 'accessdate', ['accessdte'] = 'accessdate', ['accessed'] = 'accessdate', ['accessedate'] = 'accessdate', ['accesssdate'] = 'accessdate', ['accssdate'] = 'accessdate', ['acessdate'] = 'accessdate', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'accessyear', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archivedate', ['archive url'] = 'archiveurl', -- Spanish, Italian ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'authorlink', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'accessdate', -- French ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorial'] = 'publisher', ['en ligne le'] = 'archivedate', -- French ['enlaceautor'] = 'authorlink', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'accessdate', -- Spanish, Italian ['fechaarchivo'] = 'archivedate', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['isnb'] = 'isbn', ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publiser'] = 'publisher', ['publishers'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['retrieved'] = 'accessdate', ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archiveurl', -- Spanish, Italian ['vol'] = 'volume', } return suggestions; oj03hwzzdeubhqk8618rkrl2dfb1d6e 736770 736769 2014-09-17T16:58:39Z en>Jonesey95 0 adding one 736770 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'accessdate', ['accesdate'] = 'accessdate', ['access date'] = 'accessdate', ['access-date'] = 'accessdate', ['accessate'] = 'accessdate', ['accessdare'] = 'accessdate', ['accessdatte'] = 'accessdate', ['accessddate'] = 'accessdate', ['accessdte'] = 'accessdate', ['accessed'] = 'accessdate', ['accessedate'] = 'accessdate', ['accesssdate'] = 'accessdate', ['accssdate'] = 'accessdate', ['acessdate'] = 'accessdate', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'accessyear', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archivedate', ['archive url'] = 'archiveurl', -- Spanish, Italian ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'authorlink', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'accessdate', -- French ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorial'] = 'publisher', ['en ligne le'] = 'archivedate', -- French ['enlaceautor'] = 'authorlink', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'accessdate', -- Spanish, Italian ['fechaarchivo'] = 'archivedate', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['isnb'] = 'isbn', ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publiser'] = 'publisher', ['publishers'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['retrieved'] = 'accessdate', ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archiveurl', -- Spanish, Italian ['vol'] = 'volume', } return suggestions; qyys4aplgwvve4s6fnt07tytm9klzty 736771 736770 2014-10-13T02:20:14Z en>Meltdown627 0 added suggestion 736771 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'accessdate', ['accesdate'] = 'accessdate', ['access date'] = 'accessdate', ['access-date'] = 'accessdate', ['accessate'] = 'accessdate', ['accessdare'] = 'accessdate', ['accessdatte'] = 'accessdate', ['accessddate'] = 'accessdate', ['accessdte'] = 'accessdate', ['accessed'] = 'accessdate', ['accessedate'] = 'accessdate', ['accesssdate'] = 'accessdate', ['accssdate'] = 'accessdate', ['acessdate'] = 'accessdate', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'accessyear', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archivedate', ['archive url'] = 'archiveurl', -- Spanish, Italian ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'authorlink', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'accessdate', -- French ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorial'] = 'publisher', ['en ligne le'] = 'archivedate', -- French ['enlaceautor'] = 'authorlink', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'accessdate', -- Spanish, Italian ['fechaarchivo'] = 'archivedate', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['isnb'] = 'isbn', ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publiser'] = 'publisher', ['publishers'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['pulisher'] = 'publisher', ['retrieved'] = 'accessdate', ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archiveurl', -- Spanish, Italian ['vol'] = 'volume', } return suggestions; 6aslku2ydhi9d37ujkoa15cv50p4gtu 736772 736771 2014-10-27T13:58:54Z en>Jonesey95 0 Adding day=. Commented until sandbox is merged with live module. 736772 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'accessdate', ['accesdate'] = 'accessdate', ['access date'] = 'accessdate', ['access-date'] = 'accessdate', ['accessate'] = 'accessdate', ['accessdare'] = 'accessdate', ['accessdatte'] = 'accessdate', ['accessddate'] = 'accessdate', ['accessdte'] = 'accessdate', ['accessed'] = 'accessdate', ['accessedate'] = 'accessdate', ['accesssdate'] = 'accessdate', ['accssdate'] = 'accessdate', ['acessdate'] = 'accessdate', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'accessyear', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archivedate', ['archive url'] = 'archiveurl', -- Spanish, Italian ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'authorlink', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'accessdate', -- French -- ['day'] = 'date', ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorial'] = 'publisher', ['en ligne le'] = 'archivedate', -- French ['enlaceautor'] = 'authorlink', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'accessdate', -- Spanish, Italian ['fechaarchivo'] = 'archivedate', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['isnb'] = 'isbn', ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publiser'] = 'publisher', ['publishers'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['pulisher'] = 'publisher', ['retrieved'] = 'accessdate', ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archiveurl', -- Spanish, Italian ['vol'] = 'volume', } return suggestions; r9izfdk89qptctn3opi0zyot9ip3vgj 736773 736772 2014-11-07T21:42:47Z en>Malpass93 0 Adding "deadlink" --> "deadurl" suggestion 736773 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'accessdate', ['accesdate'] = 'accessdate', ['access date'] = 'accessdate', ['access-date'] = 'accessdate', ['accessate'] = 'accessdate', ['accessdare'] = 'accessdate', ['accessdatte'] = 'accessdate', ['accessddate'] = 'accessdate', ['accessdte'] = 'accessdate', ['accessed'] = 'accessdate', ['accessedate'] = 'accessdate', ['accesssdate'] = 'accessdate', ['accssdate'] = 'accessdate', ['acessdate'] = 'accessdate', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'accessyear', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archivedate', ['archive url'] = 'archiveurl', -- Spanish, Italian ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'authorlink', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'accessdate', -- French -- ['day'] = 'date', ['deadlink'] = 'deadurl', ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorial'] = 'publisher', ['en ligne le'] = 'archivedate', -- French ['enlaceautor'] = 'authorlink', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'accessdate', -- Spanish, Italian ['fechaarchivo'] = 'archivedate', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['isnb'] = 'isbn', ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publiser'] = 'publisher', ['publishers'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['pulisher'] = 'publisher', ['retrieved'] = 'accessdate', ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archiveurl', -- Spanish, Italian ['vol'] = 'volume', } return suggestions; jplpxxkdx8z5i4uw2t238l3l0889446 736774 736773 2014-11-15T23:29:08Z en>Malpass93 0 736774 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'accessdate', ['accesdate'] = 'accessdate', ['access date'] = 'accessdate', ['access-date'] = 'accessdate', ['accessate'] = 'accessdate', ['accessdare'] = 'accessdate', ['accessdatte'] = 'accessdate', ['accessddate'] = 'accessdate', ['accessdte'] = 'accessdate', ['accessed'] = 'accessdate', ['accessedate'] = 'accessdate', ['accesssdate'] = 'accessdate', ['accssdate'] = 'accessdate', ['acessdate'] = 'accessdate', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'accessyear', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archivedate', ['archive url'] = 'archiveurl', -- Spanish, Italian ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'authorlink', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'accessdate', -- French -- ['day'] = 'date', ['deadlink'] = 'deadurl', ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorial'] = 'publisher', ['en ligne le'] = 'archivedate', -- French ['enlaceautor'] = 'authorlink', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'accessdate', -- Spanish, Italian ['fechaarchivo'] = 'archivedate', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['isnb'] = 'isbn', ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'origyear', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publiser'] = 'publisher', ['publishers'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['pulisher'] = 'publisher', ['retrieved'] = 'accessdate', ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archiveurl', -- Spanish, Italian ['vol'] = 'volume', } return suggestions; aqpqi0bdcjylv9mg549f4m2bxs4ruad 736775 736774 2014-12-03T06:23:28Z en>Jonesey95 0 Updating documentation per [[Help_talk:Citation_Style_1/Archive_5#RFC:_Citation_Style_1_parameter_naming_convention|July 2014 RFC]]; add artist and ps (due to recent migrations) 736775 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'access-date', ['accesdate'] = 'access-date', ['access date'] = 'access-date', ['access-date'] = 'access-date', ['accessate'] = 'access-date', ['accessdare'] = 'access-date', ['accessdatte'] = 'access-date', ['accessddate'] = 'access-date', ['accessdte'] = 'access-date', ['accessed'] = 'access-date', ['accessedate'] = 'access-date', ['accesssdate'] = 'access-date', ['accssdate'] = 'access-date', ['acessdate'] = 'access-date', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'author-link', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French -- ['day'] = 'date', ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorial'] = 'publisher', ['en ligne le'] = 'archive-date', -- French ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['isnb'] = 'isbn', ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'orig-year', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publiser'] = 'publisher', ['publishers'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['pulisher'] = 'publisher', ['retrieved'] = 'access-date', ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['vol'] = 'volume', } return suggestions; 5ai5y2ms9n76wd114x0lsxyvx33f8j4 736776 736775 2014-12-03T11:28:12Z en>Trappist the monk 0 remove ['access-date'] = 'access-date'; 736776 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'access-date', ['accesdate'] = 'access-date', ['access date'] = 'access-date', ['accessate'] = 'access-date', ['accessdare'] = 'access-date', ['accessdatte'] = 'access-date', ['accessddate'] = 'access-date', ['accessdte'] = 'access-date', ['accessed'] = 'access-date', ['accessedate'] = 'access-date', ['accesssdate'] = 'access-date', ['accssdate'] = 'access-date', ['acessdate'] = 'access-date', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'author-link', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French -- ['day'] = 'date', ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorial'] = 'publisher', ['en ligne le'] = 'archive-date', -- French ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['isnb'] = 'isbn', ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'orig-year', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publiser'] = 'publisher', ['publishers'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['pulisher'] = 'publisher', ['retrieved'] = 'access-date', ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['vol'] = 'volume', } return suggestions; 8gp0nyje6qgxt2qj3p5p8srhatys6u1 736777 736776 2015-08-06T14:10:19Z en>Trappist the monk 0 temporary add of previously deprecated and now deactivated parameters; 736777 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'access-date', ['accesdate'] = 'access-date', ['access date'] = 'access-date', ['accessate'] = 'access-date', ['accessdare'] = 'access-date', ['accessdatte'] = 'access-date', ['accessddate'] = 'access-date', ['accessdte'] = 'access-date', ['accessed'] = 'access-date', ['accessedate'] = 'access-date', ['accesssdate'] = 'access-date', ['accssdate'] = 'access-date', ['acessdate'] = 'access-date', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auteur'] = 'author', -- French ['auther'] = 'author', ['authorformat'] = 'name-list-format', -- remove after 2016-01-01 ['author-format'] = 'name-list-format', -- remove after 2016-01-01 ['author link'] = 'author-link', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorformat'] = 'name-list-format', -- remove after 2016-01-01 ['editor-format'] = 'name-list-format', -- remove after 2016-01-01 ['editorial'] = 'publisher', ['en ligne le'] = 'archive-date', -- French ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['isnb'] = 'isbn', ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'orig-year', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publiser'] = 'publisher', ['publishers'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['pulisher'] = 'publisher', ['retrieved'] = 'access-date', ['separator'] = 'mode', -- remove after 2016-01-01 ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['vol'] = 'volume', } return suggestions; qnnzetk6bud7dht2hl1x56hbmf1fkfe 736778 736777 2015-08-06T14:44:34Z en>Trappist the monk 0 EditorGiven & EditorSurname; 736778 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'access-date', ['accesdate'] = 'access-date', ['access date'] = 'access-date', ['accessate'] = 'access-date', ['accessdare'] = 'access-date', ['accessdatte'] = 'access-date', ['accessddate'] = 'access-date', ['accessdte'] = 'access-date', ['accessed'] = 'access-date', ['accessedate'] = 'access-date', ['accesssdate'] = 'access-date', ['accssdate'] = 'access-date', ['acessdate'] = 'access-date', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auteur'] = 'author', -- French ['auther'] = 'author', ['authorformat'] = 'name-list-format', -- remove after 2016-01-01 ['author-format'] = 'name-list-format', -- remove after 2016-01-01 ['author link'] = 'author-link', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorformat'] = 'name-list-format', -- remove after 2016-01-01 ['editor-format'] = 'name-list-format', -- remove after 2016-01-01 ['EditorGiven'] = 'editor-given', -- remove after 2016-01-01 ['editorial'] = 'publisher', ['EditorSurname'] = 'editor-surname', -- remove after 2016-01-01 ['en ligne le'] = 'archive-date', -- French ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['isnb'] = 'isbn', ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'orig-year', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publiser'] = 'publisher', ['publishers'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['pulisher'] = 'publisher', ['retrieved'] = 'access-date', ['separator'] = 'mode', -- remove after 2016-01-01 ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['vol'] = 'volume', } return suggestions; 7aireqolwwgg72y86ywubbjo2vjioa0 736779 736778 2015-08-06T14:47:10Z en>Trappist the monk 0 736779 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'access-date', ['accesdate'] = 'access-date', ['access date'] = 'access-date', ['accessate'] = 'access-date', ['accessdare'] = 'access-date', ['accessdatte'] = 'access-date', ['accessddate'] = 'access-date', ['accessdte'] = 'access-date', ['accessed'] = 'access-date', ['accessedate'] = 'access-date', ['accesssdate'] = 'access-date', ['accssdate'] = 'access-date', ['acessdate'] = 'access-date', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auteur'] = 'author', -- French ['auther'] = 'author', ['authorformat'] = 'name-list-format', -- remove after 2016-01-01 ['author-format'] = 'name-list-format', -- remove after 2016-01-01 ['author link'] = 'author-link', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorformat'] = 'name-list-format', -- remove after 2016-01-01 ['editor-format'] = 'name-list-format', -- remove after 2016-01-01 ['editorgiven'] = 'editor-given', -- remove after 2016-01-01 ['editorial'] = 'publisher', ['editorsurname'] = 'editor-surname', -- remove after 2016-01-01 ['en ligne le'] = 'archive-date', -- French ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['isnb'] = 'isbn', ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'orig-year', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publiser'] = 'publisher', ['publishers'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['pulisher'] = 'publisher', ['retrieved'] = 'access-date', ['separator'] = 'mode', -- remove after 2016-01-01 ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['vol'] = 'volume', } return suggestions; 1gm7jsbkvgtameznvlr73bre4szm0vu 736780 736779 2015-08-06T15:16:49Z en>Trappist the monk 0 began, ended, month; 736780 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'access-date', ['accesdate'] = 'access-date', ['access date'] = 'access-date', ['accessate'] = 'access-date', ['accessdare'] = 'access-date', ['accessdatte'] = 'access-date', ['accessddate'] = 'access-date', ['accessdte'] = 'access-date', ['accessed'] = 'access-date', ['accessedate'] = 'access-date', ['accesssdate'] = 'access-date', ['accssdate'] = 'access-date', ['acessdate'] = 'access-date', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auteur'] = 'author', -- French ['auther'] = 'author', ['authorformat'] = 'name-list-format', -- remove after 2016-01-01 ['author-format'] = 'name-list-format', -- remove after 2016-01-01 ['author link'] = 'author-link', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['began'] = 'date', -- remove after 2016-01-01 ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorformat'] = 'name-list-format', -- remove after 2016-01-01 ['editor-format'] = 'name-list-format', -- remove after 2016-01-01 ['editorgiven'] = 'editor-given', -- remove after 2016-01-01 ['editorial'] = 'publisher', ['editorsurname'] = 'editor-surname', -- remove after 2016-01-01 ['en ligne le'] = 'archive-date', -- French ['ended'] = 'date', -- remove after 2016-01-01 ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['isnb'] = 'isbn', ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French ['month'] = 'date', -- remove after 2016-01-01 -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'orig-year', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publiser'] = 'publisher', ['publishers'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['pulisher'] = 'publisher', ['retrieved'] = 'access-date', ['separator'] = 'mode', -- remove after 2016-01-01 ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['vol'] = 'volume', } return suggestions; rgm6bjshhdo8k0bt4h9z3e5ia7g7qo8 736781 736780 2015-09-04T02:31:36Z en>Courcelles 0 Protected "[[Module:Citation/CS1/Suggestions]]": [[WP:High-risk templates|Highly visible template]] ([Edit=Allow only template editors and admins] (indefinite) [Move=Allow only template editors and admins] (indefinite)) 736780 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'access-date', ['accesdate'] = 'access-date', ['access date'] = 'access-date', ['accessate'] = 'access-date', ['accessdare'] = 'access-date', ['accessdatte'] = 'access-date', ['accessddate'] = 'access-date', ['accessdte'] = 'access-date', ['accessed'] = 'access-date', ['accessedate'] = 'access-date', ['accesssdate'] = 'access-date', ['accssdate'] = 'access-date', ['acessdate'] = 'access-date', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auteur'] = 'author', -- French ['auther'] = 'author', ['authorformat'] = 'name-list-format', -- remove after 2016-01-01 ['author-format'] = 'name-list-format', -- remove after 2016-01-01 ['author link'] = 'author-link', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['began'] = 'date', -- remove after 2016-01-01 ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorformat'] = 'name-list-format', -- remove after 2016-01-01 ['editor-format'] = 'name-list-format', -- remove after 2016-01-01 ['editorgiven'] = 'editor-given', -- remove after 2016-01-01 ['editorial'] = 'publisher', ['editorsurname'] = 'editor-surname', -- remove after 2016-01-01 ['en ligne le'] = 'archive-date', -- French ['ended'] = 'date', -- remove after 2016-01-01 ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['isnb'] = 'isbn', ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French ['month'] = 'date', -- remove after 2016-01-01 -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'orig-year', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publiser'] = 'publisher', ['publishers'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['pulisher'] = 'publisher', ['retrieved'] = 'access-date', ['separator'] = 'mode', -- remove after 2016-01-01 ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['vol'] = 'volume', } return suggestions; rgm6bjshhdo8k0bt4h9z3e5ia7g7qo8 736782 736781 2015-09-04T17:31:11Z en>Courcelles 0 Changed protection level of Module:Citation/CS1/Suggestions: Oops ([Edit=Allow only autoconfirmed users] (indefinite) [Move=Allow only autoconfirmed users] (indefinite)) 736780 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['acccessdate'] = 'access-date', ['accesdate'] = 'access-date', ['access date'] = 'access-date', ['accessate'] = 'access-date', ['accessdare'] = 'access-date', ['accessdatte'] = 'access-date', ['accessddate'] = 'access-date', ['accessdte'] = 'access-date', ['accessed'] = 'access-date', ['accessedate'] = 'access-date', ['accesssdate'] = 'access-date', ['accssdate'] = 'access-date', ['acessdate'] = 'access-date', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auteur'] = 'author', -- French ['auther'] = 'author', ['authorformat'] = 'name-list-format', -- remove after 2016-01-01 ['author-format'] = 'name-list-format', -- remove after 2016-01-01 ['author link'] = 'author-link', ['autor'] = 'author', -- Spanish, Italian ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['began'] = 'date', -- remove after 2016-01-01 ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorformat'] = 'name-list-format', -- remove after 2016-01-01 ['editor-format'] = 'name-list-format', -- remove after 2016-01-01 ['editorgiven'] = 'editor-given', -- remove after 2016-01-01 ['editorial'] = 'publisher', ['editorsurname'] = 'editor-surname', -- remove after 2016-01-01 ['en ligne le'] = 'archive-date', -- French ['ended'] = 'date', -- remove after 2016-01-01 ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['isnb'] = 'isbn', ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French ['month'] = 'date', -- remove after 2016-01-01 -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'orig-year', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', ['pubisher'] = 'publisher', ['publiser'] = 'publisher', ['publishers'] = 'publisher', ['publsher'] = 'publisher', ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', ['pulbisher'] = 'publisher', ['pulisher'] = 'publisher', ['retrieved'] = 'access-date', ['separator'] = 'mode', -- remove after 2016-01-01 ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['vol'] = 'volume', } return suggestions; rgm6bjshhdo8k0bt4h9z3e5ia7g7qo8 736783 736782 2015-09-26T16:17:01Z en>Trappist the monk 0 Synch from sandbox; 736783 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { -- ['acccessdate'] = 'access-date', -- ['accesdate'] = 'access-date', -- ['access date'] = 'access-date', -- ['accessate'] = 'access-date', -- ['accessdare'] = 'access-date', -- ['accessdatte'] = 'access-date', -- ['accessddate'] = 'access-date', -- ['accessdte'] = 'access-date', -- ['accessed'] = 'access-date', -- ['accessedate'] = 'access-date', -- ['accesssdate'] = 'access-date', -- ['accssdate'] = 'access-date', -- ['acessdate'] = 'access-date', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auteur'] = 'author', -- French ['auther'] = 'author', ['authorformat'] = 'name-list-format', -- remove after 2016-01-01 ['author-format'] = 'name-list-format', -- remove after 2016-01-01 ['author link'] = 'author-link', -- ['autor'] = 'author', -- Spanish, Italian -- ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['began'] = 'date', -- remove after 2016-01-01 ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorformat'] = 'name-list-format', -- remove after 2016-01-01 ['editor-format'] = 'name-list-format', -- remove after 2016-01-01 ['editorgiven'] = 'editor-given', -- remove after 2016-01-01 ['editorial'] = 'publisher', ['editorsurname'] = 'editor-surname', -- remove after 2016-01-01 ['en ligne le'] = 'archive-date', -- French ['ended'] = 'date', -- remove after 2016-01-01 ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['isnb'] = 'isbn', ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French ['month'] = 'date', -- remove after 2016-01-01 -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'orig-year', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubisher'] = 'publisher', -- ['publiser'] = 'publisher', -- ['publishers'] = 'publisher', -- ['publsher'] = 'publisher', -- ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', -- ['pulbisher'] = 'publisher', -- ['pulisher'] = 'publisher', ['retrieved'] = 'access-date', ['separator'] = 'mode', -- remove after 2016-01-01 ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['vol'] = 'volume', } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not regex though they are similar. The escape character is '%', not '\'. For more information about lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['ac+es+ ?d?a?t?e?'] = 'access-date', ['a[utho]+r'] = 'author', ['a[utho]+r(%d+)'] = 'author$1', -- enumerated ['pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; 1w3htivg1h0a7w5efz7jz86xtdkc09d 736784 736783 2015-11-23T20:47:05Z en>Trappist the monk 0 anchor assertions as part of patterns; 736784 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { -- ['acccessdate'] = 'access-date', -- ['accesdate'] = 'access-date', -- ['access date'] = 'access-date', -- ['accessate'] = 'access-date', -- ['accessdare'] = 'access-date', -- ['accessdatte'] = 'access-date', -- ['accessddate'] = 'access-date', -- ['accessdte'] = 'access-date', -- ['accessed'] = 'access-date', -- ['accessedate'] = 'access-date', -- ['accesssdate'] = 'access-date', -- ['accssdate'] = 'access-date', -- ['acessdate'] = 'access-date', ['address'] = 'location', ['année'] = 'year', -- French ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auteur'] = 'author', -- French ['auther'] = 'author', ['authorformat'] = 'name-list-format', -- remove after 2016-01-01 ['author-format'] = 'name-list-format', -- remove after 2016-01-01 ['author link'] = 'author-link', -- ['autor'] = 'author', -- Spanish, Italian -- ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['began'] = 'date', -- remove after 2016-01-01 ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorformat'] = 'name-list-format', -- remove after 2016-01-01 ['editor-format'] = 'name-list-format', -- remove after 2016-01-01 ['editorgiven'] = 'editor-given', -- remove after 2016-01-01 ['editorial'] = 'publisher', ['editorsurname'] = 'editor-surname', -- remove after 2016-01-01 ['en ligne le'] = 'archive-date', -- French ['ended'] = 'date', -- remove after 2016-01-01 ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['isnb'] = 'isbn', ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['mois'] = 'month', -- French ['month'] = 'date', -- remove after 2016-01-01 -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'orig-year', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubisher'] = 'publisher', -- ['publiser'] = 'publisher', -- ['publishers'] = 'publisher', -- ['publsher'] = 'publisher', -- ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', -- ['pulbisher'] = 'publisher', -- ['pulisher'] = 'publisher', ['retrieved'] = 'access-date', ['separator'] = 'mode', -- remove after 2016-01-01 ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['vol'] = 'volume', } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not regex though they are similar. The escape character is '%', not '\'. For more information about lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', ['^a[utho]+r$'] = 'author', ['^a[utho]+r(%d+)$'] = 'author$1', -- enumerated ['^pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; e1qhuo9igancdbfnrdrcmkpbwljq22g 736785 736739 2016-04-16T10:32:02Z en>Trappist the monk 0 Synch from sandbox; 736785 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { -- ['acccessdate'] = 'access-date', -- ['accesdate'] = 'access-date', -- ['access date'] = 'access-date', -- ['accessate'] = 'access-date', -- ['accessdare'] = 'access-date', -- ['accessdatte'] = 'access-date', -- ['accessddate'] = 'access-date', -- ['accessdte'] = 'access-date', -- ['accessed'] = 'access-date', -- ['accessedate'] = 'access-date', -- ['accesssdate'] = 'access-date', -- ['accssdate'] = 'access-date', -- ['acessdate'] = 'access-date', ['address'] = 'location', ['année'] = 'year', -- French ['año'] = 'year', ['año-original'] = 'orig-year', ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auteur'] = 'author', -- French ['auther'] = 'author', ['authorformat'] = 'name-list-format', -- remove after 2016-01-01 ['author-format'] = 'name-list-format', -- remove after 2016-01-01 ['author link'] = 'author-link', -- ['autor'] = 'author', -- Spanish, Italian -- ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['began'] = 'date', -- remove after 2016-01-01 ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorformat'] = 'name-list-format', -- remove after 2016-01-01 ['editor-format'] = 'name-list-format', -- remove after 2016-01-01 ['editorgiven'] = 'editor-given', -- remove after 2016-01-01 ['editorial'] = 'publisher', ['editorsurname'] = 'editor-surname', -- remove after 2016-01-01 ['en ligne le'] = 'archive-date', -- French ['ended'] = 'date', -- remove after 2016-01-01 ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['isnb'] = 'isbn', ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['lugar'] = 'location', --Spanish ['mois'] = 'month', -- French -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'orig-year', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubisher'] = 'publisher', -- ['publiser'] = 'publisher', -- ['publishers'] = 'publisher', -- ['publsher'] = 'publisher', -- ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', -- ['pulbisher'] = 'publisher', -- ['pulisher'] = 'publisher', ['retrieved'] = 'access-date', ['separator'] = 'mode', -- remove after 2016-01-01 ['série'] = 'work', -- French ['service'] = 'agency', ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not regex though they are similar. The escape character is '%', not '\'. For more information about lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', ['^a[utho]+r$'] = 'author', ['^a[utho]+r(%d+)$'] = 'author$1', -- enumerated ['^pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; hle2gq05pe0ph243pk9bigpg4puyzb9 736786 736785 2016-04-25T03:25:10Z en>Eyesnore 0 736786 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { -- ['acccessdate'] = 'access-date', -- ['accesdate'] = 'access-date', -- ['access date'] = 'access-date', -- ['accessate'] = 'access-date', -- ['accessdare'] = 'access-date', -- ['accessdatte'] = 'access-date', -- ['accessddate'] = 'access-date', -- ['accessdte'] = 'access-date', -- ['accessed'] = 'access-date', -- ['accessedate'] = 'access-date', -- ['accesssdate'] = 'access-date', -- ['accssdate'] = 'access-date', -- ['acessdate'] = 'access-date', ['address'] = 'location', ['année'] = 'year', -- French ['año'] = 'year', ['año-original'] = 'orig-year', ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auteur'] = 'author', -- French ['auther'] = 'author', -- ['authorformat'] = 'name-list-format', -- remove after 2016-01-01 -- ['author-format'] = 'name-list-format', -- remove after 2016-01-01 ['author link'] = 'author-link', -- ['autor'] = 'author', -- Spanish, Italian -- ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', -- ['began'] = 'date', -- remove after 2016-01-01 ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', -- ['editorformat'] = 'name-list-format', -- remove after 2016-01-01 -- ['editor-format'] = 'name-list-format', -- remove after 2016-01-01 -- ['editorgiven'] = 'editor-given', -- remove after 2016-01-01 ['editorial'] = 'publisher', -- ['editorsurname'] = 'editor-surname', -- remove after 2016-01-01 ['en ligne le'] = 'archive-date', -- French -- ['ended'] = 'date', -- remove after 2016-01-01 ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['idioma'] = 'language', -- Spanish, Italian ['isnb'] = 'isbn', ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['lugar'] = 'location', --Spanish ['mois'] = 'month', -- French -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['obra'] = 'work', -- Spanish, Italian ['origdate'] = 'orig-year', ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubisher'] = 'publisher', -- ['publiser'] = 'publisher', -- ['publishers'] = 'publisher', -- ['publsher'] = 'publisher', -- ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', -- ['pulbisher'] = 'publisher', -- ['pulisher'] = 'publisher', ['retrieved'] = 'access-date', -- ['separator'] = 'mode', -- remove after 2016-01-01 ['série'] = 'work', -- French ['service'] = 'agency', ['sitioweb'] = 'website', --Spanish ['suscripción'] = 'subscription', -- Spanish, Italian ['tile'] = 'title', ['tite'] = 'title', ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not regex though they are similar. The escape character is '%', not '\'. For more information about lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', ['^a[utho]+r$'] = 'author', ['^a[utho]+r(%d+)$'] = 'author$1', -- enumerated ['^pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; fpn2pdlwpm8bs8l6x9srz3fnqdh6xkv 736787 736786 2016-05-06T17:27:32Z en>Matthiaspaul 0 Added replacement parameter suggestions for parameters supported by the citation template in German Wikipedia 736787 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { -- ['acccessdate'] = 'access-date', -- ['accesdate'] = 'access-date', -- ['access date'] = 'access-date', -- ['accessate'] = 'access-date', -- ['accessdare'] = 'access-date', -- ['accessdatte'] = 'access-date', -- ['accessddate'] = 'access-date', -- ['accessdte'] = 'access-date', -- ['accessed'] = 'access-date', -- ['accessedate'] = 'access-date', -- ['accesssdate'] = 'access-date', -- ['accssdate'] = 'access-date', -- ['acessdate'] = 'access-date', ['address'] = 'location', ['année'] = 'year', -- French ['año'] = 'year', ['año-original'] = 'orig-year', ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', -- ['authorformat'] = 'name-list-format', -- remove after 2016-01-01 -- ['author-format'] = 'name-list-format', -- remove after 2016-01-01 ['author link'] = 'author-link', -- ['autor'] = 'author', -- Spanish, Italian ['autor'] = 'authors', -- German (singular and plural) -- ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['band'] = 'volume', -- German -- ['began'] = 'date', -- remove after 2016-01-01 ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', -- ['editorformat'] = 'name-list-format', -- remove after 2016-01-01 -- ['editor-format'] = 'name-list-format', -- remove after 2016-01-01 -- ['editorgiven'] = 'editor-given', -- remove after 2016-01-01 ['editorial'] = 'publisher', -- ['editorsurname'] = 'editor-surname', -- remove after 2016-01-01 ['en ligne le'] = 'archive-date', -- French -- ['ended'] = 'date', -- remove after 2016-01-01 ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['herausgeber'] = 'editors', -- German (singular and plural) ['idioma'] = 'language', -- Spanish, Italian ['isbnistformalfalsch'] = 'ignore-isbn-error', -- German ['isnb'] = 'isbn', ['jahr'] = 'year', -- German ['kapitel'] = 'chapter', -- German -- ['kommentar'] = 'comment', -- German ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License ...') ['loaction'] = 'location', ['locatoin'] = 'location', ['lugar'] = 'location', -- Spanish ['mois'] = 'month', -- French ['monat'] = 'month', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['nummer'] = 'number', -- German ['obra'] = 'work', -- Spanish, Italian ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['origdate'] = 'orig-year', ['originaljahr'] = 'orig-year', -- German ['originalort'] = 'location', -- German (if 'ort' is specified at the same time, the latter should be put in 'publication-place') ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'location', -- German ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubisher'] = 'publisher', -- ['publiser'] = 'publisher', -- ['publishers'] = 'publisher', -- ['publsher'] = 'publisher', -- ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', -- ['pulbisher'] = 'publisher', -- ['pulisher'] = 'publisher', ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['sammelwerk'] = 'work', -- German ['seiten'] = 'pages', -- German -- ['separator'] = 'mode', -- remove after 2016-01-01 ['série'] = 'work', -- French ['service'] = 'agency', ['sitioweb'] = 'website', --Spanish ['suscripción'] = 'subscription', -- Spanish, Italian -- ['tag'] = 'date', -- German ['tile'] = 'title', ['tite'] = 'title', ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['übersetzer'] = 'translator', -- German (singular and plural) ['verlag'] = 'publisher', -- German ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['zdb'] = 'id', -- German (as 'id=ZDB&nbsp;...') ['zugriff'] = 'access-date', -- German } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not regex though they are similar. The escape character is '%', not '\'. For more information about lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', ['^a[utho]+r$'] = 'author', ['^a[utho]+r(%d+)$'] = 'author$1', -- enumerated ['^pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; btxq09e0jglg9g54ak8jy3zipwskkwt 736788 736787 2016-05-06T17:50:15Z en>Matthiaspaul 0 Changed suggestion of parameter 'month' to 'date' as 'month' is no longer a valid parameter. Enabled German parameter 'tag' (for former English parameter 'day'), now to be emulated by 'date'. 736788 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { -- ['acccessdate'] = 'access-date', -- ['accesdate'] = 'access-date', -- ['access date'] = 'access-date', -- ['accessate'] = 'access-date', -- ['accessdare'] = 'access-date', -- ['accessdatte'] = 'access-date', -- ['accessddate'] = 'access-date', -- ['accessdte'] = 'access-date', -- ['accessed'] = 'access-date', -- ['accessedate'] = 'access-date', -- ['accesssdate'] = 'access-date', -- ['accssdate'] = 'access-date', -- ['acessdate'] = 'access-date', ['address'] = 'location', ['année'] = 'year', -- French ['año'] = 'year', ['año-original'] = 'orig-year', ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', -- ['authorformat'] = 'name-list-format', -- remove after 2016-01-01 -- ['author-format'] = 'name-list-format', -- remove after 2016-01-01 ['author link'] = 'author-link', -- ['autor'] = 'author', -- Spanish, Italian ['autor'] = 'authors', -- German (singular and plural) -- ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['band'] = 'volume', -- German -- ['began'] = 'date', -- remove after 2016-01-01 ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', -- ['editorformat'] = 'name-list-format', -- remove after 2016-01-01 -- ['editor-format'] = 'name-list-format', -- remove after 2016-01-01 -- ['editorgiven'] = 'editor-given', -- remove after 2016-01-01 ['editorial'] = 'publisher', -- ['editorsurname'] = 'editor-surname', -- remove after 2016-01-01 ['en ligne le'] = 'archive-date', -- French -- ['ended'] = 'date', -- remove after 2016-01-01 ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['herausgeber'] = 'editors', -- German (singular and plural) ['idioma'] = 'language', -- Spanish, Italian ['isbnistformalfalsch'] = 'ignore-isbn-error', -- German ['isnb'] = 'isbn', ['jahr'] = 'year', -- German ['kapitel'] = 'chapter', -- German -- ['kommentar'] = 'comment', -- German ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License ...') ['loaction'] = 'location', ['locatoin'] = 'location', ['lugar'] = 'location', -- Spanish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['nummer'] = 'number', -- German ['obra'] = 'work', -- Spanish, Italian ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['origdate'] = 'orig-year', ['originaljahr'] = 'orig-year', -- German ['originalort'] = 'location', -- German (if 'ort' is specified at the same time, the latter should be put in 'publication-place') ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'location', -- German ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubisher'] = 'publisher', -- ['publiser'] = 'publisher', -- ['publishers'] = 'publisher', -- ['publsher'] = 'publisher', -- ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', -- ['pulbisher'] = 'publisher', -- ['pulisher'] = 'publisher', ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['sammelwerk'] = 'work', -- German ['seiten'] = 'pages', -- German -- ['separator'] = 'mode', -- remove after 2016-01-01 ['série'] = 'work', -- French ['service'] = 'agency', ['sitioweb'] = 'website', --Spanish ['suscripción'] = 'subscription', -- Spanish, Italian ['tag'] = 'date', -- German ['tile'] = 'title', ['tite'] = 'title', ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['übersetzer'] = 'translator', -- German (singular and plural) ['verlag'] = 'publisher', -- German ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['zdb'] = 'id', -- German (as 'id=ZDB&nbsp;...') ['zugriff'] = 'access-date', -- German } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not regex though they are similar. The escape character is '%', not '\'. For more information about lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', ['^a[utho]+r$'] = 'author', ['^a[utho]+r(%d+)$'] = 'author$1', -- enumerated ['^pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; 7h2mafsqjr0ywmtbqf7u5zl6uoy9qtv 736789 736788 2016-05-07T07:21:56Z en>Matthiaspaul 0 Added suggestions for more citation parameters from German Wikipedia 736789 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { -- ['acccessdate'] = 'access-date', -- ['accesdate'] = 'access-date', -- ['access date'] = 'access-date', -- ['accessate'] = 'access-date', -- ['accessdare'] = 'access-date', -- ['accessdatte'] = 'access-date', -- ['accessddate'] = 'access-date', -- ['accessdte'] = 'access-date', -- ['accessed'] = 'access-date', -- ['accessedate'] = 'access-date', -- ['accesssdate'] = 'access-date', -- ['accssdate'] = 'access-date', -- ['acessdate'] = 'access-date', ['address'] = 'location', ['année'] = 'year', -- French ['año'] = 'year', ['año-original'] = 'orig-year', ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', -- ['authorformat'] = 'name-list-format', -- remove after 2016-01-01 -- ['author-format'] = 'name-list-format', -- remove after 2016-01-01 ['author link'] = 'author-link', -- ['autor'] = 'author', -- Spanish, Italian ['autor'] = 'authors', -- German (singular and plural) -- ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['band'] = 'volume', -- German -- ['began'] = 'date', -- remove after 2016-01-01 ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French ['datum'] = 'date', -- German ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') (not yet supported by us directly) ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', -- ['editorformat'] = 'name-list-format', -- remove after 2016-01-01 -- ['editor-format'] = 'name-list-format', -- remove after 2016-01-01 -- ['editorgiven'] = 'editor-given', -- remove after 2016-01-01 ['editorial'] = 'publisher', -- ['editorsurname'] = 'editor-surname', -- remove after 2016-01-01 ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', -- ['ended'] = 'date', -- remove after 2016-01-01 ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['herausgeber'] = 'editors', -- German (singular and plural) ['idioma'] = 'language', -- Spanish, Italian ['isbnistformalfalsch'] = 'ignore-isbn-error', -- German ['isnb'] = 'isbn', ['jahr'] = 'year', -- German ['kapitel'] = 'chapter', -- German -- ['kommentar'] = 'comment', -- German (not yet supported by us) ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License ...') ['loaction'] = 'location', ['locatoin'] = 'location', ['lugar'] = 'location', -- Spanish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['nummer'] = 'number', -- German ['obra'] = 'work', -- Spanish, Italian ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['origdate'] = 'orig-year', ['originaljahr'] = 'orig-year', -- German ['originalort'] = 'location', -- German (if 'ort' is specified at the same time, the latter should be put in 'publication-place') ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'location', -- German ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubisher'] = 'publisher', -- ['publiser'] = 'publisher', -- ['publishers'] = 'publisher', -- ['publsher'] = 'publisher', -- ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', -- ['pulbisher'] = 'publisher', -- ['pulisher'] = 'publisher', ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['sammelwerk'] = 'work', -- German ['seiten'] = 'pages', -- German -- ['separator'] = 'mode', -- remove after 2016-01-01 ['série'] = 'work', -- French ['service'] = 'agency', ['sitioweb'] = 'website', --Spanish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['suscripción'] = 'subscription', -- Spanish, Italian ['tag'] = 'date', -- German ['tile'] = 'title', ['tite'] = 'title', ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') (not yet supported by us directly) ['übersetzer'] = 'translator', -- German (singular and plural) ['verlag'] = 'publisher', -- German ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') (not yet supported by us directly) ['zugriff'] = 'access-date', -- German } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not regex though they are similar. The escape character is '%', not '\'. For more information about lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', ['^a[utho]+r$'] = 'author', ['^a[utho]+r(%d+)$'] = 'author$1', -- enumerated ['^pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; 95f61xuma4j1g74idt41t69vav27x4h 736790 736789 2016-05-08T08:23:31Z en>Matthiaspaul 0 Added more suggestions for parameters supported by citation templates Literatur and Internetquelle and emulations of Cite * templates used in German Wikipedia 736790 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { -- ['acccessdate'] = 'access-date', -- ['accesdate'] = 'access-date', -- ['access date'] = 'access-date', -- ['accessate'] = 'access-date', -- ['accessdare'] = 'access-date', -- ['accessdatte'] = 'access-date', -- ['accessddate'] = 'access-date', -- ['accessdte'] = 'access-date', -- ['accessed'] = 'access-date', -- ['accessedate'] = 'access-date', -- ['accesssdate'] = 'access-date', -- ['accssdate'] = 'access-date', -- ['acessdate'] = 'access-date', ['accessmonth'] = 'access-date', -- (no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date') ['accessyear'] = 'access-date', -- (no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date') ['address'] = 'location', ['année'] = 'year', -- French ['año'] = 'year', ['año-original'] = 'orig-year', ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archiv-datum'] = 'archive-date', -- German ['archive date'] = 'archive-date', ['archiv-url'] = 'archive-url', -- German ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', -- ['authorformat'] = 'name-list-format', -- remove after 2016-01-01 -- ['author-format'] = 'name-list-format', -- remove after 2016-01-01 ['author link'] = 'author-link', -- ['autor'] = 'author', -- Spanish, Italian ['autor'] = 'authors', -- German (singular and plural) -- ['autor2'] = 'author2', -- Spanish, Italian ['autthor'] = 'author', ['band'] = 'volume', -- German -- ['began'] = 'date', -- remove after 2016-01-01 ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French ['datum'] = 'date', -- German ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') (not yet supported by us directly) ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', -- ['editorformat'] = 'name-list-format', -- remove after 2016-01-01 -- ['editor-format'] = 'name-list-format', -- remove after 2016-01-01 -- ['editorgiven'] = 'editor-given', -- remove after 2016-01-01 ['editorial'] = 'publisher', -- ['editorsurname'] = 'editor-surname', -- remove after 2016-01-01 ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', -- ['ended'] = 'date', -- remove after 2016-01-01 ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian ['frist'] = 'first', ['herausgeber'] = 'editors', -- German (singular and plural) ['idioma'] = 'language', -- Spanish, Italian ['isbnistformalfalsch'] = 'ignore-isbn-error', -- German ['isnb'] = 'isbn', ['jahr'] = 'year', -- German ['kapitel'] = 'chapter', -- German -- ['kommentar'] = 'comment', -- German (not yet supported by us) ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License ...') ['loaction'] = 'location', ['locatoin'] = 'location', ['lugar'] = 'location', -- Spanish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['nummer'] = 'number', -- German ['obra'] = 'work', -- Spanish, Italian ['offline'] = 'dead-url', -- German ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['origdate'] = 'orig-year', ['originaljahr'] = 'orig-year', -- German ['originalort'] = 'location', -- German (if 'ort' is specified at the same time, the latter should be put in 'publication-place') ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'location', -- German ['other'] = 'others', ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubisher'] = 'publisher', -- ['publiser'] = 'publisher', -- ['publishers'] = 'publisher', -- ['publsher'] = 'publisher', -- ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', -- ['pulbisher'] = 'publisher', -- ['pulisher'] = 'publisher', ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['sammelwerk'] = 'work', -- German ['seiten'] = 'pages', -- German -- ['separator'] = 'mode', -- remove after 2016-01-01 ['série'] = 'work', -- French ['service'] = 'agency', ['sitioweb'] = 'website', --Spanish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['suscripción'] = 'subscription', -- Spanish, Italian ['tag'] = 'date', -- German ['tile'] = 'title', ['tite'] = 'title', ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') (not yet supported by us directly) ['übersetzer'] = 'translator', -- German (singular and plural) ['verlag'] = 'publisher', -- German ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') (not yet supported by us directly) ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not regex though they are similar. The escape character is '%', not '\'. For more information about lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', ['^a[utho]+r$'] = 'author', ['^a[utho]+r(%d+)$'] = 'author$1', -- enumerated ['^pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; 92wlzwwm6w4kz9f52d6u7tn84jrxgt3 736791 736790 2016-05-13T17:59:11Z en>Matthiaspaul 0 Added suggestions for some parameters supported by the citation template in the Polish WP 736791 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { -- ['acccessdate'] = 'access-date', -- ['accesdate'] = 'access-date', -- ['access date'] = 'access-date', -- ['accessate'] = 'access-date', -- ['accessdare'] = 'access-date', -- ['accessdatte'] = 'access-date', -- ['accessddate'] = 'access-date', -- ['accessdte'] = 'access-date', -- ['accessed'] = 'access-date', -- ['accessedate'] = 'access-date', -- ['accesssdate'] = 'access-date', -- ['accssdate'] = 'access-date', -- ['acessdate'] = 'access-date', ['accessmonth'] = 'access-date', -- (no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date') ['accessyear'] = 'access-date', -- (no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date') ['address'] = 'location', ['année'] = 'year', -- French ['año'] = 'year', ['año-original'] = 'orig-year', ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archiv-datum'] = 'archive-date', -- German ['archive date'] = 'archive-date', ['archiv-url'] = 'archive-url', -- German ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', -- ['authorformat'] = 'name-list-format', -- remove after 2016-01-01 -- ['author-format'] = 'name-list-format', -- remove after 2016-01-01 ['author link'] = 'author-link', -- Polish ['author link2'] = 'author2-link', -- Polish -- ['autor'] = 'author', -- Spanish, Italian, Polish ['autor'] = 'authors', -- German (singular and plural) -- ['autor2'] = 'author2', -- Spanish, Italian, Polish -- ['autor3'] = 'author3', -- Polish ['autthor'] = 'author', ['band'] = 'volume', -- German -- ['began'] = 'date', -- remove after 2016-01-01 ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French ['czasopismo'] = 'journal', -- Polish ['data'] = 'date', -- Polish ['data dostępu'] = 'access-date', -- Polish ['datum'] = 'date', -- German ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') (not yet supported by us directly) ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', -- ['editorformat'] = 'name-list-format', -- remove after 2016-01-01 -- ['editor-format'] = 'name-list-format', -- remove after 2016-01-01 -- ['editorgiven'] = 'editor-given', -- remove after 2016-01-01 ['editorial'] = 'publisher', -- ['editorsurname'] = 'editor-surname', -- remove after 2016-01-01 ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', -- ['ended'] = 'date', -- remove after 2016-01-01 ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', ['herausgeber'] = 'editors', -- German (singular and plural) ['idioma'] = 'language', -- Spanish, Italian ['imię'] = 'first', -- Polish ['isbnistformalfalsch'] = 'ignore-isbn-error', -- German ['isnb'] = 'isbn', ['jahr'] = 'year', -- German ['kapitel'] = 'chapter', -- German -- ['kommentar'] = 'comment', -- German (not yet supported by us) ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License ...') ['loaction'] = 'location', ['locatoin'] = 'location', ['lugar'] = 'location', -- Spanish ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['nummer'] = 'number', -- German ['obra'] = 'work', -- Spanish, Italian ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'dead-url', -- German ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opublikowany'] = 'agency', -- Polish ['origdate'] = 'orig-year', ['originaljahr'] = 'orig-year', -- German ['originalort'] = 'location', -- German (if 'ort' is specified at the same time, the latter should be put in 'publication-place') ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'location', -- German ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['praca'] = 'work', -- Polish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubisher'] = 'publisher', -- ['publiser'] = 'publisher', -- ['publishers'] = 'publisher', -- ['publsher'] = 'publisher', -- ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', -- ['pulbisher'] = 'publisher', -- ['pulisher'] = 'publisher', ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['seiten'] = 'pages', -- German -- ['separator'] = 'mode', -- remove after 2016-01-01 ['seria'] = 'series', -- Polish ['série'] = 'work', -- French *RECHECK* ['service'] = 'agency', ['sitioweb'] = 'website', --Spanish ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['suscripción'] = 'subscription', -- Spanish, Italian, Polish ['tag'] = 'date', -- German ['tile'] = 'title', ['tite'] = 'title', ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') (not yet supported by us directly) ['übersetzer'] = 'translator', -- German (singular and plural) ['verlag'] = 'publisher', -- German ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') (not yet supported by us directly) ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not regex though they are similar. The escape character is '%', not '\'. For more information about lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', ['^a[utho]+r$'] = 'author', ['^a[utho]+r(%d+)$'] = 'author$1', -- enumerated ['^pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; m9r4bd8z0xh79y2rny8loerdiwqxhqj 736792 736791 2016-05-24T12:33:28Z en>Moroboshi 0 736792 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { -- ['acccessdate'] = 'access-date', -- ['accesdate'] = 'access-date', -- ['access date'] = 'access-date', -- ['accessate'] = 'access-date', -- ['accessdare'] = 'access-date', -- ['accessdatte'] = 'access-date', -- ['accessddate'] = 'access-date', -- ['accessdte'] = 'access-date', -- ['accessed'] = 'access-date', -- ['accessedate'] = 'access-date', -- ['accesssdate'] = 'access-date', -- ['accssdate'] = 'access-date', -- ['acessdate'] = 'access-date', ['accessmonth'] = 'access-date', -- (no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date') ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', -- (no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date') ['address'] = 'location', ['année'] = 'year', -- French ['año'] = 'year', ['año-original'] = 'orig-year', ['añoacceso'] = 'access-date', -- Spanish ['annoaccesso'] = 'access-date', --Italian ['annodiaccesso'] = 'access-date', --Italian ['apellido'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archive date'] = 'archive-date', ['archiv-url'] = 'archive-url', -- German ['archive url'] = 'archive-url', -- Spanish ['artist'] = 'others', ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', -- ['authorformat'] = 'name-list-format', -- remove after 2016-01-01 -- ['author-format'] = 'name-list-format', -- remove after 2016-01-01 ['author link'] = 'author-link', -- Polish ['author link2'] = 'author2-link', -- Polish -- ['autor'] = 'author', -- Spanish, Polish ['autor'] = 'authors', -- German (singular and plural) ['autore'] = 'author', -- Italian -- ['autor2'] = 'author2', -- Spanish, Polish -- ['autor3'] = 'author3', -- Polish ['autthor'] = 'author', ['band'] = 'volume', -- German -- ['began'] = 'date', -- remove after 2016-01-01 ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['coautores'] = 'coauthors', -- Spanish ['coautori'] = 'coauthors', -- Italian ['cognome'] = 'last', -- Italian ['consulté le'] = 'access-date', -- French ['czasopismo'] = 'journal', -- Polish ['data'] = 'date', -- Polish, Italian ['dataarchivio'] = 'archive-date', -- Italian ['data dostępu'] = 'access-date', -- Polish ['datum'] = 'date', -- German ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') (not yet supported by us directly) ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', -- ['editorformat'] = 'name-list-format', -- remove after 2016-01-01 -- ['editor-format'] = 'name-list-format', -- remove after 2016-01-01 -- ['editorgiven'] = 'editor-given', -- remove after 2016-01-01 ['editorial'] = 'publisher', -- ['editorsurname'] = 'editor-surname', -- remove after 2016-01-01 ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', -- ['ended'] = 'date', -- remove after 2016-01-01 ['enlaceautor'] = 'author-link', -- Spanish ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', ['herausgeber'] = 'editors', -- German (singular and plural) ['idioma'] = 'language', -- Spanish, Italian ['imię'] = 'first', -- Polish ['isbnistformalfalsch'] = 'ignore-isbn-error', -- German ['isnb'] = 'isbn', ['jahr'] = 'year', -- German ['kapitel'] = 'chapter', -- German -- ['kommentar'] = 'comment', -- German (not yet supported by us) ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License ...') ['loaction'] = 'location', ['locatoin'] = 'location', ['lugar'] = 'location', -- Spanish ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['nummer'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'dead-url', -- German ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opublikowany'] = 'agency', -- Polish ['opera'] = 'work', -- Italian ['origdate'] = 'orig-year', ['originaljahr'] = 'orig-year', -- German ['originalort'] = 'location', -- German (if 'ort' is specified at the same time, the latter should be put in 'publication-place') ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'location', -- German ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['praca'] = 'work', -- Polish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubisher'] = 'publisher', -- ['publiser'] = 'publisher', -- ['publishers'] = 'publisher', -- ['publsher'] = 'publisher', -- ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', -- ['pulbisher'] = 'publisher', -- ['pulisher'] = 'publisher', ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['seiten'] = 'pages', -- German -- ['separator'] = 'mode', -- remove after 2016-01-01 ['seria'] = 'series', -- Polish ['série'] = 'work', -- French *RECHECK* ['service'] = 'agency', ['sitioweb'] = 'website', --Spanish ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['suscripción'] = 'subscription', -- Spanish, Polish ['tag'] = 'date', -- German ['tile'] = 'title', ['tite'] = 'title', ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['ubicación'] = 'location', -- Spanish ['urlarchivo'] = 'archive-url', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') (not yet supported by us directly) ['übersetzer'] = 'translator', -- German (singular and plural) ['verlag'] = 'publisher', -- German ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') (not yet supported by us directly) ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not regex though they are similar. The escape character is '%', not '\'. For more information about lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', ['^a[utho]+r$'] = 'author', ['^a[utho]+r(%d+)$'] = 'author$1', -- enumerated ['^pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; 7z8ytza1cvny3fj8xgw6be5ptn83kia 736793 736792 2016-05-24T12:34:04Z en>Moroboshi 0 Undid revision 721850149 by [[Special:Contributions/Moroboshi|Moroboshi]] ([[User talk:Moroboshi|talk]]) 736793 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { -- ['acccessdate'] = 'access-date', -- ['accesdate'] = 'access-date', -- ['access date'] = 'access-date', -- ['accessate'] = 'access-date', -- ['accessdare'] = 'access-date', -- ['accessdatte'] = 'access-date', -- ['accessddate'] = 'access-date', -- ['accessdte'] = 'access-date', -- ['accessed'] = 'access-date', -- ['accessedate'] = 'access-date', -- ['accesssdate'] = 'access-date', -- ['accssdate'] = 'access-date', -- ['acessdate'] = 'access-date', ['accessmonth'] = 'access-date', -- (no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date') ['accessyear'] = 'access-date', -- (no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date') ['address'] = 'location', ['année'] = 'year', -- French ['año'] = 'year', ['año-original'] = 'orig-year', ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archiv-datum'] = 'archive-date', -- German ['archive date'] = 'archive-date', ['archiv-url'] = 'archive-url', -- German ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', -- ['authorformat'] = 'name-list-format', -- remove after 2016-01-01 -- ['author-format'] = 'name-list-format', -- remove after 2016-01-01 ['author link'] = 'author-link', -- Polish ['author link2'] = 'author2-link', -- Polish -- ['autor'] = 'author', -- Spanish, Italian, Polish ['autor'] = 'authors', -- German (singular and plural) -- ['autor2'] = 'author2', -- Spanish, Italian, Polish -- ['autor3'] = 'author3', -- Polish ['autthor'] = 'author', ['band'] = 'volume', -- German -- ['began'] = 'date', -- remove after 2016-01-01 ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French ['czasopismo'] = 'journal', -- Polish ['data'] = 'date', -- Polish ['data dostępu'] = 'access-date', -- Polish ['datum'] = 'date', -- German ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') (not yet supported by us directly) ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', -- ['editorformat'] = 'name-list-format', -- remove after 2016-01-01 -- ['editor-format'] = 'name-list-format', -- remove after 2016-01-01 -- ['editorgiven'] = 'editor-given', -- remove after 2016-01-01 ['editorial'] = 'publisher', -- ['editorsurname'] = 'editor-surname', -- remove after 2016-01-01 ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', -- ['ended'] = 'date', -- remove after 2016-01-01 ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', ['herausgeber'] = 'editors', -- German (singular and plural) ['idioma'] = 'language', -- Spanish, Italian ['imię'] = 'first', -- Polish ['isbnistformalfalsch'] = 'ignore-isbn-error', -- German ['isnb'] = 'isbn', ['jahr'] = 'year', -- German ['kapitel'] = 'chapter', -- German -- ['kommentar'] = 'comment', -- German (not yet supported by us) ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License ...') ['loaction'] = 'location', ['locatoin'] = 'location', ['lugar'] = 'location', -- Spanish ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['nummer'] = 'number', -- German ['obra'] = 'work', -- Spanish, Italian ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'dead-url', -- German ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opublikowany'] = 'agency', -- Polish ['origdate'] = 'orig-year', ['originaljahr'] = 'orig-year', -- German ['originalort'] = 'location', -- German (if 'ort' is specified at the same time, the latter should be put in 'publication-place') ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'location', -- German ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['praca'] = 'work', -- Polish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubisher'] = 'publisher', -- ['publiser'] = 'publisher', -- ['publishers'] = 'publisher', -- ['publsher'] = 'publisher', -- ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', -- ['pulbisher'] = 'publisher', -- ['pulisher'] = 'publisher', ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['seiten'] = 'pages', -- German -- ['separator'] = 'mode', -- remove after 2016-01-01 ['seria'] = 'series', -- Polish ['série'] = 'work', -- French *RECHECK* ['service'] = 'agency', ['sitioweb'] = 'website', --Spanish ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['suscripción'] = 'subscription', -- Spanish, Italian, Polish ['tag'] = 'date', -- German ['tile'] = 'title', ['tite'] = 'title', ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') (not yet supported by us directly) ['übersetzer'] = 'translator', -- German (singular and plural) ['verlag'] = 'publisher', -- German ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') (not yet supported by us directly) ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not regex though they are similar. The escape character is '%', not '\'. For more information about lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', ['^a[utho]+r$'] = 'author', ['^a[utho]+r(%d+)$'] = 'author$1', -- enumerated ['^pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; m9r4bd8z0xh79y2rny8loerdiwqxhqj 736794 736793 2016-11-20T20:59:19Z en>Trappist the monk 0 some Norwegian parameters; 736794 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { -- ['acccessdate'] = 'access-date', -- ['accesdate'] = 'access-date', -- ['access date'] = 'access-date', -- ['accessate'] = 'access-date', -- ['accessdare'] = 'access-date', -- ['accessdatte'] = 'access-date', -- ['accessddate'] = 'access-date', -- ['accessdte'] = 'access-date', -- ['accessed'] = 'access-date', -- ['accessedate'] = 'access-date', -- ['accesssdate'] = 'access-date', -- ['accssdate'] = 'access-date', -- ['acessdate'] = 'access-date', ['accessmonth'] = 'access-date', -- (no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date') ['accessyear'] = 'access-date', -- (no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date') ['address'] = 'location', ['année'] = 'year', -- French ['año'] = 'year', ['año-original'] = 'orig-year', ['añoacceso'] = 'access-date', -- Spanish, Italian ['apellido'] = 'last', -- Spanish, Italian ['archiv-datum'] = 'archive-date', -- German ['archive date'] = 'archive-date', ['archiv-url'] = 'archive-url', -- German ['archive url'] = 'archive-url', -- Spanish, Italian ['artist'] = 'others', ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', -- ['authorformat'] = 'name-list-format', -- remove after 2016-01-01 -- ['author-format'] = 'name-list-format', -- remove after 2016-01-01 ['author link'] = 'author-link', -- Polish ['author link2'] = 'author2-link', -- Polish -- ['autor'] = 'author', -- Spanish, Italian, Polish ['autor'] = 'authors', -- German (singular and plural) -- ['autor2'] = 'author2', -- Spanish, Italian, Polish -- ['autor3'] = 'author3', -- Polish ['autthor'] = 'author', ['band'] = 'volume', -- German -- ['began'] = 'date', -- remove after 2016-01-01 ['bind'] = 'volume', -- Norwegian ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish, Italian ['coautores'] = 'coauthors', -- Spanish, Italian ['consulté le'] = 'access-date', -- French ['czasopismo'] = 'journal', -- Polish ['data'] = 'date', -- Polish ['data dostępu'] = 'access-date', -- Polish ['datum'] = 'date', -- German ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') (not yet supported by us directly) ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', -- ['editorformat'] = 'name-list-format', -- remove after 2016-01-01 -- ['editor-format'] = 'name-list-format', -- remove after 2016-01-01 -- ['editorgiven'] = 'editor-given', -- remove after 2016-01-01 ['editorial'] = 'publisher', -- ['editorsurname'] = 'editor-surname', -- remove after 2016-01-01 ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', -- ['ended'] = 'date', -- remove after 2016-01-01 ['enlaceautor'] = 'author-link', -- Spanish, Italian ['fecha'] = 'date', -- Spanish, Italian ['fechaacceso'] = 'access-date', -- Spanish, Italian ['fechaarchivo'] = 'archive-date', -- Spanish, Italian ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['forfatter'] = 'author', -- Norwegian ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', ['herausgeber'] = 'editors', -- German (singular and plural) ['idioma'] = 'language', -- Spanish, Italian ['imię'] = 'first', -- Polish ['isbnistformalfalsch'] = 'ignore-isbn-error', -- German ['isnb'] = 'isbn', ['jahr'] = 'year', -- German ['kapitel'] = 'chapter', -- German -- ['kommentar'] = 'comment', -- German (not yet supported by us) ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License ...') ['loaction'] = 'location', ['locatoin'] = 'location', ['lugar'] = 'location', -- Spanish ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish, Italian ['nummer'] = 'number', -- German, Norwegian ['obra'] = 'work', -- Spanish, Italian ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'dead-url', -- German ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opublikowany'] = 'agency', -- Polish ['origdate'] = 'orig-year', ['originaljahr'] = 'orig-year', -- German ['originalort'] = 'location', -- German (if 'ort' is specified at the same time, the latter should be put in 'publication-place') ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'location', -- German ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['praca'] = 'work', -- Polish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', ['publikasjon'] = 'journal', -- Norwegian: publication -- ['pubisher'] = 'publisher', -- ['publiser'] = 'publisher', -- ['publishers'] = 'publisher', -- ['publsher'] = 'publisher', -- ['publsiher'] = 'publisher', ['pulbication-place'] = 'publication-place', -- ['pulbisher'] = 'publisher', -- ['pulisher'] = 'publisher', ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['seiten'] = 'pages', -- German -- ['separator'] = 'mode', -- remove after 2016-01-01 ['seria'] = 'series', -- Polish ['série'] = 'work', -- French *RECHECK* ['service'] = 'agency', ['side'] = 'page', -- Norwegian ['sitioweb'] = 'website', --Spanish ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['suscripción'] = 'subscription', -- Spanish, Italian, Polish ['tag'] = 'date', -- German ['tile'] = 'title', ['tite'] = 'title', ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['tittel'] = 'title', -- Norwegian ['títle'] = 'title', ['título'] = 'title', -- Spanish, Italian ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['ubicación'] = 'location', -- Spanish, Italian ['urlarchivo'] = 'archive-url', -- Spanish, Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') (not yet supported by us directly) ['übersetzer'] = 'translator', -- German (singular and plural) ['utgivelsesår'] = 'year', -- Norwegian: release year ['verlag'] = 'publisher', -- German ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') (not yet supported by us directly) ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not regex though they are similar. The escape character is '%', not '\'. For more information about lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', ['^a[utho]+r$'] = 'author', ['^a[utho]+r(%d+)$'] = 'author$1', -- enumerated ['^pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; bo080ruxmbasn2hdzu8zgm2l92wwp95 736795 736794 2017-04-29T09:38:17Z en>Trappist the monk 0 synch from sandbox; 736795 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['accessmonth'] = 'access-date', -- no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date' ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', -- no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date' ['address'] = 'location', ['année'] = 'year', -- French ['año'] = 'year', ['año-original'] = 'orig-year', ['añoacceso'] = 'access-date', -- Spanish ['annoaccesso'] = 'access-date', --Italian ['annodiaccesso'] = 'access-date', --Italian ['apellido'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archive date'] = 'archive-date', ['archiv-url'] = 'archive-url', -- German ['archive url'] = 'archive-url', -- Spanish ['artist'] = 'others', ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'author-link', -- Polish ['author link2'] = 'author2-link', -- Polish ['autor'] = 'authors', -- German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', ['band'] = 'volume', -- German ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['consulté le'] = 'access-date', -- French ['czasopismo'] = 'journal', -- Polish ['data'] = 'date', -- Polish, Italian ['dataarchivio'] = 'archive-date', -- Italian ['data dostępu'] = 'access-date', -- Polish ['datum'] = 'date', -- German ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') (not yet supported by us directly) ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorial'] = 'publisher', ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', ['herausgeber'] = 'editors', -- German (singular and plural) ['idioma'] = 'language', -- Spanish, Italian ['imię'] = 'first', -- Polish ['isbnistformalfalsch'] = 'ignore-isbn-error', -- German ['isnb'] = 'isbn', ['jahr'] = 'year', -- German ['kapitel'] = 'chapter', -- German -- ['kommentar'] = 'comment', -- German (not yet supported by us) ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License ...') ['loaction'] = 'location', ['locatoin'] = 'location', ['lugar'] = 'location', -- Spanish ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['nummer'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'dead-url', -- German ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opublikowany'] = 'agency', -- Polish ['opera'] = 'work', -- Italian ['origdate'] = 'orig-year', ['originaljahr'] = 'orig-year', -- German ['originalort'] = 'location', -- German (if 'ort' is specified at the same time, the latter should be put in 'publication-place') ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'location', -- German ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['praca'] = 'work', -- Polish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', ['pulbication-place'] = 'publication-place', ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['seiten'] = 'pages', -- German ['seria'] = 'series', -- Polish ['série'] = 'work', -- French *RECHECK* ['service'] = 'agency', ['sitioweb'] = 'website', --Spanish ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['suscripción'] = 'subscription', -- Spanish, Polish ['tag'] = 'date', -- German ['tile'] = 'title', ['tite'] = 'title', ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['ubicación'] = 'location', -- Spanish ['urlarchivo'] = 'archive-url', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') (not yet supported by us directly) ['übersetzer'] = 'translator', -- German (singular and plural) ['verlag'] = 'publisher', -- German ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') (not yet supported by us directly) ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not regex though they are similar. The escape character is '%', not '\'. For more information about lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', ['^a[utho]+r$'] = 'author', ['^a[utho]+r(%d+)$'] = 'author$1', -- enumerated ['^pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; js6xozslbdgyigcumx6taxh33cortcl 736796 736795 2019-01-21T23:49:41Z en>Meltdown627 0 added "sito" 736796 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['accessmonth'] = 'access-date', -- no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date' ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', -- no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date' ['address'] = 'location', ['année'] = 'year', -- French ['año'] = 'year', ['año-original'] = 'orig-year', ['añoacceso'] = 'access-date', -- Spanish ['annoaccesso'] = 'access-date', --Italian ['annodiaccesso'] = 'access-date', --Italian ['apellido'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archive date'] = 'archive-date', ['archiv-url'] = 'archive-url', -- German ['archive url'] = 'archive-url', -- Spanish ['artist'] = 'others', ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'author-link', -- Polish ['author link2'] = 'author2-link', -- Polish ['autor'] = 'authors', -- German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', ['band'] = 'volume', -- German ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['consulté le'] = 'access-date', -- French ['czasopismo'] = 'journal', -- Polish ['data'] = 'date', -- Polish, Italian ['dataarchivio'] = 'archive-date', -- Italian ['data dostępu'] = 'access-date', -- Polish ['datum'] = 'date', -- German ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') (not yet supported by us directly) ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editorial'] = 'publisher', ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', ['herausgeber'] = 'editors', -- German (singular and plural) ['idioma'] = 'language', -- Spanish, Italian ['imię'] = 'first', -- Polish ['isbnistformalfalsch'] = 'ignore-isbn-error', -- German ['isnb'] = 'isbn', ['jahr'] = 'year', -- German ['kapitel'] = 'chapter', -- German -- ['kommentar'] = 'comment', -- German (not yet supported by us) ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License ...') ['loaction'] = 'location', ['locatoin'] = 'location', ['lugar'] = 'location', -- Spanish ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['nummer'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'dead-url', -- German ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opublikowany'] = 'agency', -- Polish ['opera'] = 'work', -- Italian ['origdate'] = 'orig-year', ['originaljahr'] = 'orig-year', -- German ['originalort'] = 'location', -- German (if 'ort' is specified at the same time, the latter should be put in 'publication-place') ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'location', -- German ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['praca'] = 'work', -- Polish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', ['pulbication-place'] = 'publication-place', ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['seiten'] = 'pages', -- German ['seria'] = 'series', -- Polish ['série'] = 'work', -- French *RECHECK* ['service'] = 'agency', ['sitioweb'] = 'website', --Spanish ['sito'] = 'website', --Italian ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['suscripción'] = 'subscription', -- Spanish, Polish ['tag'] = 'date', -- German ['tile'] = 'title', ['tite'] = 'title', ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['ubicación'] = 'location', -- Spanish ['urlarchivo'] = 'archive-url', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') (not yet supported by us directly) ['übersetzer'] = 'translator', -- German (singular and plural) ['verlag'] = 'publisher', -- German ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') (not yet supported by us directly) ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not regex though they are similar. The escape character is '%', not '\'. For more information about lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', ['^a[utho]+r$'] = 'author', ['^a[utho]+r(%d+)$'] = 'author$1', -- enumerated ['^pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; hp8bpglf82rjhjb0ka8e4p2aj76ima9 736797 736796 2019-07-21T16:39:01Z en>Trappist the monk 0 +editora (pt); 736797 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['accessmonth'] = 'access-date', -- no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date' ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', -- no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date' ['address'] = 'location', ['année'] = 'year', -- French ['año'] = 'year', ['año-original'] = 'orig-year', ['añoacceso'] = 'access-date', -- Spanish ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['apellido'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archive date'] = 'archive-date', ['archiv-url'] = 'archive-url', -- German ['archive url'] = 'archive-url', -- Spanish ['artist'] = 'others', ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'author-link', -- Polish ['author link2'] = 'author2-link', -- Polish ['autor'] = 'authors', -- German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', ['band'] = 'volume', -- German ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['consulté le'] = 'access-date', -- French ['czasopismo'] = 'journal', -- Polish ['data'] = 'date', -- Polish, Italian ['dataarchivio'] = 'archive-date', -- Italian ['data dostępu'] = 'access-date', -- Polish ['datum'] = 'date', -- German ['deadlink'] = 'dead-url', ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') (not yet supported by us directly) ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editora'] = 'publisher', -- Portuguese ['editorial'] = 'publisher', ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', ['herausgeber'] = 'editors', -- German (singular and plural) ['idioma'] = 'language', -- Spanish, Italian ['imię'] = 'first', -- Polish ['isbnistformalfalsch'] = 'ignore-isbn-error', -- German ['isnb'] = 'isbn', ['jahr'] = 'year', -- German ['kapitel'] = 'chapter', -- German -- ['kommentar'] = 'comment', -- German (not yet supported by us) ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License ...') ['loaction'] = 'location', ['locatoin'] = 'location', ['lugar'] = 'location', -- Spanish ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['nummer'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'dead-url', -- German ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opublikowany'] = 'agency', -- Polish ['opera'] = 'work', -- Italian ['origdate'] = 'orig-year', ['originaljahr'] = 'orig-year', -- German ['originalort'] = 'location', -- German (if 'ort' is specified at the same time, the latter should be put in 'publication-place') ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'location', -- German ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['praca'] = 'work', -- Polish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', ['pulbication-place'] = 'publication-place', ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['seiten'] = 'pages', -- German ['seria'] = 'series', -- Polish ['série'] = 'work', -- French *RECHECK* ['service'] = 'agency', ['sitioweb'] = 'website', --Spanish ['sito'] = 'website', --Italian ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['suscripción'] = 'subscription', -- Spanish, Polish ['tag'] = 'date', -- German ['tile'] = 'title', ['tite'] = 'title', ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['ubicación'] = 'location', -- Spanish ['urlarchivo'] = 'archive-url', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') (not yet supported by us directly) ['übersetzer'] = 'translator', -- German (singular and plural) ['verlag'] = 'publisher', -- German ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') (not yet supported by us directly) ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not regex though they are similar. The escape character is '%', not '\'. For more information about lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', ['^a[utho]+r$'] = 'author', ['^a[utho]+r(%d+)$'] = 'author$1', -- enumerated ['^pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; jx0q04e5yd2dlgy72ys42gz4ls24v8e 736798 736797 2019-09-29T20:25:13Z en>Brainulator9 0 Replacing dead-url with url-status 736798 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['accessmonth'] = 'access-date', -- no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date' ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', -- no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date' ['address'] = 'location', ['année'] = 'year', -- French ['año'] = 'year', ['año-original'] = 'orig-year', ['añoacceso'] = 'access-date', -- Spanish ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['apellido'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archive date'] = 'archive-date', ['archiv-url'] = 'archive-url', -- German ['archive url'] = 'archive-url', -- Spanish ['artist'] = 'others', ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'author-link', -- Polish ['author link2'] = 'author2-link', -- Polish ['autor'] = 'authors', -- German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', ['band'] = 'volume', -- German ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['consulté le'] = 'access-date', -- French ['czasopismo'] = 'journal', -- Polish ['data'] = 'date', -- Polish, Italian ['dataarchivio'] = 'archive-date', -- Italian ['data dostępu'] = 'access-date', -- Polish ['datum'] = 'date', -- German ['deadlink'] = 'url-status', ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') (not yet supported by us directly) ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editora'] = 'publisher', -- Portuguese ['editorial'] = 'publisher', ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', ['herausgeber'] = 'editors', -- German (singular and plural) ['idioma'] = 'language', -- Spanish, Italian ['imię'] = 'first', -- Polish ['isbnistformalfalsch'] = 'ignore-isbn-error', -- German ['isnb'] = 'isbn', ['jahr'] = 'year', -- German ['kapitel'] = 'chapter', -- German -- ['kommentar'] = 'comment', -- German (not yet supported by us) ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License ...') ['loaction'] = 'location', ['locatoin'] = 'location', ['lugar'] = 'location', -- Spanish ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['nummer'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'url-status', -- German ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opublikowany'] = 'agency', -- Polish ['opera'] = 'work', -- Italian ['origdate'] = 'orig-year', ['originaljahr'] = 'orig-year', -- German ['originalort'] = 'location', -- German (if 'ort' is specified at the same time, the latter should be put in 'publication-place') ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'location', -- German ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['praca'] = 'work', -- Polish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', ['pulbication-place'] = 'publication-place', ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['seiten'] = 'pages', -- German ['seria'] = 'series', -- Polish ['série'] = 'work', -- French *RECHECK* ['service'] = 'agency', ['sitioweb'] = 'website', --Spanish ['sito'] = 'website', --Italian ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['suscripción'] = 'subscription', -- Spanish, Polish ['tag'] = 'date', -- German ['tile'] = 'title', ['tite'] = 'title', ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['ubicación'] = 'location', -- Spanish ['urlarchivo'] = 'archive-url', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') (not yet supported by us directly) ['übersetzer'] = 'translator', -- German (singular and plural) ['verlag'] = 'publisher', -- German ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') (not yet supported by us directly) ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not regex though they are similar. The escape character is '%', not '\'. For more information about lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', ['^a[utho]+r$'] = 'author', ['^a[utho]+r(%d+)$'] = 'author$1', -- enumerated ['^pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; q2jz6t9017qwiabapa4vok8lfaejg0y 736799 736798 2020-04-19T01:13:10Z en>DannyS712 0 extraneous tab 736799 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['accessmonth'] = 'access-date', -- no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date' ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', -- no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date' ['address'] = 'location', ['année'] = 'year', -- French ['año'] = 'year', ['año-original'] = 'orig-year', ['añoacceso'] = 'access-date', -- Spanish ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['apellido'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archive date'] = 'archive-date', ['archiv-url'] = 'archive-url', -- German ['archive url'] = 'archive-url', -- Spanish ['artist'] = 'others', ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'author-link', -- Polish ['author link2'] = 'author2-link', -- Polish ['autor'] = 'authors', -- German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', ['band'] = 'volume', -- German ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['consulté le'] = 'access-date', -- French ['czasopismo'] = 'journal', -- Polish ['data'] = 'date', -- Polish, Italian ['dataarchivio'] = 'archive-date', -- Italian ['data dostępu'] = 'access-date', -- Polish ['datum'] = 'date', -- German ['deadlink'] = 'url-status', ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') (not yet supported by us directly) ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editora'] = 'publisher', -- Portuguese ['editorial'] = 'publisher', ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', ['herausgeber'] = 'editors', -- German (singular and plural) ['idioma'] = 'language', -- Spanish, Italian ['imię'] = 'first', -- Polish ['isbnistformalfalsch'] = 'ignore-isbn-error', -- German ['isnb'] = 'isbn', ['jahr'] = 'year', -- German ['kapitel'] = 'chapter', -- German -- ['kommentar'] = 'comment', -- German (not yet supported by us) ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License ...') ['loaction'] = 'location', ['locatoin'] = 'location', ['lugar'] = 'location', -- Spanish ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['nummer'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'url-status', -- German ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opublikowany'] = 'agency', -- Polish ['opera'] = 'work', -- Italian ['origdate'] = 'orig-year', ['originaljahr'] = 'orig-year', -- German ['originalort'] = 'location', -- German (if 'ort' is specified at the same time, the latter should be put in 'publication-place') ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'location', -- German ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['praca'] = 'work', -- Polish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', ['pulbication-place'] = 'publication-place', ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['seiten'] = 'pages', -- German ['seria'] = 'series', -- Polish ['série'] = 'work', -- French *RECHECK* ['service'] = 'agency', ['sitioweb'] = 'website', --Spanish ['sito'] = 'website', --Italian ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['suscripción'] = 'subscription', -- Spanish, Polish ['tag'] = 'date', -- German ['tile'] = 'title', ['tite'] = 'title', ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['ubicación'] = 'location', -- Spanish ['urlarchivo'] = 'archive-url', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') (not yet supported by us directly) ['übersetzer'] = 'translator', -- German (singular and plural) ['verlag'] = 'publisher', -- German ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') (not yet supported by us directly) ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not regex though they are similar. The escape character is '%', not '\'. For more information about lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', ['^a[utho]+r$'] = 'author', ['^a[utho]+r(%d+)$'] = 'author$1', -- enumerated ['^pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; g2v4y0h5da21a8c63euup6eax6fae7t 736800 736799 2020-04-19T11:26:29Z en>Trappist the monk 0 Undid revision 951812985 by [[Special:Contributions/DannyS712|DannyS712]] ([[User talk:DannyS712|talk]]) unproductive change to coding style; 736800 Scribunto text/plain --Please insert new suggestions in alphabetical order --The form is ['incorrect'] = 'correct', suggestions = { ['accessmonth'] = 'access-date', -- no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date' ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', -- no longer supported by us, but still by citation templates mirrored in foreign WPs; can be emulated using 'access-date' ['address'] = 'location', ['année'] = 'year', -- French ['año'] = 'year', ['año-original'] = 'orig-year', ['añoacceso'] = 'access-date', -- Spanish ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['apellido'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archive date'] = 'archive-date', ['archiv-url'] = 'archive-url', -- German ['archive url'] = 'archive-url', -- Spanish ['artist'] = 'others', ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'author-link', -- Polish ['author link2'] = 'author2-link', -- Polish ['autor'] = 'authors', -- German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', ['band'] = 'volume', -- German ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['consulté le'] = 'access-date', -- French ['czasopismo'] = 'journal', -- Polish ['data'] = 'date', -- Polish, Italian ['dataarchivio'] = 'archive-date', -- Italian ['data dostępu'] = 'access-date', -- Polish ['datum'] = 'date', -- German ['deadlink'] = 'url-status', ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') (not yet supported by us directly) ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editora'] = 'publisher', -- Portuguese ['editorial'] = 'publisher', ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', ['herausgeber'] = 'editors', -- German (singular and plural) ['idioma'] = 'language', -- Spanish, Italian ['imię'] = 'first', -- Polish ['isbnistformalfalsch'] = 'ignore-isbn-error', -- German ['isnb'] = 'isbn', ['jahr'] = 'year', -- German ['kapitel'] = 'chapter', -- German -- ['kommentar'] = 'comment', -- German (not yet supported by us) ['lang'] = 'language', ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License ...') ['loaction'] = 'location', ['locatoin'] = 'location', ['lugar'] = 'location', -- Spanish ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['nummer'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'url-status', -- German ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opublikowany'] = 'agency', -- Polish ['opera'] = 'work', -- Italian ['origdate'] = 'orig-year', ['originaljahr'] = 'orig-year', -- German ['originalort'] = 'location', -- German (if 'ort' is specified at the same time, the latter should be put in 'publication-place') ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'location', -- German ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['praca'] = 'work', -- Polish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', ['pulbication-place'] = 'publication-place', ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['seiten'] = 'pages', -- German ['seria'] = 'series', -- Polish ['série'] = 'work', -- French *RECHECK* ['service'] = 'agency', ['sitioweb'] = 'website', --Spanish ['sito'] = 'website', --Italian ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['suscripción'] = 'subscription', -- Spanish, Polish ['tag'] = 'date', -- German ['tile'] = 'title', ['tite'] = 'title', ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish ['transchapter'] = 'trans-chapter', ['translator'] = 'others', ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['ubicación'] = 'location', -- Spanish ['urlarchivo'] = 'archive-url', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') (not yet supported by us directly) ['übersetzer'] = 'translator', -- German (singular and plural) ['verlag'] = 'publisher', -- German ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') (not yet supported by us directly) ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not regex though they are similar. The escape character is '%', not '\'. For more information about lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', ['^a[utho]+r$'] = 'author', ['^a[utho]+r(%d+)$'] = 'author$1', -- enumerated ['^pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; q2jz6t9017qwiabapa4vok8lfaejg0y 736801 736800 2020-07-11T13:18:06Z en>Trappist the monk 0 sync from sandbox; 736801 Scribunto text/plain -- Please insert new suggestions in alphabetical order -- The form is ['incorrect'] = 'correct', suggestions = { ['abruf'] = 'access-date', -- German ['abruf-verborgen'] = 'access-date', -- German ['accessmonth'] = 'access-date', ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', ['address'] = 'location', ['année'] = 'date', -- French ['año'] = 'date', ['año-original'] = 'orig-year', ['añoacceso'] = 'access-date', -- Spanish ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['apellido'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archive date'] = 'archive-date', ['archiv-url'] = 'archive-url', -- German ['archive url'] = 'archive-url', -- Spanish ['artikelnr'] = 'id', -- German (as 'id=Article No. ...') ['artist'] = 'others', ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'author-link', -- Polish ['author link2'] = 'author2-link', -- Polish ['autor'] = 'author', -- German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', ['band'] = 'volume', -- German ['bandreihe'] = 'volume', -- German ['ch'] = 'language', -- German (as 'language=de-CH') ['chapter_title'] = 'chapter', ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['consulté le'] = 'access-date', -- French ['czasopismo'] = 'journal', -- Polish ['data'] = 'date', -- Polish, Italian ['dataarchivio'] = 'archive-date', -- Italian ['data dostępu'] = 'access-date', -- Polish ['datum'] = 'date', -- German ['deadlink'] = 'url-status', ['deadurl'] = 'url-status', ['dead-url'] = 'url-status', ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') ['doi_brokendate'] = 'doi-broken-date', ['doi_inactivedate'] = 'doi-inactive-date', ['éditeur'] = 'editor', -- French ['editon'] = 'edition', ['editoin'] = 'edition', ['editora'] = 'publisher', -- Portuguese ['editorial'] = 'publisher', ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['first 1'] = 'first1', ['foramt'] = 'format', ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', ['fundstelle'] = 'at', -- German ['herausgeber'] = 'editor', -- German (singular and plural) ['hrsg'] = 'publisher', -- German ['hrsgreihe'] = 'editor', -- German ['idioma'] = 'language', -- Spanish, Italian ['imię'] = 'first', -- Polish ['isbndefekt'] = 'ignore-isbn-error', -- German ['isbnformalfalsch'] = 'ignore-isbn-error', -- German ['isbnistformalfalsch'] = 'ignore-isbn-error', -- German ['isnb'] = 'isbn', ['issnformalfalsch'] = 'ignore-issn-error', -- German ['jahr'] = 'date', -- German ['jahrea'] = 'orig-year', -- German (not a direct replacement, but can be emulated) ['kapitel'] = 'chapter', -- German ['langauge'] = 'language', ['langue'] = 'language', -- French ['last 1'] = 'last1', ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', ['locatoin'] = 'location', ['lugar'] = 'location', -- Spanish ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', ['newpaper'] = 'newspaper', ['news'] = 'newspaper', ['nom'] = 'last', -- French ['nom1'] = 'last1', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['nummer'] = 'number', -- German ['nummerreihe'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'url-status', -- German (as 'url-status=dead') ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opublikowany'] = 'agency', -- Polish ['opera'] = 'work', -- Italian ['origdate'] = 'orig-year', ['originaljahr'] = 'orig-year', -- German ['originalort'] = 'publication-place', -- German ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'publication-place', -- German ['ortea'] = 'publication-place', -- German (not a direct replacement, but can be emulated) ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', ['página'] = 'page', -- Spanish, Italian ['páginas'] = 'pages', -- Spanish, Italian ['passage'] = 'pages', -- French ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', ['pmcid'] = 'pmc', ['praca'] = 'work', -- Polish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', ['pulbication-place'] = 'publication-place', ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['seria'] = 'series', -- Polish ['série'] = 'series', -- French ['service'] = 'agency', ['sitioweb'] = 'website', -- Spanish ['sito'] = 'website', -- Italian ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['suscripción'] = 'url-access', -- Spanish, Polish (as |url-access=subscription) ['tag'] = 'date', -- German ['template doc demo'] = 'template-doc-demo', ['tile'] = 'title', ['tite'] = 'title', ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titolo'] = 'title', -- Spanish, Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish ['transchapter'] = 'trans-chapter', ['trans_chapter'] = 'trans-chapter', ['trans_title'] = 'trans-title', ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['ubicación'] = 'location', -- Spanish ['urlarchivo'] = 'archive-url', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') ['übersetzer'] = 'translator', -- German (singular and plural) ['verlag'] = 'publisher', -- German ['verlagea'] = 'publisher', -- German (not a direct replacement, but can be emulated) ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not REGEX though they are similar. The escape character is '%', not '\'. For more information about Lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', ['^a[utho]+r$'] = 'author', ['^a[utho]+r(%d+)$'] = 'author$1', -- enumerated ['^pu[blish]+ers?$'] = 'publisher', } return {suggestions = suggestions, patterns=patterns}; l7auw5vzj9ly0o4n2jg6xns2wtxy157 736802 736801 2020-10-10T13:22:49Z en>Trappist the monk 0 sync from sandbox; 736802 Scribunto text/plain -- Please insert new suggestions in alphabetical order -- The form is ['incorrect'] = 'correct', suggestions = { ['abruf'] = 'access-date', -- German ['abruf-verborgen'] = 'access-date', -- German ['accessmonth'] = 'access-date', ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', ['address'] = 'location', ['année'] = 'date', -- French ['año'] = 'date', -- Spanish ['añooriginal'] = 'orig-date', -- Spanish ['año-original'] = 'orig-date', -- Spanish ['añoacceso'] = 'access-date', -- Spanish ['anno'] = 'date', -- Italian ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['annooriginale'] = 'orig-date', -- Italian ['apellido'] = 'last', -- Spanish ['apellidos'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archive date'] = 'archive-date', ['archiv-url'] = 'archive-url', -- German ['archive url'] = 'archive-url', -- Spanish ['artikelnr'] = 'id', -- German (as 'id=Article No. ...') ['artist'] = 'others', ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', ['authorfirst'] = 'author-first', -- old parameter name ['authorgiven'] = 'author-given', -- old parameter name ['authorlast'] = 'author-last', -- old parameter name ['author link'] = 'author-link', -- Polish ['authorsurname'] = 'author-surname', -- old parameter name ['autor'] = 'author', -- Spanish, German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', ['band'] = 'volume', -- German ['bandreihe'] = 'volume', -- German ['ch'] = 'language', -- German (as 'language=de-CH') ['chapter_title'] = 'chapter', ['cid'] = 'ref', -- Italian ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['città'] = 'location', -- Italian ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['consulté le'] = 'access-date', -- French ['curatore'] = 'publisher', -- Italian ['czasopismo'] = 'journal', -- Polish ['data'] = 'date', -- Polish, Italian ['dataaccesso'] = 'access-date', -- Italian ['dataarchivio'] = 'archive-date', -- Italian ['data dostępu'] = 'access-date', -- Polish ['datum'] = 'date', -- German ['deadlink'] = 'url-status', ['deadurl'] = 'url-status', -- old parameter name ['dead-url'] = 'url-status', -- old parameter name ['distributor'] = 'publisher', ['displayeditors'] = 'display-editors', -- old parameter name ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') ['doibroken'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-broken'] = 'doi-broken-date', -- former parameter alias ['doi_brokendate'] = 'doi-broken-date', ['doiinactive'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-inactive'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-inactive-date'] = 'doi-broken-date', -- former parameter alias ['doi_inactivedate'] = 'doi-inactive-date', --['ed'] = 'edition', avoid suggestion as in English this could be short for editor or edition ['éditeur'] = 'editor', -- French ['editon'] = 'edition', -- misspelling ['editoin'] = 'edition', -- misspelling -- ['editora'] = 'publisher', -- can be either editor or publisher -- ['editore'] = 'agency', -- can be either publisher or agency -- ['editori'] = 'editor', -- can be either editor or publisher -- ['editorial'] = 'publisher', -- can be either publisher or work ['editorfirst'] = 'editor-first', -- old parameter name ['editorgiven'] = 'editor-given', -- old parameter name ['editorlast'] = 'editor-last', -- old parameter name ['editormask'] = 'editor-mask', -- old parameter name ['editorsurname'] = 'editor-surname', -- old parameter name ['edizione'] = 'edition', -- Italian ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['enlaceroto'] = 'url-status', -- Spanish ['embargo'] = 'pmc-embargo-date', -- former parameter name ['e-print'] = 'eprint', -- misspelling ['family'] = 'surname', -- misguess ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['foramt'] = 'format', -- misspelling ['formato'] = 'format', -- Spanish, Italian, Polish ['forename'] = 'given', -- misguess ['fore-name'] = 'given', -- misguess/misspelling ['frist'] = 'first', -- misspelling ['fundstelle'] = 'at', -- German ['giornale'] = 'journal', -- Italian ['herausgeber'] = 'editor', -- German (singular and plural) ['hrsg'] = 'publisher', -- German ['hrsgreihe'] = 'editor', -- German ['idioma'] = 'language', -- Spanish ['ignoreisbnerror'] = 'isbn', -- former parameter alias (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['imię'] = 'first', -- Polish ['in-set'] = 'inset', -- misspelling ['interviewerlink'] = 'interviewer-link', -- former parameter alias ['interviewermask'] = 'interviewer-mask', -- former parameter alias ['isbndefekt'] = 'ignore-isbn-error', -- German ['isbnformalfalsch'] = 'ignore-isbn-error', -- German ['isbnistformalfalsch'] = 'ignore-isbn-error', -- German ['isnb'] = 'isbn', -- misspelling ['issnformalfalsch'] = 'ignore-issn-error', -- German ['jahr'] = 'date', -- German ['jahrea'] = 'orig-date', -- German (not a direct replacement, but can be emulated) ['kapitel'] = 'chapter', -- German ['langauge'] = 'language', -- misspelling ['langue'] = 'language', -- French ['laysummary'] = 'lay-url', -- old parameter ['lay-summary'] = 'lay-url', -- old parameter ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', -- misspelling ['locatoin'] = 'location', -- misspelling ['lugar'] = 'location', -- Spanish ['mes'] = 'date', -- Spanish (not a direct replacement) ['mese'] = 'date', -- Italian (not a direct replacement) ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', -- misspelling ['net-work'] = 'network', -- misspelling ['newpaper'] = 'newspaper', -- misspelling ['news'] = 'newspaper', ['news-group'] = 'newsgroup', -- misspelling ['news-paper'] = 'newspaper', -- misspelling ['no-cat'] = 'no-tracking', -- old parameter ['nom'] = 'last', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['numero'] = 'number', -- Italian, Spanish ['nummer'] = 'number', -- German ['nummerreihe'] = 'number', -- German ['notracking'] = 'no-tracking', -- old parameter ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'url-status', -- German (as 'url-status=dead') ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opera'] = 'work', -- Italian ['opublikowany'] = 'agency', -- Polish ['origdate'] = 'orig-date', -- misspelling ['originaljahr'] = 'orig-date', -- German ['originalort'] = 'publication-place', -- German ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'publication-place', -- German ['ortea'] = 'publication-place', -- German (not a direct replacement, but can be emulated) ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', -- misspelling ['pagina'] = 'page', -- Italian ['página'] = 'page', -- Spanish ['páginas'] = 'pages', -- Spanish ['pagine'] = 'pages', -- Italian ['passage'] = 'pages', -- French ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['periodico'] = 'magazine', -- Spanish ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', -- misspelling ['pmcid'] = 'pmc', ['post-script'] = 'postscript', -- misspelling ['praca'] = 'work', -- Polish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['primero'] = 'first', -- Spanish ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubblicazione'] = 'magazine', -- could be any kind of work -- ['publicación'] = 'journal', -- could be any kind of work ['pulbication-place'] = 'publication-place', -- misspelling ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['richiestasottoscrizione'] = 'url-access', -- Italian (as |url-access=subscription) ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['script-post'] = 'postscript', -- misspelling ['script-trans'] = 'transcript', -- misspelling ['seria'] = 'series', -- Spanish, Polish ['serie'] = 'series', -- Italian ['série'] = 'series', -- French ['service'] = 'agency', ['sitioweb'] = 'website', -- Spanish ['sito'] = 'website', -- Italian ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['sur-name'] = 'surname', -- misspelling ['suscripción'] = 'url-access', -- Spanish, Polish (as |url-access=subscription) ['tag'] = 'date', -- German ['template doc demo'] = 'no-tracking', -- old parameter ['tile'] = 'title', -- misspelling ['tipo'] = 'type', -- Italian ['tite'] = 'title', -- misspelling ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titolo'] = 'title', -- Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish ['transchapter'] = 'trans-chapter', ['trans_chapter'] = 'trans-chapter', ['transscript'] = 'transcript', -- misspelling ['trans-script'] = 'transcript', -- misspelling ['transscript-format'] = 'transcript-format', -- misspelling ['transscripturl'] = 'transcript-url', -- misspelling ['transscript-url'] = 'transcript-url', -- misspelling ['trans_title'] = 'trans-title', ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['ubicación'] = 'location', -- Spanish ['urlarchivo'] = 'archive-url', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urlmorto'] = 'url-status', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') ['übersetzer'] = 'translator', -- German (singular and plural) ['v-authors'] = 'vauthors', -- misspelling ['v-editors'] = 'veditors', -- misspelling ['verlag'] = 'publisher', -- German ['verlagea'] = 'publisher', -- German (not a direct replacement, but can be emulated) ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not REGEX though they are similar. The escape character is '%', not '\'. For more information about Lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', -- misspelling ['^apellido[s]?(%d+)$'] = 'last$1', -- Spanish, enumerated ['^a[utho]+r$'] = 'author', -- misspelling ['^a[utho]+r(%d+)$'] = 'author$1', -- misspelling, enumerated ['^author link(%d+)$'] = 'author-link$1', -- Polish, enumerated ['^autor[e]?(%d+)$'] = 'author$1', -- Italian/Spanish/German, enumerated ['^authorfirst(%d+)$'] = 'author-first$1', -- old parameter name, enumerated ['^author(%d+)first$'] = 'author-first$1', -- old parameter name, enumerated ['^authorgiven(%d+)$'] = 'author-given$1', -- old parameter name, enumerated ['^author(%d+)given$'] = 'author-given$1', -- old parameter name, enumerated ['^authorlast(%d+)$'] = 'author-last$1', -- old parameter name, enumerated ['^author(%d+)last$'] = 'author-last$1', -- old parameter name, enumerated ['^authorsurname(%d+)$'] = 'author-surname$1', -- old parameter name, enumerated ['^author(%d+)surname$'] = 'author-surname$1', -- old parameter name, enumerated ['^cognome(%d+)$'] = 'last$1', -- Italian, enumerated ['^editorfirst(%d+)$'] = 'editor-first$1', -- old parameter name, enumerated ['^editor(%d+)first$'] = 'editor-first$1', -- old parameter name, enumerated ['^editorgiven(%d+)$'] = 'editor-given$1', -- old parameter name, enumerated ['^editor(%d+)given$'] = 'editor-given$1', -- old parameter name, enumerated ['^editorlast(%d+)$'] = 'editor-last$1', -- old parameter name, enumerated ['^editor(%d+)last$'] = 'editor-last$1', -- old parameter name, enumerated ['^editormask(%d+)$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editor(%d+)mask$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editorsurname(%d+)$'] = 'editor-surname$1', -- old parameter name, enumerated ['^editor(%d+)surname$'] = 'editor-surname$1', -- old parameter name, enumerated ['^enlaceautore(%d+)$'] = 'author-link$1', -- Spanish, enumerated ['^first (%d+)$'] = 'first$1', -- enumerated ['^last (%d+)$'] = 'last$1', -- enumerated ['^nom[e]?(%d+)$'] = 'last$1', -- Italian/French, enumerated ['^nombre(%d+)$'] = 'first$1', -- Spanish, enumerated ['^primero(%d+)$'] = 'first$1', -- Spanish, enumerated ['^pu[blish]+ers?$'] = 'publisher', -- misspelling ['^wkautore(%d+)$'] = 'author-link$1', -- Italian, enumerated } return {suggestions = suggestions, patterns=patterns}; 8frsjrkbc4m7d88w8vw8nyscdhpf5oz 736803 736802 2020-10-13T21:27:11Z en>Pokechu22 0 Suggest site -> website 736803 Scribunto text/plain -- Please insert new suggestions in alphabetical order -- The form is ['incorrect'] = 'correct', suggestions = { ['abruf'] = 'access-date', -- German ['abruf-verborgen'] = 'access-date', -- German ['accessmonth'] = 'access-date', ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', ['address'] = 'location', ['année'] = 'date', -- French ['año'] = 'date', -- Spanish ['añooriginal'] = 'orig-date', -- Spanish ['año-original'] = 'orig-date', -- Spanish ['añoacceso'] = 'access-date', -- Spanish ['anno'] = 'date', -- Italian ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['annooriginale'] = 'orig-date', -- Italian ['apellido'] = 'last', -- Spanish ['apellidos'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archive date'] = 'archive-date', ['archiv-url'] = 'archive-url', -- German ['archive url'] = 'archive-url', -- Spanish ['artikelnr'] = 'id', -- German (as 'id=Article No. ...') ['artist'] = 'others', ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', ['authorfirst'] = 'author-first', -- old parameter name ['authorgiven'] = 'author-given', -- old parameter name ['authorlast'] = 'author-last', -- old parameter name ['author link'] = 'author-link', -- Polish ['authorsurname'] = 'author-surname', -- old parameter name ['autor'] = 'author', -- Spanish, German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', ['band'] = 'volume', -- German ['bandreihe'] = 'volume', -- German ['ch'] = 'language', -- German (as 'language=de-CH') ['chapter_title'] = 'chapter', ['cid'] = 'ref', -- Italian ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['città'] = 'location', -- Italian ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['consulté le'] = 'access-date', -- French ['curatore'] = 'publisher', -- Italian ['czasopismo'] = 'journal', -- Polish ['data'] = 'date', -- Polish, Italian ['dataaccesso'] = 'access-date', -- Italian ['dataarchivio'] = 'archive-date', -- Italian ['data dostępu'] = 'access-date', -- Polish ['datum'] = 'date', -- German ['deadlink'] = 'url-status', ['deadurl'] = 'url-status', -- old parameter name ['dead-url'] = 'url-status', -- old parameter name ['distributor'] = 'publisher', ['displayeditors'] = 'display-editors', -- old parameter name ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') ['doibroken'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-broken'] = 'doi-broken-date', -- former parameter alias ['doi_brokendate'] = 'doi-broken-date', ['doiinactive'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-inactive'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-inactive-date'] = 'doi-broken-date', -- former parameter alias ['doi_inactivedate'] = 'doi-inactive-date', --['ed'] = 'edition', avoid suggestion as in English this could be short for editor or edition ['éditeur'] = 'editor', -- French ['editon'] = 'edition', -- misspelling ['editoin'] = 'edition', -- misspelling -- ['editora'] = 'publisher', -- can be either editor or publisher -- ['editore'] = 'agency', -- can be either publisher or agency -- ['editori'] = 'editor', -- can be either editor or publisher -- ['editorial'] = 'publisher', -- can be either publisher or work ['editorfirst'] = 'editor-first', -- old parameter name ['editorgiven'] = 'editor-given', -- old parameter name ['editorlast'] = 'editor-last', -- old parameter name ['editormask'] = 'editor-mask', -- old parameter name ['editorsurname'] = 'editor-surname', -- old parameter name ['edizione'] = 'edition', -- Italian ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['enlaceroto'] = 'url-status', -- Spanish ['embargo'] = 'pmc-embargo-date', -- former parameter name ['e-print'] = 'eprint', -- misspelling ['family'] = 'surname', -- misguess ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['foramt'] = 'format', -- misspelling ['formato'] = 'format', -- Spanish, Italian, Polish ['forename'] = 'given', -- misguess ['fore-name'] = 'given', -- misguess/misspelling ['frist'] = 'first', -- misspelling ['fundstelle'] = 'at', -- German ['giornale'] = 'journal', -- Italian ['herausgeber'] = 'editor', -- German (singular and plural) ['hrsg'] = 'publisher', -- German ['hrsgreihe'] = 'editor', -- German ['idioma'] = 'language', -- Spanish ['ignoreisbnerror'] = 'isbn', -- former parameter alias (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['imię'] = 'first', -- Polish ['in-set'] = 'inset', -- misspelling ['interviewerlink'] = 'interviewer-link', -- former parameter alias ['interviewermask'] = 'interviewer-mask', -- former parameter alias ['isbndefekt'] = 'ignore-isbn-error', -- German ['isbnformalfalsch'] = 'ignore-isbn-error', -- German ['isbnistformalfalsch'] = 'ignore-isbn-error', -- German ['isnb'] = 'isbn', -- misspelling ['issnformalfalsch'] = 'ignore-issn-error', -- German ['jahr'] = 'date', -- German ['jahrea'] = 'orig-date', -- German (not a direct replacement, but can be emulated) ['kapitel'] = 'chapter', -- German ['langauge'] = 'language', -- misspelling ['langue'] = 'language', -- French ['laysummary'] = 'lay-url', -- old parameter ['lay-summary'] = 'lay-url', -- old parameter ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', -- misspelling ['locatoin'] = 'location', -- misspelling ['lugar'] = 'location', -- Spanish ['mes'] = 'date', -- Spanish (not a direct replacement) ['mese'] = 'date', -- Italian (not a direct replacement) ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', -- misspelling ['net-work'] = 'network', -- misspelling ['newpaper'] = 'newspaper', -- misspelling ['news'] = 'newspaper', ['news-group'] = 'newsgroup', -- misspelling ['news-paper'] = 'newspaper', -- misspelling ['no-cat'] = 'no-tracking', -- old parameter ['nom'] = 'last', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['numero'] = 'number', -- Italian, Spanish ['nummer'] = 'number', -- German ['nummerreihe'] = 'number', -- German ['notracking'] = 'no-tracking', -- old parameter ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'url-status', -- German (as 'url-status=dead') ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opera'] = 'work', -- Italian ['opublikowany'] = 'agency', -- Polish ['origdate'] = 'orig-date', -- misspelling ['originaljahr'] = 'orig-date', -- German ['originalort'] = 'publication-place', -- German ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'publication-place', -- German ['ortea'] = 'publication-place', -- German (not a direct replacement, but can be emulated) ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', -- misspelling ['pagina'] = 'page', -- Italian ['página'] = 'page', -- Spanish ['páginas'] = 'pages', -- Spanish ['pagine'] = 'pages', -- Italian ['passage'] = 'pages', -- French ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['periodico'] = 'magazine', -- Spanish ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', -- misspelling ['pmcid'] = 'pmc', ['post-script'] = 'postscript', -- misspelling ['praca'] = 'work', -- Polish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['primero'] = 'first', -- Spanish ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubblicazione'] = 'magazine', -- could be any kind of work -- ['publicación'] = 'journal', -- could be any kind of work ['pulbication-place'] = 'publication-place', -- misspelling ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['richiestasottoscrizione'] = 'url-access', -- Italian (as |url-access=subscription) ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['script-post'] = 'postscript', -- misspelling ['script-trans'] = 'transcript', -- misspelling ['seria'] = 'series', -- Spanish, Polish ['serie'] = 'series', -- Italian ['série'] = 'series', -- French ['service'] = 'agency', ['site'] = 'website', ['sitioweb'] = 'website', -- Spanish ['sito'] = 'website', -- Italian ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['sur-name'] = 'surname', -- misspelling ['suscripción'] = 'url-access', -- Spanish, Polish (as |url-access=subscription) ['tag'] = 'date', -- German ['template doc demo'] = 'no-tracking', -- old parameter ['tile'] = 'title', -- misspelling ['tipo'] = 'type', -- Italian ['tite'] = 'title', -- misspelling ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titolo'] = 'title', -- Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish ['transchapter'] = 'trans-chapter', ['trans_chapter'] = 'trans-chapter', ['transscript'] = 'transcript', -- misspelling ['trans-script'] = 'transcript', -- misspelling ['transscript-format'] = 'transcript-format', -- misspelling ['transscripturl'] = 'transcript-url', -- misspelling ['transscript-url'] = 'transcript-url', -- misspelling ['trans_title'] = 'trans-title', ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['ubicación'] = 'location', -- Spanish ['urlarchivo'] = 'archive-url', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urlmorto'] = 'url-status', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') ['übersetzer'] = 'translator', -- German (singular and plural) ['v-authors'] = 'vauthors', -- misspelling ['v-editors'] = 'veditors', -- misspelling ['verlag'] = 'publisher', -- German ['verlagea'] = 'publisher', -- German (not a direct replacement, but can be emulated) ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not REGEX though they are similar. The escape character is '%', not '\'. For more information about Lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', -- misspelling ['^apellido[s]?(%d+)$'] = 'last$1', -- Spanish, enumerated ['^a[utho]+r$'] = 'author', -- misspelling ['^a[utho]+r(%d+)$'] = 'author$1', -- misspelling, enumerated ['^author link(%d+)$'] = 'author-link$1', -- Polish, enumerated ['^autor[e]?(%d+)$'] = 'author$1', -- Italian/Spanish/German, enumerated ['^authorfirst(%d+)$'] = 'author-first$1', -- old parameter name, enumerated ['^author(%d+)first$'] = 'author-first$1', -- old parameter name, enumerated ['^authorgiven(%d+)$'] = 'author-given$1', -- old parameter name, enumerated ['^author(%d+)given$'] = 'author-given$1', -- old parameter name, enumerated ['^authorlast(%d+)$'] = 'author-last$1', -- old parameter name, enumerated ['^author(%d+)last$'] = 'author-last$1', -- old parameter name, enumerated ['^authorsurname(%d+)$'] = 'author-surname$1', -- old parameter name, enumerated ['^author(%d+)surname$'] = 'author-surname$1', -- old parameter name, enumerated ['^cognome(%d+)$'] = 'last$1', -- Italian, enumerated ['^editorfirst(%d+)$'] = 'editor-first$1', -- old parameter name, enumerated ['^editor(%d+)first$'] = 'editor-first$1', -- old parameter name, enumerated ['^editorgiven(%d+)$'] = 'editor-given$1', -- old parameter name, enumerated ['^editor(%d+)given$'] = 'editor-given$1', -- old parameter name, enumerated ['^editorlast(%d+)$'] = 'editor-last$1', -- old parameter name, enumerated ['^editor(%d+)last$'] = 'editor-last$1', -- old parameter name, enumerated ['^editormask(%d+)$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editor(%d+)mask$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editorsurname(%d+)$'] = 'editor-surname$1', -- old parameter name, enumerated ['^editor(%d+)surname$'] = 'editor-surname$1', -- old parameter name, enumerated ['^enlaceautore(%d+)$'] = 'author-link$1', -- Spanish, enumerated ['^first (%d+)$'] = 'first$1', -- enumerated ['^last (%d+)$'] = 'last$1', -- enumerated ['^nom[e]?(%d+)$'] = 'last$1', -- Italian/French, enumerated ['^nombre(%d+)$'] = 'first$1', -- Spanish, enumerated ['^primero(%d+)$'] = 'first$1', -- Spanish, enumerated ['^pu[blish]+ers?$'] = 'publisher', -- misspelling ['^wkautore(%d+)$'] = 'author-link$1', -- Italian, enumerated } return {suggestions = suggestions, patterns=patterns}; na28bwto6l5biyx6e0b1x7pvjxzmivt 736804 736803 2020-10-16T00:34:52Z en>Pokechu22 0 orig_date -> orig-date, orig_year -> orig-year (both synonyms) 736804 Scribunto text/plain -- Please insert new suggestions in alphabetical order -- The form is ['incorrect'] = 'correct', suggestions = { ['abruf'] = 'access-date', -- German ['abruf-verborgen'] = 'access-date', -- German ['accessmonth'] = 'access-date', ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', ['address'] = 'location', ['année'] = 'date', -- French ['año'] = 'date', -- Spanish ['añooriginal'] = 'orig-date', -- Spanish ['año-original'] = 'orig-date', -- Spanish ['añoacceso'] = 'access-date', -- Spanish ['anno'] = 'date', -- Italian ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['annooriginale'] = 'orig-date', -- Italian ['apellido'] = 'last', -- Spanish ['apellidos'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archive date'] = 'archive-date', ['archiv-url'] = 'archive-url', -- German ['archive url'] = 'archive-url', -- Spanish ['artikelnr'] = 'id', -- German (as 'id=Article No. ...') ['artist'] = 'others', ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', ['authorfirst'] = 'author-first', -- old parameter name ['authorgiven'] = 'author-given', -- old parameter name ['authorlast'] = 'author-last', -- old parameter name ['author link'] = 'author-link', -- Polish ['authorsurname'] = 'author-surname', -- old parameter name ['autor'] = 'author', -- Spanish, German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', ['band'] = 'volume', -- German ['bandreihe'] = 'volume', -- German ['ch'] = 'language', -- German (as 'language=de-CH') ['chapter_title'] = 'chapter', ['cid'] = 'ref', -- Italian ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['città'] = 'location', -- Italian ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['consulté le'] = 'access-date', -- French ['curatore'] = 'publisher', -- Italian ['czasopismo'] = 'journal', -- Polish ['data'] = 'date', -- Polish, Italian ['dataaccesso'] = 'access-date', -- Italian ['dataarchivio'] = 'archive-date', -- Italian ['data dostępu'] = 'access-date', -- Polish ['datum'] = 'date', -- German ['deadlink'] = 'url-status', ['deadurl'] = 'url-status', -- old parameter name ['dead-url'] = 'url-status', -- old parameter name ['distributor'] = 'publisher', ['displayeditors'] = 'display-editors', -- old parameter name ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') ['doibroken'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-broken'] = 'doi-broken-date', -- former parameter alias ['doi_brokendate'] = 'doi-broken-date', ['doiinactive'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-inactive'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-inactive-date'] = 'doi-broken-date', -- former parameter alias ['doi_inactivedate'] = 'doi-inactive-date', --['ed'] = 'edition', avoid suggestion as in English this could be short for editor or edition ['éditeur'] = 'editor', -- French ['editon'] = 'edition', -- misspelling ['editoin'] = 'edition', -- misspelling -- ['editora'] = 'publisher', -- can be either editor or publisher -- ['editore'] = 'agency', -- can be either publisher or agency -- ['editori'] = 'editor', -- can be either editor or publisher -- ['editorial'] = 'publisher', -- can be either publisher or work ['editorfirst'] = 'editor-first', -- old parameter name ['editorgiven'] = 'editor-given', -- old parameter name ['editorlast'] = 'editor-last', -- old parameter name ['editormask'] = 'editor-mask', -- old parameter name ['editorsurname'] = 'editor-surname', -- old parameter name ['edizione'] = 'edition', -- Italian ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['enlaceroto'] = 'url-status', -- Spanish ['embargo'] = 'pmc-embargo-date', -- former parameter name ['e-print'] = 'eprint', -- misspelling ['family'] = 'surname', -- misguess ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['foramt'] = 'format', -- misspelling ['formato'] = 'format', -- Spanish, Italian, Polish ['forename'] = 'given', -- misguess ['fore-name'] = 'given', -- misguess/misspelling ['frist'] = 'first', -- misspelling ['fundstelle'] = 'at', -- German ['giornale'] = 'journal', -- Italian ['herausgeber'] = 'editor', -- German (singular and plural) ['hrsg'] = 'publisher', -- German ['hrsgreihe'] = 'editor', -- German ['idioma'] = 'language', -- Spanish ['ignoreisbnerror'] = 'isbn', -- former parameter alias (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['imię'] = 'first', -- Polish ['in-set'] = 'inset', -- misspelling ['interviewerlink'] = 'interviewer-link', -- former parameter alias ['interviewermask'] = 'interviewer-mask', -- former parameter alias ['isbndefekt'] = 'ignore-isbn-error', -- German ['isbnformalfalsch'] = 'ignore-isbn-error', -- German ['isbnistformalfalsch'] = 'ignore-isbn-error', -- German ['isnb'] = 'isbn', -- misspelling ['issnformalfalsch'] = 'ignore-issn-error', -- German ['jahr'] = 'date', -- German ['jahrea'] = 'orig-date', -- German (not a direct replacement, but can be emulated) ['kapitel'] = 'chapter', -- German ['langauge'] = 'language', -- misspelling ['langue'] = 'language', -- French ['laysummary'] = 'lay-url', -- old parameter ['lay-summary'] = 'lay-url', -- old parameter ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', -- misspelling ['locatoin'] = 'location', -- misspelling ['lugar'] = 'location', -- Spanish ['mes'] = 'date', -- Spanish (not a direct replacement) ['mese'] = 'date', -- Italian (not a direct replacement) ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', -- misspelling ['net-work'] = 'network', -- misspelling ['newpaper'] = 'newspaper', -- misspelling ['news'] = 'newspaper', ['news-group'] = 'newsgroup', -- misspelling ['news-paper'] = 'newspaper', -- misspelling ['no-cat'] = 'no-tracking', -- old parameter ['nom'] = 'last', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['numero'] = 'number', -- Italian, Spanish ['nummer'] = 'number', -- German ['nummerreihe'] = 'number', -- German ['notracking'] = 'no-tracking', -- old parameter ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'url-status', -- German (as 'url-status=dead') ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opera'] = 'work', -- Italian ['opublikowany'] = 'agency', -- Polish ['origdate'] = 'orig-date', -- misspelling ['orig_date'] = 'orig-date', ['originaljahr'] = 'orig-date', -- German ['originalort'] = 'publication-place', -- German ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['orig_year'] = 'orig-year', ['ort'] = 'publication-place', -- German ['ortea'] = 'publication-place', -- German (not a direct replacement, but can be emulated) ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', -- misspelling ['pagina'] = 'page', -- Italian ['página'] = 'page', -- Spanish ['páginas'] = 'pages', -- Spanish ['pagine'] = 'pages', -- Italian ['passage'] = 'pages', -- French ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['periodico'] = 'magazine', -- Spanish ['périodique'] = 'publisher', -- French ['plublisher'] = 'publisher', -- misspelling ['pmcid'] = 'pmc', ['post-script'] = 'postscript', -- misspelling ['praca'] = 'work', -- Polish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['primero'] = 'first', -- Spanish ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubblicazione'] = 'magazine', -- could be any kind of work -- ['publicación'] = 'journal', -- could be any kind of work ['pulbication-place'] = 'publication-place', -- misspelling ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['richiestasottoscrizione'] = 'url-access', -- Italian (as |url-access=subscription) ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['script-post'] = 'postscript', -- misspelling ['script-trans'] = 'transcript', -- misspelling ['seria'] = 'series', -- Spanish, Polish ['serie'] = 'series', -- Italian ['série'] = 'series', -- French ['service'] = 'agency', ['site'] = 'website', ['sitioweb'] = 'website', -- Spanish ['sito'] = 'website', -- Italian ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['sur-name'] = 'surname', -- misspelling ['suscripción'] = 'url-access', -- Spanish, Polish (as |url-access=subscription) ['tag'] = 'date', -- German ['template doc demo'] = 'no-tracking', -- old parameter ['tile'] = 'title', -- misspelling ['tipo'] = 'type', -- Italian ['tite'] = 'title', -- misspelling ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titolo'] = 'title', -- Italian ['titre'] = 'title', -- French ['títle'] = 'title', ['título'] = 'title', -- Spanish ['transchapter'] = 'trans-chapter', ['trans_chapter'] = 'trans-chapter', ['transscript'] = 'transcript', -- misspelling ['trans-script'] = 'transcript', -- misspelling ['transscript-format'] = 'transcript-format', -- misspelling ['transscripturl'] = 'transcript-url', -- misspelling ['transscript-url'] = 'transcript-url', -- misspelling ['trans_title'] = 'trans-title', ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['ubicación'] = 'location', -- Spanish ['urlarchivo'] = 'archive-url', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urlmorto'] = 'url-status', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') ['übersetzer'] = 'translator', -- German (singular and plural) ['v-authors'] = 'vauthors', -- misspelling ['v-editors'] = 'veditors', -- misspelling ['verlag'] = 'publisher', -- German ['verlagea'] = 'publisher', -- German (not a direct replacement, but can be emulated) ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not REGEX though they are similar. The escape character is '%', not '\'. For more information about Lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', -- misspelling ['^apellido[s]?(%d+)$'] = 'last$1', -- Spanish, enumerated ['^a[utho]+r$'] = 'author', -- misspelling ['^a[utho]+r(%d+)$'] = 'author$1', -- misspelling, enumerated ['^author link(%d+)$'] = 'author-link$1', -- Polish, enumerated ['^autor[e]?(%d+)$'] = 'author$1', -- Italian/Spanish/German, enumerated ['^authorfirst(%d+)$'] = 'author-first$1', -- old parameter name, enumerated ['^author(%d+)first$'] = 'author-first$1', -- old parameter name, enumerated ['^authorgiven(%d+)$'] = 'author-given$1', -- old parameter name, enumerated ['^author(%d+)given$'] = 'author-given$1', -- old parameter name, enumerated ['^authorlast(%d+)$'] = 'author-last$1', -- old parameter name, enumerated ['^author(%d+)last$'] = 'author-last$1', -- old parameter name, enumerated ['^authorsurname(%d+)$'] = 'author-surname$1', -- old parameter name, enumerated ['^author(%d+)surname$'] = 'author-surname$1', -- old parameter name, enumerated ['^cognome(%d+)$'] = 'last$1', -- Italian, enumerated ['^editorfirst(%d+)$'] = 'editor-first$1', -- old parameter name, enumerated ['^editor(%d+)first$'] = 'editor-first$1', -- old parameter name, enumerated ['^editorgiven(%d+)$'] = 'editor-given$1', -- old parameter name, enumerated ['^editor(%d+)given$'] = 'editor-given$1', -- old parameter name, enumerated ['^editorlast(%d+)$'] = 'editor-last$1', -- old parameter name, enumerated ['^editor(%d+)last$'] = 'editor-last$1', -- old parameter name, enumerated ['^editormask(%d+)$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editor(%d+)mask$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editorsurname(%d+)$'] = 'editor-surname$1', -- old parameter name, enumerated ['^editor(%d+)surname$'] = 'editor-surname$1', -- old parameter name, enumerated ['^enlaceautore(%d+)$'] = 'author-link$1', -- Spanish, enumerated ['^first (%d+)$'] = 'first$1', -- enumerated ['^last (%d+)$'] = 'last$1', -- enumerated ['^nom[e]?(%d+)$'] = 'last$1', -- Italian/French, enumerated ['^nombre(%d+)$'] = 'first$1', -- Spanish, enumerated ['^primero(%d+)$'] = 'first$1', -- Spanish, enumerated ['^pu[blish]+ers?$'] = 'publisher', -- misspelling ['^wkautore(%d+)$'] = 'author-link$1', -- Italian, enumerated } return {suggestions = suggestions, patterns=patterns}; cthwdvt3cttz6tvqr1mmxb05hv7grnl 736805 736804 2021-01-09T14:11:07Z en>Trappist the monk 0 sync from sandbox; 736805 Scribunto text/plain -- Please insert new suggestions in alphabetical order -- The form is ['incorrect'] = 'correct', suggestions = { ['ASIN-TLD'] = 'asin-tld', -- old parameter name ['abruf'] = 'access-date', -- German ['abruf-verborgen'] = 'access-date', -- German ['accessmonth'] = 'access-date', ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', ['acessodata'] = 'access-date', -- Brazilian ['ad'] = 'first', -- Turkish ['address'] = 'location', ['anno'] = 'date', -- Italian ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['annooriginale'] = 'orig-date', -- Italian ['année'] = 'date', -- French ['apellido'] = 'last', -- Spanish ['apellidos'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archiv-url'] = 'archive-url', -- German ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish ['artikelnr'] = 'id', -- German (as 'id=Article No. ...') ['artist'] = 'others', ['arşiv-tarihi'] = 'archive-date', -- Turkish ['arşiv-url'] = 'archive-url', -- Turkish ['arşivtarihi'] = 'archive-date', -- Turkish ['arşivurl'] = 'archive-url', -- Turkish ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'author-link', -- Polish ['authorfirst'] = 'author-first', -- old parameter name ['authorgiven'] = 'author-given', -- old parameter name ['authorlast'] = 'author-last', -- old parameter name ['authormask'] = 'author-mask', -- old parameter name ['authorsurname'] = 'author-surname', -- old parameter name ['autor'] = 'author', -- Spanish, German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', ['ay'] = 'month', -- Turkish ['año'] = 'date', -- Spanish ['año-original'] = 'orig-date', -- Spanish ['añoacceso'] = 'access-date', -- Spanish ['añooriginal'] = 'orig-date', -- Spanish ['band'] = 'volume', -- German ['bandreihe'] = 'volume', -- German ['baskı'] = 'edition', -- Turkish ['başlık'] = 'title', -- Turkish ['ch'] = 'language', -- German (as 'language=de-CH') ['chapter_title'] = 'chapter', ['cid'] = 'ref', -- Italian ['cilt'] = 'volume', -- Turkish ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['città'] = 'location', -- Italian ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['consulté le'] = 'access-date', -- French ['curatore'] = 'publisher', -- Italian ['czasopismo'] = 'journal', -- Polish ['data dostępu'] = 'access-date', -- Polish ['data'] = 'date', -- Polish, Italian ['dataaccesso'] = 'access-date', -- Italian ['dataarchivio'] = 'archive-date', -- Italian ['datum'] = 'date', -- German ['dead-url'] = 'url-status', -- old parameter name ['deadlink'] = 'url-status', ['deadurl'] = 'url-status', -- old parameter name ['dergi'] = 'work', -- Turkish ['dil'] = 'language', -- Turkish ['displayauthors'] = 'display-authors', -- old parameter name ['displayeditors'] = 'display-editors', -- old parameter name ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') ['doi-broken'] = 'doi-broken-date', -- former parameter alias ['doi-inactive'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-inactive-date'] = 'doi-broken-date', -- former parameter alias ['doi_brokendate'] = 'doi-broken-date', -- former parameter alias ['doi_inactivedate'] = 'doi-inactive-date', -- former parameter alias ['doibroken'] = 'doi-broken-date', -- invalid name found in mainspace ['doiinactive'] = 'doi-broken-date', -- invalid name found in mainspace ['e-print'] = 'eprint', -- misspelling -- ['ed'] = 'edition', avoid suggestion as in English this could be short for editor or edition -- ['editora'] = 'publisher', -- can be either editor or publisher -- ['editore'] = 'agency', -- can be either publisher or agency -- ['editori'] = 'editor', -- can be either editor or publisher -- ['editorial'] = 'publisher', -- can be either publisher or work ['editoin'] = 'edition', -- misspelling ['editon'] = 'edition', -- misspelling ['editorfirst'] = 'editor-first', -- old parameter name ['editorgiven'] = 'editor-given', -- old parameter name ['editorlast'] = 'editor-last', -- old parameter name ['editorlink'] = 'editor-link', -- old parameter name ['editormask'] = 'editor-mask', -- old parameter name ['editors'] = 'editor', -- old parameter name (can be emulated using multiple singular |editor= params) ['editorsurname'] = 'editor-surname', -- old parameter name ['edizione'] = 'edition', -- Italian ['embargo'] = 'pmc-embargo-date', -- former parameter name ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['enlaceroto'] = 'url-status', -- Spanish ['erişimtarihi'] = 'access-date', -- Turkish ['eser'] = 'work', -- Turkish ['family'] = 'surname', -- misguess ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['foramt'] = 'format', -- misspelling ['fore-name'] = 'given', -- misguess/misspelling ['forename'] = 'given', -- misguess ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', -- misspelling ['fundstelle'] = 'at', -- German ['gazete'] = 'work', -- Turkish ['giornale'] = 'journal', -- Italian ['herausgeber'] = 'editor', -- German (singular and plural) ['hrsg'] = 'publisher', -- German ['hrsgreihe'] = 'editor', -- German ['idioma'] = 'language', -- Spanish ['ignore-isbn-error'] = 'isbn', -- old parameter (can be fully emulated using ((syntax))) ['ignoreisbnerror'] = 'isbn', -- former parameter alias (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['imię'] = 'first', -- Polish ['in-set'] = 'inset', -- misspelling ['interviewerlink'] = 'interviewer-link', -- former parameter alias ['interviewermask'] = 'interviewer-mask', -- former parameter alias ['isbndefekt'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnistformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isnb'] = 'isbn', -- misspelling ['issnformalfalsch'] = 'issn', -- German (can be fully emulated using ((syntax))) ['jahr'] = 'date', -- German ['jahrea'] = 'orig-date', -- German (not a direct replacement, but can be emulated) ['kapitel'] = 'chapter', -- German ['langauge'] = 'language', -- misspelling ['langue'] = 'language', -- French ['last-author-amp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['lastauthoramp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['lay-summary'] = 'lay-url', -- old parameter ['laysummary'] = 'lay-url', -- old parameter ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', -- misspelling ['local'] = 'location', -- Brazilian ['locatoin'] = 'location', -- misspelling ['lugar'] = 'location', -- Spanish ['mes'] = 'date', -- Spanish (not a direct replacement) ['mese'] = 'date', -- Italian (not a direct replacement) ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', -- misspelling ['net-work'] = 'network', -- misspelling ['newpaper'] = 'newspaper', -- misspelling ['news'] = 'newspaper', ['news-group'] = 'newsgroup', -- misspelling ['news-paper'] = 'newspaper', -- misspelling ['no-cat'] = 'no-tracking', -- old parameter ['nocat'] = 'no-tracking', -- old parameter ['nom'] = 'last', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['notracking'] = 'no-tracking', -- old parameter ['numero'] = 'number', -- Italian, Spanish ['nummer'] = 'number', -- German ['nummerreihe'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'url-status', -- German (as 'url-status=dead') ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opera'] = 'work', -- Italian ['opublikowany'] = 'agency', -- Polish ['origdate'] = 'orig-date', -- misspelling ['originaljahr'] = 'orig-date', -- German ['originalort'] = 'publication-place', -- German ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'publication-place', -- German ['ortea'] = 'publication-place', -- German (not a direct replacement, but can be emulated) ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', -- misspelling ['pagina'] = 'page', -- Italian ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['passage'] = 'pages', -- French ['periodico'] = 'magazine', -- Spanish ['plublisher'] = 'publisher', -- misspelling ['pmcid'] = 'pmc', ['post-script'] = 'postscript', -- misspelling ['praca'] = 'work', -- Polish ['primero'] = 'first', -- Spanish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubblicazione'] = 'magazine', -- could be any kind of work -- ['publicación'] = 'journal', -- could be any kind of work -- ['published'] = 'publisher', -- could be date, location, or name of publisher ['pulbication-place'] = 'publication-place', -- misspelling ['página'] = 'page', -- Spanish ['páginas'] = 'pages', -- Spanish ['périodique'] = 'publisher', -- French ['registration'] = 'url-access', -- old parameter name (emulated as |url-access=registration) ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['richiestasottoscrizione'] = 'url-access', -- Italian (as |url-access=subscription) ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['sayfa'] = 'page', -- Turkish ['sayfalar'] = 'pages', -- Turkish ['sayı'] = 'issue', -- Turkish ['script-post'] = 'postscript', -- misspelling ['script-trans'] = 'transcript', -- misspelling ['seria'] = 'series', -- Spanish, Polish ['serie'] = 'series', -- Italian ['service'] = 'agency', ['sitioweb'] = 'website', -- Spanish ['sito'] = 'website', -- Italian ['soyadı'] = 'last', -- Turkish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['subjectlink'] = 'subject-link', -- old parameter name ['subscription'] = 'url-access', -- old parameter name (emulated as |url-access=subscription) ['sur-name'] = 'surname', -- misspelling ['suscripción'] = 'url-access', -- Spanish, Polish (as |url-access=subscription) ['série'] = 'series', -- French ['tag'] = 'date', -- German ['tarih'] = 'date', -- Turkish ['template doc demo'] = 'no-tracking', -- former parameter alias ['tile'] = 'title', -- misspelling ['tipo'] = 'type', -- Italian ['tite'] = 'title', -- misspelling ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titled'] = 'title', -- Brazilian ['titolo'] = 'title', -- Italian ['titre'] = 'title', -- French ['trans-script'] = 'transcript', -- misspelling ['trans_chapter'] = 'trans-chapter', -- former parameter alias ['trans_title'] = 'trans-title', -- former parameter alias ['transchapter'] = 'trans-chapter', ['transscript'] = 'transcript', -- misspelling ['transscript-format'] = 'transcript-format', -- misspelling ['transscript-url'] = 'transcript-url', -- misspelling ['transscripturl'] = 'transcript-url', -- misspelling ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['títle'] = 'title', ['título'] = 'title', -- Spanish ['ubicación'] = 'location', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urlarchivo'] = 'archive-url', -- Spanish ['urlmorto'] = 'url-status', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') ['v-authors'] = 'vauthors', -- misspelling ['v-editors'] = 'veditors', -- misspelling ['verlag'] = 'publisher', -- German ['verlagea'] = 'publisher', -- German (not a direct replacement, but can be emulated) ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['yardımcıyazarlar'] = 'author', -- Turkish ['yayımcı'] = 'publisher', -- Turkish ['yayıncı'] = 'publisher', -- Turkish ['yazar'] = 'author', -- Turkish ['yazarbağı'] = 'author-link', -- Turkish ['yer'] = 'location', -- Turkish ['yıl'] = 'date', -- Turkish ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German ['éditeur'] = 'editor', -- French ['ölüurl'] = 'url-status', -- Turkish ['übersetzer'] = 'translator', -- German (singular and plural) } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not REGEX though they are similar. The escape character is '%', not '\'. For more information about Lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', -- misspelling ['^apellido[s]?(%d+)$'] = 'last$1', -- Spanish, enumerated ['^a[utho]+r$'] = 'author', -- misspelling ['^a[utho]+r(%d+)$'] = 'author$1', -- misspelling, enumerated ['^author link(%d+)$'] = 'author-link$1', -- Polish, enumerated ['^autor[e]?(%d+)$'] = 'author$1', -- Italian/Spanish/German, enumerated ['^authorfirst(%d+)$'] = 'author-first$1', -- old parameter name, enumerated ['^author(%d+)first$'] = 'author-first$1', -- old parameter name, enumerated ['^authorgiven(%d+)$'] = 'author-given$1', -- old parameter name, enumerated ['^author(%d+)given$'] = 'author-given$1', -- old parameter name, enumerated ['^authorlast(%d+)$'] = 'author-last$1', -- old parameter name, enumerated ['^author(%d+)last$'] = 'author-last$1', -- old parameter name, enumerated ['^authormask(%d+)$'] = 'author-mask$1', -- old parameter name, enumerated ['^author(%d+)mask$'] = 'author-mask$1', -- old parameter name, enumerated ['^authorsurname(%d+)$'] = 'author-surname$1', -- old parameter name, enumerated ['^author(%d+)surname$'] = 'author-surname$1', -- old parameter name, enumerated ['^cognome(%d+)$'] = 'last$1', -- Italian, enumerated ['^editorfirst(%d+)$'] = 'editor-first$1', -- old parameter name, enumerated ['^editor(%d+)first$'] = 'editor-first$1', -- old parameter name, enumerated ['^editorgiven(%d+)$'] = 'editor-given$1', -- old parameter name, enumerated ['^editor(%d+)given$'] = 'editor-given$1', -- old parameter name, enumerated ['^editorlast(%d+)$'] = 'editor-last$1', -- old parameter name, enumerated ['^editor(%d+)last$'] = 'editor-last$1', -- old parameter name, enumerated ['^editorlink(%d+)$'] = 'editor-link$1', -- old parameter name, enumerated ['^editor(%d+)link$'] = 'editor-link$1', -- old parameter name, enumerated ['^editormask(%d+)$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editor(%d+)mask$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editorsurname(%d+)$'] = 'editor-surname$1', -- old parameter name, enumerated ['^editor(%d+)surname$'] = 'editor-surname$1', -- old parameter name, enumerated ['^enlaceautore(%d+)$'] = 'author-link$1', -- Spanish, enumerated ['^first (%d+)$'] = 'first$1', -- enumerated ['^last (%d+)$'] = 'last$1', -- enumerated ['^nom[e]?(%d+)$'] = 'last$1', -- Italian/French, enumerated ['^nombre(%d+)$'] = 'first$1', -- Spanish, enumerated ['^primero(%d+)$'] = 'first$1', -- Spanish, enumerated ['^pu[blish]+ers?$'] = 'publisher', -- misspelling ['^subjectlink(%d+)$'] = 'subject-link$1', -- old parameter name, enumerated ['^subject(%d+)link$'] = 'subject-link$1', -- old parameter name, enumerated ['^wkautore(%d+)$'] = 'author-link$1', -- Italian, enumerated } return {suggestions = suggestions, patterns=patterns}; hbuxocoj0hw3gi5d5bj97wwtwcnu7f2 736806 736805 2021-04-10T13:14:43Z en>Trappist the monk 0 sync from sandbox; 736806 Scribunto text/plain -- Please insert new suggestions in alphabetical order -- The form is ['incorrect'] = 'correct', suggestions = { ['ASIN-TLD'] = 'asin-tld', -- old parameter name ['abruf'] = 'access-date', -- German ['abruf-verborgen'] = 'access-date', -- German ['accessmonth'] = 'access-date', ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', ['acessodata'] = 'access-date', -- Brazilian ['ad'] = 'first', -- Turkish ['address'] = 'location', ['anno'] = 'date', -- Italian ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['annooriginale'] = 'orig-date', -- Italian ['année'] = 'date', -- French ['apellido'] = 'last', -- Spanish ['apellidos'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archiv-url'] = 'archive-url', -- German ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish ['artikelnr'] = 'id', -- German (as 'id=Article No. ...') ['artist'] = 'others', ['arşiv-tarihi'] = 'archive-date', -- Turkish ['arşiv-url'] = 'archive-url', -- Turkish ['arşivtarihi'] = 'archive-date', -- Turkish ['arşivurl'] = 'archive-url', -- Turkish ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'author-link', -- Polish ['authorfirst'] = 'author-first', -- old parameter name ['authorgiven'] = 'author-given', -- old parameter name ['authorlast'] = 'author-last', -- old parameter name ['authormask'] = 'author-mask', -- old parameter name ['authorsurname'] = 'author-surname', -- old parameter name ['autor'] = 'author', -- Spanish, German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', ['ay'] = 'month', -- Turkish ['año'] = 'date', -- Spanish ['año-original'] = 'orig-date', -- Spanish ['añoacceso'] = 'access-date', -- Spanish ['añooriginal'] = 'orig-date', -- Spanish ['band'] = 'volume', -- German ['bandreihe'] = 'volume', -- German ['baskı'] = 'edition', -- Turkish ['başlık'] = 'title', -- Turkish -- ['booktitle'] = 'book-title', -- old parameter name ['ch'] = 'language', -- German (as 'language=de-CH') ['chapter_title'] = 'chapter', -- ['chapterurl'] = 'chapter-url', -- old parameter name ['cid'] = 'ref', -- Italian ['cilt'] = 'volume', -- Turkish ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['città'] = 'location', -- Italian ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['conferenceurl'] = 'conference-url', -- old parameter name ['consulté le'] = 'access-date', -- French ['contributionurl'] = 'contribution-url', -- old parameter name ['curatore'] = 'publisher', -- Italian ['czasopismo'] = 'journal', -- Polish ['data dostępu'] = 'access-date', -- Polish ['data'] = 'date', -- Polish, Italian ['dataaccesso'] = 'access-date', -- Italian ['dataarchivio'] = 'archive-date', -- Italian ['datum'] = 'date', -- German ['dead-url'] = 'url-status', -- old parameter name ['deadlink'] = 'url-status', ['deadurl'] = 'url-status', -- old parameter name ['dergi'] = 'work', -- Turkish ['dil'] = 'language', -- Turkish ['displayauthors'] = 'display-authors', -- old parameter name ['displayeditors'] = 'display-editors', -- old parameter name ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') ['doi-broken'] = 'doi-broken-date', -- former parameter alias ['doi-inactive'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-inactive-date'] = 'doi-broken-date', -- former parameter alias ['doi_brokendate'] = 'doi-broken-date', -- former parameter alias ['doi_inactivedate'] = 'doi-inactive-date', -- former parameter alias ['doibroken'] = 'doi-broken-date', -- invalid name found in mainspace ['doiinactive'] = 'doi-broken-date', -- invalid name found in mainspace ['e-print'] = 'eprint', -- misspelling -- ['ed'] = 'edition', avoid suggestion as in English this could be short for editor or edition -- ['editora'] = 'publisher', -- can be either editor or publisher -- ['editore'] = 'agency', -- can be either publisher or agency -- ['editori'] = 'editor', -- can be either editor or publisher -- ['editorial'] = 'publisher', -- can be either publisher or work ['editoin'] = 'edition', -- misspelling ['editon'] = 'edition', -- misspelling ['editorfirst'] = 'editor-first', -- old parameter name ['editorgiven'] = 'editor-given', -- old parameter name ['editorlast'] = 'editor-last', -- old parameter name ['editorlink'] = 'editor-link', -- old parameter name ['editormask'] = 'editor-mask', -- old parameter name ['editors'] = 'editor', -- old parameter name (can be emulated using multiple singular |editor= params) ['editorsurname'] = 'editor-surname', -- old parameter name ['edizione'] = 'edition', -- Italian ['embargo'] = 'pmc-embargo-date', -- former parameter name ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['enlaceroto'] = 'url-status', -- Spanish -- ['episodelink'] = 'episode-link', -- old parameter name ['erişimtarihi'] = 'access-date', -- Turkish ['eser'] = 'work', -- Turkish ['family'] = 'surname', -- misguess ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['foramt'] = 'format', -- misspelling ['fore-name'] = 'given', -- misguess/misspelling ['forename'] = 'given', -- misguess ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', -- misspelling ['fundstelle'] = 'at', -- German ['gazete'] = 'work', -- Turkish ['giornale'] = 'journal', -- Italian ['herausgeber'] = 'editor', -- German (singular and plural) ['hrsg'] = 'publisher', -- German ['hrsgreihe'] = 'editor', -- German ['idioma'] = 'language', -- Spanish ['ignore-isbn-error'] = 'isbn', -- old parameter (can be fully emulated using ((syntax))) ['ignoreisbnerror'] = 'isbn', -- former parameter alias (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['imię'] = 'first', -- Polish ['in-set'] = 'inset', -- misspelling ['interviewerlink'] = 'interviewer-link', -- former parameter alias ['interviewermask'] = 'interviewer-mask', -- former parameter alias ['isbndefekt'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnistformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isnb'] = 'isbn', -- misspelling ['issnformalfalsch'] = 'issn', -- German (can be fully emulated using ((syntax))) ['jahr'] = 'date', -- German ['jahrea'] = 'orig-date', -- German (not a direct replacement, but can be emulated) ['kapitel'] = 'chapter', -- German ['langauge'] = 'language', -- misspelling ['langue'] = 'language', -- French ['last-author-amp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['lastauthoramp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['laydate'] = 'lay-date', -- old parameter name ['laysource'] = 'lay-source', -- old parameter name ['lay-summary'] = 'lay-url', -- old parameter ['laysummary'] = 'lay-url', -- old parameter ['layurl'] = 'lay-url', -- old parameter name ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', -- misspelling ['local'] = 'location', -- Brazilian ['locatoin'] = 'location', -- misspelling ['lugar'] = 'location', -- Spanish -- ['mailinglist'] = 'mailing-list', -- old parameter name -- ['mapurl'] = 'map-url', -- old parameter name ['mes'] = 'date', -- Spanish (not a direct replacement) ['mese'] = 'date', -- Italian (not a direct replacement) ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['name-list-format'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', -- misspelling ['net-work'] = 'network', -- misspelling ['newpaper'] = 'newspaper', -- misspelling ['news'] = 'newspaper', ['news-group'] = 'newsgroup', -- misspelling ['news-paper'] = 'newspaper', -- misspelling ['no-cat'] = 'no-tracking', -- old parameter ['nocat'] = 'no-tracking', -- old parameter ['nom'] = 'last', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian -- ['nopp'] = 'no-pp', -- old parameter name ['notracking'] = 'no-tracking', -- old parameter ['numero'] = 'number', -- Italian, Spanish ['nummer'] = 'number', -- German ['nummerreihe'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'url-status', -- German (as 'url-status=dead') ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opera'] = 'work', -- Italian ['opublikowany'] = 'agency', -- Polish ['origdate'] = 'orig-date', -- misspelling ['originaljahr'] = 'orig-date', -- German ['originalort'] = 'publication-place', -- German ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'publication-place', -- German ['ortea'] = 'publication-place', -- German (not a direct replacement, but can be emulated) ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', -- misspelling ['pagina'] = 'page', -- Italian ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['passage'] = 'pages', -- French ['periodico'] = 'magazine', -- Spanish ['plublisher'] = 'publisher', -- misspelling ['pmcid'] = 'pmc', ['post-script'] = 'postscript', -- misspelling ['praca'] = 'work', -- Polish ['primero'] = 'first', -- Spanish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubblicazione'] = 'magazine', -- could be any kind of work -- ['publicación'] = 'journal', -- could be any kind of work -- ['publicationdate'] = 'publication-date', -- old parameter name -- ['published'] = 'publisher', -- could be date, location, or name of publisher -- ['publicationplace'] = 'publication-place', -- old parameter name ['pulbication-place'] = 'publication-place', -- misspelling ['página'] = 'page', -- Spanish ['páginas'] = 'pages', -- Spanish ['périodique'] = 'publisher', -- French ['registration'] = 'url-access', -- old parameter name (emulated as |url-access=registration) ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['richiestasottoscrizione'] = 'url-access', -- Italian (as |url-access=subscription) ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['sayfa'] = 'page', -- Turkish ['sayfalar'] = 'pages', -- Turkish ['sayı'] = 'issue', -- Turkish ['script-post'] = 'postscript', -- misspelling ['script-trans'] = 'transcript', -- misspelling ['sectionurl'] = 'section-url', -- old parameter name ['seria'] = 'series', -- Spanish, Polish ['serie'] = 'series', -- Italian ['série'] = 'series', -- French -- ['serieslink'] = 'series-link', -- old parameter name ['seriesno'] = 'series-number', -- old parameter name -- ['series-no'] = 'series-number', -- old parameter name ['service'] = 'agency', ['sitioweb'] = 'website', -- Spanish ['sito'] = 'website', -- Italian ['soyadı'] = 'last', -- Turkish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['subjectlink'] = 'subject-link', -- old parameter name ['subscription'] = 'url-access', -- old parameter name (emulated as |url-access=subscription) ['sur-name'] = 'surname', -- misspelling ['suscripción'] = 'url-access', -- Spanish, Polish (as |url-access=subscription) ['tag'] = 'date', -- German ['tarih'] = 'date', -- Turkish ['template doc demo'] = 'no-tracking', -- former parameter alias ['tile'] = 'title', -- misspelling ['timecaption'] = 'time-caption', -- old parameter name ['titlelink'] = 'title-link', -- old parameter name ['tipo'] = 'type', -- Italian ['tite'] = 'title', -- misspelling ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titled'] = 'title', -- Brazilian ['titolo'] = 'title', -- Italian ['titre'] = 'title', -- French ['trans-script'] = 'transcript', -- misspelling ['trans_chapter'] = 'trans-chapter', -- former parameter alias ['trans_title'] = 'trans-title', -- former parameter alias ['transchapter'] = 'trans-chapter', -- ['transcripturl'] = 'transcript-url', -- old parameter name ['transscript'] = 'transcript', -- misspelling ['transscript-format'] = 'transcript-format', -- misspelling ['transscript-url'] = 'transcript-url', -- misspelling ['transscripturl'] = 'transcript-url', -- misspelling ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['títle'] = 'title', ['título'] = 'title', -- Spanish ['ubicación'] = 'location', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urlarchivo'] = 'archive-url', -- Spanish ['urlmorto'] = 'url-status', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') ['v-authors'] = 'vauthors', -- misspelling ['v-editors'] = 'veditors', -- misspelling ['verlag'] = 'publisher', -- German ['verlagea'] = 'publisher', -- German (not a direct replacement, but can be emulated) ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['yardımcıyazarlar'] = 'author', -- Turkish ['yayımcı'] = 'publisher', -- Turkish ['yayıncı'] = 'publisher', -- Turkish ['yazar'] = 'author', -- Turkish ['yazarbağı'] = 'author-link', -- Turkish ['yer'] = 'location', -- Turkish ['yıl'] = 'date', -- Turkish ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German ['éditeur'] = 'editor', -- French ['ölüurl'] = 'url-status', -- Turkish ['übersetzer'] = 'translator', -- German (singular and plural) } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not REGEX though they are similar. The escape character is '%', not '\'. For more information about Lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', -- misspelling ['^apellido[s]?(%d+)$'] = 'last$1', -- Spanish, enumerated ['^a[utho]+r$'] = 'author', -- misspelling ['^a[utho]+r(%d+)$'] = 'author$1', -- misspelling, enumerated ['^author link(%d+)$'] = 'author-link$1', -- Polish, enumerated ['^autor[e]?(%d+)$'] = 'author$1', -- Italian/Spanish/German, enumerated ['^authorfirst(%d+)$'] = 'author-first$1', -- old parameter name, enumerated ['^author(%d+)first$'] = 'author-first$1', -- old parameter name, enumerated ['^authorgiven(%d+)$'] = 'author-given$1', -- old parameter name, enumerated ['^author(%d+)given$'] = 'author-given$1', -- old parameter name, enumerated ['^authorlast(%d+)$'] = 'author-last$1', -- old parameter name, enumerated ['^author(%d+)last$'] = 'author-last$1', -- old parameter name, enumerated ['^authormask(%d+)$'] = 'author-mask$1', -- old parameter name, enumerated ['^author(%d+)mask$'] = 'author-mask$1', -- old parameter name, enumerated ['^authorsurname(%d+)$'] = 'author-surname$1', -- old parameter name, enumerated ['^author(%d+)surname$'] = 'author-surname$1', -- old parameter name, enumerated ['^cognome(%d+)$'] = 'last$1', -- Italian, enumerated ['^editorfirst(%d+)$'] = 'editor-first$1', -- old parameter name, enumerated ['^editor(%d+)first$'] = 'editor-first$1', -- old parameter name, enumerated ['^editorgiven(%d+)$'] = 'editor-given$1', -- old parameter name, enumerated ['^editor(%d+)given$'] = 'editor-given$1', -- old parameter name, enumerated ['^editorlast(%d+)$'] = 'editor-last$1', -- old parameter name, enumerated ['^editor(%d+)last$'] = 'editor-last$1', -- old parameter name, enumerated ['^editorlink(%d+)$'] = 'editor-link$1', -- old parameter name, enumerated ['^editor(%d+)link$'] = 'editor-link$1', -- old parameter name, enumerated ['^editormask(%d+)$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editor(%d+)mask$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editorsurname(%d+)$'] = 'editor-surname$1', -- old parameter name, enumerated ['^editor(%d+)surname$'] = 'editor-surname$1', -- old parameter name, enumerated ['^enlaceautore(%d+)$'] = 'author-link$1', -- Spanish, enumerated ['^first (%d+)$'] = 'first$1', -- enumerated ['^last (%d+)$'] = 'last$1', -- enumerated ['^nom[e]?(%d+)$'] = 'last$1', -- Italian/French, enumerated ['^nombre(%d+)$'] = 'first$1', -- Spanish, enumerated ['^primero(%d+)$'] = 'first$1', -- Spanish, enumerated ['^pu[blish]+ers?$'] = 'publisher', -- misspelling ['^subjectlink(%d+)$'] = 'subject-link$1', -- old parameter name, enumerated ['^subject(%d+)link$'] = 'subject-link$1', -- old parameter name, enumerated ['^wkautore(%d+)$'] = 'author-link$1', -- Italian, enumerated } return {suggestions = suggestions, patterns=patterns}; m6g2jluwhkitcxe5r3nvqqx3co3skpm 736807 736806 2021-08-17T00:18:49Z en>MusikAnimal 0 Changed protection settings for "[[Module:Citation/CS1/Suggestions]]": [[WP:High-risk templates|High-risk Lua module]]: 30,000+ transclusions ([Edit=Require template editor access] (indefinite) [Move=Require template editor access] (indefinite)) 736806 Scribunto text/plain -- Please insert new suggestions in alphabetical order -- The form is ['incorrect'] = 'correct', suggestions = { ['ASIN-TLD'] = 'asin-tld', -- old parameter name ['abruf'] = 'access-date', -- German ['abruf-verborgen'] = 'access-date', -- German ['accessmonth'] = 'access-date', ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', ['acessodata'] = 'access-date', -- Brazilian ['ad'] = 'first', -- Turkish ['address'] = 'location', ['anno'] = 'date', -- Italian ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['annooriginale'] = 'orig-date', -- Italian ['année'] = 'date', -- French ['apellido'] = 'last', -- Spanish ['apellidos'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archiv-url'] = 'archive-url', -- German ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish ['artikelnr'] = 'id', -- German (as 'id=Article No. ...') ['artist'] = 'others', ['arşiv-tarihi'] = 'archive-date', -- Turkish ['arşiv-url'] = 'archive-url', -- Turkish ['arşivtarihi'] = 'archive-date', -- Turkish ['arşivurl'] = 'archive-url', -- Turkish ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'author-link', -- Polish ['authorfirst'] = 'author-first', -- old parameter name ['authorgiven'] = 'author-given', -- old parameter name ['authorlast'] = 'author-last', -- old parameter name ['authormask'] = 'author-mask', -- old parameter name ['authorsurname'] = 'author-surname', -- old parameter name ['autor'] = 'author', -- Spanish, German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', ['ay'] = 'month', -- Turkish ['año'] = 'date', -- Spanish ['año-original'] = 'orig-date', -- Spanish ['añoacceso'] = 'access-date', -- Spanish ['añooriginal'] = 'orig-date', -- Spanish ['band'] = 'volume', -- German ['bandreihe'] = 'volume', -- German ['baskı'] = 'edition', -- Turkish ['başlık'] = 'title', -- Turkish -- ['booktitle'] = 'book-title', -- old parameter name ['ch'] = 'language', -- German (as 'language=de-CH') ['chapter_title'] = 'chapter', -- ['chapterurl'] = 'chapter-url', -- old parameter name ['cid'] = 'ref', -- Italian ['cilt'] = 'volume', -- Turkish ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['città'] = 'location', -- Italian ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['conferenceurl'] = 'conference-url', -- old parameter name ['consulté le'] = 'access-date', -- French ['contributionurl'] = 'contribution-url', -- old parameter name ['curatore'] = 'publisher', -- Italian ['czasopismo'] = 'journal', -- Polish ['data dostępu'] = 'access-date', -- Polish ['data'] = 'date', -- Polish, Italian ['dataaccesso'] = 'access-date', -- Italian ['dataarchivio'] = 'archive-date', -- Italian ['datum'] = 'date', -- German ['dead-url'] = 'url-status', -- old parameter name ['deadlink'] = 'url-status', ['deadurl'] = 'url-status', -- old parameter name ['dergi'] = 'work', -- Turkish ['dil'] = 'language', -- Turkish ['displayauthors'] = 'display-authors', -- old parameter name ['displayeditors'] = 'display-editors', -- old parameter name ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') ['doi-broken'] = 'doi-broken-date', -- former parameter alias ['doi-inactive'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-inactive-date'] = 'doi-broken-date', -- former parameter alias ['doi_brokendate'] = 'doi-broken-date', -- former parameter alias ['doi_inactivedate'] = 'doi-inactive-date', -- former parameter alias ['doibroken'] = 'doi-broken-date', -- invalid name found in mainspace ['doiinactive'] = 'doi-broken-date', -- invalid name found in mainspace ['e-print'] = 'eprint', -- misspelling -- ['ed'] = 'edition', avoid suggestion as in English this could be short for editor or edition -- ['editora'] = 'publisher', -- can be either editor or publisher -- ['editore'] = 'agency', -- can be either publisher or agency -- ['editori'] = 'editor', -- can be either editor or publisher -- ['editorial'] = 'publisher', -- can be either publisher or work ['editoin'] = 'edition', -- misspelling ['editon'] = 'edition', -- misspelling ['editorfirst'] = 'editor-first', -- old parameter name ['editorgiven'] = 'editor-given', -- old parameter name ['editorlast'] = 'editor-last', -- old parameter name ['editorlink'] = 'editor-link', -- old parameter name ['editormask'] = 'editor-mask', -- old parameter name ['editors'] = 'editor', -- old parameter name (can be emulated using multiple singular |editor= params) ['editorsurname'] = 'editor-surname', -- old parameter name ['edizione'] = 'edition', -- Italian ['embargo'] = 'pmc-embargo-date', -- former parameter name ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['enlaceroto'] = 'url-status', -- Spanish -- ['episodelink'] = 'episode-link', -- old parameter name ['erişimtarihi'] = 'access-date', -- Turkish ['eser'] = 'work', -- Turkish ['family'] = 'surname', -- misguess ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['foramt'] = 'format', -- misspelling ['fore-name'] = 'given', -- misguess/misspelling ['forename'] = 'given', -- misguess ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', -- misspelling ['fundstelle'] = 'at', -- German ['gazete'] = 'work', -- Turkish ['giornale'] = 'journal', -- Italian ['herausgeber'] = 'editor', -- German (singular and plural) ['hrsg'] = 'publisher', -- German ['hrsgreihe'] = 'editor', -- German ['idioma'] = 'language', -- Spanish ['ignore-isbn-error'] = 'isbn', -- old parameter (can be fully emulated using ((syntax))) ['ignoreisbnerror'] = 'isbn', -- former parameter alias (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['imię'] = 'first', -- Polish ['in-set'] = 'inset', -- misspelling ['interviewerlink'] = 'interviewer-link', -- former parameter alias ['interviewermask'] = 'interviewer-mask', -- former parameter alias ['isbndefekt'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnistformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isnb'] = 'isbn', -- misspelling ['issnformalfalsch'] = 'issn', -- German (can be fully emulated using ((syntax))) ['jahr'] = 'date', -- German ['jahrea'] = 'orig-date', -- German (not a direct replacement, but can be emulated) ['kapitel'] = 'chapter', -- German ['langauge'] = 'language', -- misspelling ['langue'] = 'language', -- French ['last-author-amp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['lastauthoramp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['laydate'] = 'lay-date', -- old parameter name ['laysource'] = 'lay-source', -- old parameter name ['lay-summary'] = 'lay-url', -- old parameter ['laysummary'] = 'lay-url', -- old parameter ['layurl'] = 'lay-url', -- old parameter name ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', -- misspelling ['local'] = 'location', -- Brazilian ['locatoin'] = 'location', -- misspelling ['lugar'] = 'location', -- Spanish -- ['mailinglist'] = 'mailing-list', -- old parameter name -- ['mapurl'] = 'map-url', -- old parameter name ['mes'] = 'date', -- Spanish (not a direct replacement) ['mese'] = 'date', -- Italian (not a direct replacement) ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['name-list-format'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', -- misspelling ['net-work'] = 'network', -- misspelling ['newpaper'] = 'newspaper', -- misspelling ['news'] = 'newspaper', ['news-group'] = 'newsgroup', -- misspelling ['news-paper'] = 'newspaper', -- misspelling ['no-cat'] = 'no-tracking', -- old parameter ['nocat'] = 'no-tracking', -- old parameter ['nom'] = 'last', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian -- ['nopp'] = 'no-pp', -- old parameter name ['notracking'] = 'no-tracking', -- old parameter ['numero'] = 'number', -- Italian, Spanish ['nummer'] = 'number', -- German ['nummerreihe'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'url-status', -- German (as 'url-status=dead') ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opera'] = 'work', -- Italian ['opublikowany'] = 'agency', -- Polish ['origdate'] = 'orig-date', -- misspelling ['originaljahr'] = 'orig-date', -- German ['originalort'] = 'publication-place', -- German ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'publication-place', -- German ['ortea'] = 'publication-place', -- German (not a direct replacement, but can be emulated) ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', -- misspelling ['pagina'] = 'page', -- Italian ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['passage'] = 'pages', -- French ['periodico'] = 'magazine', -- Spanish ['plublisher'] = 'publisher', -- misspelling ['pmcid'] = 'pmc', ['post-script'] = 'postscript', -- misspelling ['praca'] = 'work', -- Polish ['primero'] = 'first', -- Spanish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubblicazione'] = 'magazine', -- could be any kind of work -- ['publicación'] = 'journal', -- could be any kind of work -- ['publicationdate'] = 'publication-date', -- old parameter name -- ['published'] = 'publisher', -- could be date, location, or name of publisher -- ['publicationplace'] = 'publication-place', -- old parameter name ['pulbication-place'] = 'publication-place', -- misspelling ['página'] = 'page', -- Spanish ['páginas'] = 'pages', -- Spanish ['périodique'] = 'publisher', -- French ['registration'] = 'url-access', -- old parameter name (emulated as |url-access=registration) ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['richiestasottoscrizione'] = 'url-access', -- Italian (as |url-access=subscription) ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['sayfa'] = 'page', -- Turkish ['sayfalar'] = 'pages', -- Turkish ['sayı'] = 'issue', -- Turkish ['script-post'] = 'postscript', -- misspelling ['script-trans'] = 'transcript', -- misspelling ['sectionurl'] = 'section-url', -- old parameter name ['seria'] = 'series', -- Spanish, Polish ['serie'] = 'series', -- Italian ['série'] = 'series', -- French -- ['serieslink'] = 'series-link', -- old parameter name ['seriesno'] = 'series-number', -- old parameter name -- ['series-no'] = 'series-number', -- old parameter name ['service'] = 'agency', ['sitioweb'] = 'website', -- Spanish ['sito'] = 'website', -- Italian ['soyadı'] = 'last', -- Turkish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['subjectlink'] = 'subject-link', -- old parameter name ['subscription'] = 'url-access', -- old parameter name (emulated as |url-access=subscription) ['sur-name'] = 'surname', -- misspelling ['suscripción'] = 'url-access', -- Spanish, Polish (as |url-access=subscription) ['tag'] = 'date', -- German ['tarih'] = 'date', -- Turkish ['template doc demo'] = 'no-tracking', -- former parameter alias ['tile'] = 'title', -- misspelling ['timecaption'] = 'time-caption', -- old parameter name ['titlelink'] = 'title-link', -- old parameter name ['tipo'] = 'type', -- Italian ['tite'] = 'title', -- misspelling ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titled'] = 'title', -- Brazilian ['titolo'] = 'title', -- Italian ['titre'] = 'title', -- French ['trans-script'] = 'transcript', -- misspelling ['trans_chapter'] = 'trans-chapter', -- former parameter alias ['trans_title'] = 'trans-title', -- former parameter alias ['transchapter'] = 'trans-chapter', -- ['transcripturl'] = 'transcript-url', -- old parameter name ['transscript'] = 'transcript', -- misspelling ['transscript-format'] = 'transcript-format', -- misspelling ['transscript-url'] = 'transcript-url', -- misspelling ['transscripturl'] = 'transcript-url', -- misspelling ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['títle'] = 'title', ['título'] = 'title', -- Spanish ['ubicación'] = 'location', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urlarchivo'] = 'archive-url', -- Spanish ['urlmorto'] = 'url-status', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') ['v-authors'] = 'vauthors', -- misspelling ['v-editors'] = 'veditors', -- misspelling ['verlag'] = 'publisher', -- German ['verlagea'] = 'publisher', -- German (not a direct replacement, but can be emulated) ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['yardımcıyazarlar'] = 'author', -- Turkish ['yayımcı'] = 'publisher', -- Turkish ['yayıncı'] = 'publisher', -- Turkish ['yazar'] = 'author', -- Turkish ['yazarbağı'] = 'author-link', -- Turkish ['yer'] = 'location', -- Turkish ['yıl'] = 'date', -- Turkish ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German ['éditeur'] = 'editor', -- French ['ölüurl'] = 'url-status', -- Turkish ['übersetzer'] = 'translator', -- German (singular and plural) } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not REGEX though they are similar. The escape character is '%', not '\'. For more information about Lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', -- misspelling ['^apellido[s]?(%d+)$'] = 'last$1', -- Spanish, enumerated ['^a[utho]+r$'] = 'author', -- misspelling ['^a[utho]+r(%d+)$'] = 'author$1', -- misspelling, enumerated ['^author link(%d+)$'] = 'author-link$1', -- Polish, enumerated ['^autor[e]?(%d+)$'] = 'author$1', -- Italian/Spanish/German, enumerated ['^authorfirst(%d+)$'] = 'author-first$1', -- old parameter name, enumerated ['^author(%d+)first$'] = 'author-first$1', -- old parameter name, enumerated ['^authorgiven(%d+)$'] = 'author-given$1', -- old parameter name, enumerated ['^author(%d+)given$'] = 'author-given$1', -- old parameter name, enumerated ['^authorlast(%d+)$'] = 'author-last$1', -- old parameter name, enumerated ['^author(%d+)last$'] = 'author-last$1', -- old parameter name, enumerated ['^authormask(%d+)$'] = 'author-mask$1', -- old parameter name, enumerated ['^author(%d+)mask$'] = 'author-mask$1', -- old parameter name, enumerated ['^authorsurname(%d+)$'] = 'author-surname$1', -- old parameter name, enumerated ['^author(%d+)surname$'] = 'author-surname$1', -- old parameter name, enumerated ['^cognome(%d+)$'] = 'last$1', -- Italian, enumerated ['^editorfirst(%d+)$'] = 'editor-first$1', -- old parameter name, enumerated ['^editor(%d+)first$'] = 'editor-first$1', -- old parameter name, enumerated ['^editorgiven(%d+)$'] = 'editor-given$1', -- old parameter name, enumerated ['^editor(%d+)given$'] = 'editor-given$1', -- old parameter name, enumerated ['^editorlast(%d+)$'] = 'editor-last$1', -- old parameter name, enumerated ['^editor(%d+)last$'] = 'editor-last$1', -- old parameter name, enumerated ['^editorlink(%d+)$'] = 'editor-link$1', -- old parameter name, enumerated ['^editor(%d+)link$'] = 'editor-link$1', -- old parameter name, enumerated ['^editormask(%d+)$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editor(%d+)mask$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editorsurname(%d+)$'] = 'editor-surname$1', -- old parameter name, enumerated ['^editor(%d+)surname$'] = 'editor-surname$1', -- old parameter name, enumerated ['^enlaceautore(%d+)$'] = 'author-link$1', -- Spanish, enumerated ['^first (%d+)$'] = 'first$1', -- enumerated ['^last (%d+)$'] = 'last$1', -- enumerated ['^nom[e]?(%d+)$'] = 'last$1', -- Italian/French, enumerated ['^nombre(%d+)$'] = 'first$1', -- Spanish, enumerated ['^primero(%d+)$'] = 'first$1', -- Spanish, enumerated ['^pu[blish]+ers?$'] = 'publisher', -- misspelling ['^subjectlink(%d+)$'] = 'subject-link$1', -- old parameter name, enumerated ['^subject(%d+)link$'] = 'subject-link$1', -- old parameter name, enumerated ['^wkautore(%d+)$'] = 'author-link$1', -- Italian, enumerated } return {suggestions = suggestions, patterns=patterns}; m6g2jluwhkitcxe5r3nvqqx3co3skpm 736808 736807 2022-01-06T13:23:31Z en>Jonesey95 0 add archive-link 736808 Scribunto text/plain -- Please insert new suggestions in alphabetical order -- The form is ['incorrect'] = 'correct', suggestions = { ['ASIN-TLD'] = 'asin-tld', -- old parameter name ['abruf'] = 'access-date', -- German ['abruf-verborgen'] = 'access-date', -- German ['accessmonth'] = 'access-date', ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', ['acessodata'] = 'access-date', -- Brazilian ['ad'] = 'first', -- Turkish ['address'] = 'location', ['anno'] = 'date', -- Italian ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['annooriginale'] = 'orig-date', -- Italian ['année'] = 'date', -- French ['apellido'] = 'last', -- Spanish ['apellidos'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archiv-url'] = 'archive-url', -- German ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish ['archive-link'] = 'archive-url', ['artikelnr'] = 'id', -- German (as 'id=Article No. ...') ['artist'] = 'others', ['arşiv-tarihi'] = 'archive-date', -- Turkish ['arşiv-url'] = 'archive-url', -- Turkish ['arşivtarihi'] = 'archive-date', -- Turkish ['arşivurl'] = 'archive-url', -- Turkish ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'author-link', -- Polish ['authorfirst'] = 'author-first', -- old parameter name ['authorgiven'] = 'author-given', -- old parameter name ['authorlast'] = 'author-last', -- old parameter name ['authormask'] = 'author-mask', -- old parameter name ['authorsurname'] = 'author-surname', -- old parameter name ['autor'] = 'author', -- Spanish, German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', ['ay'] = 'month', -- Turkish ['año'] = 'date', -- Spanish ['año-original'] = 'orig-date', -- Spanish ['añoacceso'] = 'access-date', -- Spanish ['añooriginal'] = 'orig-date', -- Spanish ['band'] = 'volume', -- German ['bandreihe'] = 'volume', -- German ['baskı'] = 'edition', -- Turkish ['başlık'] = 'title', -- Turkish -- ['booktitle'] = 'book-title', -- old parameter name ['ch'] = 'language', -- German (as 'language=de-CH') ['chapter_title'] = 'chapter', -- ['chapterurl'] = 'chapter-url', -- old parameter name ['cid'] = 'ref', -- Italian ['cilt'] = 'volume', -- Turkish ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['città'] = 'location', -- Italian ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['conferenceurl'] = 'conference-url', -- old parameter name ['consulté le'] = 'access-date', -- French ['contributionurl'] = 'contribution-url', -- old parameter name ['curatore'] = 'publisher', -- Italian ['czasopismo'] = 'journal', -- Polish ['data dostępu'] = 'access-date', -- Polish ['data'] = 'date', -- Polish, Italian ['dataaccesso'] = 'access-date', -- Italian ['dataarchivio'] = 'archive-date', -- Italian ['datum'] = 'date', -- German ['dead-url'] = 'url-status', -- old parameter name ['deadlink'] = 'url-status', ['deadurl'] = 'url-status', -- old parameter name ['dergi'] = 'work', -- Turkish ['dil'] = 'language', -- Turkish ['displayauthors'] = 'display-authors', -- old parameter name ['displayeditors'] = 'display-editors', -- old parameter name ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') ['doi-broken'] = 'doi-broken-date', -- former parameter alias ['doi-inactive'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-inactive-date'] = 'doi-broken-date', -- former parameter alias ['doi_brokendate'] = 'doi-broken-date', -- former parameter alias ['doi_inactivedate'] = 'doi-inactive-date', -- former parameter alias ['doibroken'] = 'doi-broken-date', -- invalid name found in mainspace ['doiinactive'] = 'doi-broken-date', -- invalid name found in mainspace ['e-print'] = 'eprint', -- misspelling -- ['ed'] = 'edition', avoid suggestion as in English this could be short for editor or edition -- ['editora'] = 'publisher', -- can be either editor or publisher -- ['editore'] = 'agency', -- can be either publisher or agency -- ['editori'] = 'editor', -- can be either editor or publisher -- ['editorial'] = 'publisher', -- can be either publisher or work ['editoin'] = 'edition', -- misspelling ['editon'] = 'edition', -- misspelling ['editorfirst'] = 'editor-first', -- old parameter name ['editorgiven'] = 'editor-given', -- old parameter name ['editorlast'] = 'editor-last', -- old parameter name ['editorlink'] = 'editor-link', -- old parameter name ['editormask'] = 'editor-mask', -- old parameter name ['editors'] = 'editor', -- old parameter name (can be emulated using multiple singular |editor= params) ['editorsurname'] = 'editor-surname', -- old parameter name ['edizione'] = 'edition', -- Italian ['embargo'] = 'pmc-embargo-date', -- former parameter name ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['enlaceroto'] = 'url-status', -- Spanish -- ['episodelink'] = 'episode-link', -- old parameter name ['erişimtarihi'] = 'access-date', -- Turkish ['eser'] = 'work', -- Turkish ['family'] = 'surname', -- misguess ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['foramt'] = 'format', -- misspelling ['fore-name'] = 'given', -- misguess/misspelling ['forename'] = 'given', -- misguess ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', -- misspelling ['fundstelle'] = 'at', -- German ['gazete'] = 'work', -- Turkish ['giornale'] = 'journal', -- Italian ['herausgeber'] = 'editor', -- German (singular and plural) ['hrsg'] = 'publisher', -- German ['hrsgreihe'] = 'editor', -- German ['idioma'] = 'language', -- Spanish ['ignore-isbn-error'] = 'isbn', -- old parameter (can be fully emulated using ((syntax))) ['ignoreisbnerror'] = 'isbn', -- former parameter alias (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['imię'] = 'first', -- Polish ['in-set'] = 'inset', -- misspelling ['interviewerlink'] = 'interviewer-link', -- former parameter alias ['interviewermask'] = 'interviewer-mask', -- former parameter alias ['isbndefekt'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnistformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isnb'] = 'isbn', -- misspelling ['issnformalfalsch'] = 'issn', -- German (can be fully emulated using ((syntax))) ['jahr'] = 'date', -- German ['jahrea'] = 'orig-date', -- German (not a direct replacement, but can be emulated) ['kapitel'] = 'chapter', -- German ['langauge'] = 'language', -- misspelling ['langue'] = 'language', -- French ['last-author-amp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['lastauthoramp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['laydate'] = 'lay-date', -- old parameter name ['laysource'] = 'lay-source', -- old parameter name ['lay-summary'] = 'lay-url', -- old parameter ['laysummary'] = 'lay-url', -- old parameter ['layurl'] = 'lay-url', -- old parameter name ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['loaction'] = 'location', -- misspelling ['local'] = 'location', -- Brazilian ['locatoin'] = 'location', -- misspelling ['lugar'] = 'location', -- Spanish -- ['mailinglist'] = 'mailing-list', -- old parameter name -- ['mapurl'] = 'map-url', -- old parameter name ['mes'] = 'date', -- Spanish (not a direct replacement) ['mese'] = 'date', -- Italian (not a direct replacement) ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['name-list-format'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', -- misspelling ['net-work'] = 'network', -- misspelling ['newpaper'] = 'newspaper', -- misspelling ['news'] = 'newspaper', ['news-group'] = 'newsgroup', -- misspelling ['news-paper'] = 'newspaper', -- misspelling ['no-cat'] = 'no-tracking', -- old parameter ['nocat'] = 'no-tracking', -- old parameter ['nom'] = 'last', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian -- ['nopp'] = 'no-pp', -- old parameter name ['notracking'] = 'no-tracking', -- old parameter ['numero'] = 'number', -- Italian, Spanish ['nummer'] = 'number', -- German ['nummerreihe'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'url-status', -- German (as 'url-status=dead') ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opera'] = 'work', -- Italian ['opublikowany'] = 'agency', -- Polish ['origdate'] = 'orig-date', -- misspelling ['originaljahr'] = 'orig-date', -- German ['originalort'] = 'publication-place', -- German ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'publication-place', -- German ['ortea'] = 'publication-place', -- German (not a direct replacement, but can be emulated) ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', -- misspelling ['pagina'] = 'page', -- Italian ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['passage'] = 'pages', -- French ['periodico'] = 'magazine', -- Spanish ['plublisher'] = 'publisher', -- misspelling ['pmcid'] = 'pmc', ['post-script'] = 'postscript', -- misspelling ['praca'] = 'work', -- Polish ['primero'] = 'first', -- Spanish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubblicazione'] = 'magazine', -- could be any kind of work -- ['publicación'] = 'journal', -- could be any kind of work -- ['publicationdate'] = 'publication-date', -- old parameter name -- ['published'] = 'publisher', -- could be date, location, or name of publisher -- ['publicationplace'] = 'publication-place', -- old parameter name ['pulbication-place'] = 'publication-place', -- misspelling ['página'] = 'page', -- Spanish ['páginas'] = 'pages', -- Spanish ['périodique'] = 'publisher', -- French ['registration'] = 'url-access', -- old parameter name (emulated as |url-access=registration) ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['richiestasottoscrizione'] = 'url-access', -- Italian (as |url-access=subscription) ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['sayfa'] = 'page', -- Turkish ['sayfalar'] = 'pages', -- Turkish ['sayı'] = 'issue', -- Turkish ['script-post'] = 'postscript', -- misspelling ['script-trans'] = 'transcript', -- misspelling ['sectionurl'] = 'section-url', -- old parameter name ['seria'] = 'series', -- Spanish, Polish ['serie'] = 'series', -- Italian ['série'] = 'series', -- French -- ['serieslink'] = 'series-link', -- old parameter name ['seriesno'] = 'series-number', -- old parameter name -- ['series-no'] = 'series-number', -- old parameter name ['service'] = 'agency', ['sitioweb'] = 'website', -- Spanish ['sito'] = 'website', -- Italian ['soyadı'] = 'last', -- Turkish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['subjectlink'] = 'subject-link', -- old parameter name ['subscription'] = 'url-access', -- old parameter name (emulated as |url-access=subscription) ['sur-name'] = 'surname', -- misspelling ['suscripción'] = 'url-access', -- Spanish, Polish (as |url-access=subscription) ['tag'] = 'date', -- German ['tarih'] = 'date', -- Turkish ['template doc demo'] = 'no-tracking', -- former parameter alias ['tile'] = 'title', -- misspelling ['timecaption'] = 'time-caption', -- old parameter name ['titlelink'] = 'title-link', -- old parameter name ['tipo'] = 'type', -- Italian ['tite'] = 'title', -- misspelling ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titled'] = 'title', -- Brazilian ['titolo'] = 'title', -- Italian ['titre'] = 'title', -- French ['trans-script'] = 'transcript', -- misspelling ['trans_chapter'] = 'trans-chapter', -- former parameter alias ['trans_title'] = 'trans-title', -- former parameter alias ['transchapter'] = 'trans-chapter', -- ['transcripturl'] = 'transcript-url', -- old parameter name ['transscript'] = 'transcript', -- misspelling ['transscript-format'] = 'transcript-format', -- misspelling ['transscript-url'] = 'transcript-url', -- misspelling ['transscripturl'] = 'transcript-url', -- misspelling ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['títle'] = 'title', ['título'] = 'title', -- Spanish ['ubicación'] = 'location', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urlarchivo'] = 'archive-url', -- Spanish ['urlmorto'] = 'url-status', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') ['v-authors'] = 'vauthors', -- misspelling ['v-editors'] = 'veditors', -- misspelling ['verlag'] = 'publisher', -- German ['verlagea'] = 'publisher', -- German (not a direct replacement, but can be emulated) ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['yardımcıyazarlar'] = 'author', -- Turkish ['yayımcı'] = 'publisher', -- Turkish ['yayıncı'] = 'publisher', -- Turkish ['yazar'] = 'author', -- Turkish ['yazarbağı'] = 'author-link', -- Turkish ['yer'] = 'location', -- Turkish ['yıl'] = 'date', -- Turkish ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German ['éditeur'] = 'editor', -- French ['ölüurl'] = 'url-status', -- Turkish ['übersetzer'] = 'translator', -- German (singular and plural) } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not REGEX though they are similar. The escape character is '%', not '\'. For more information about Lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', -- misspelling ['^apellido[s]?(%d+)$'] = 'last$1', -- Spanish, enumerated ['^a[utho]+r$'] = 'author', -- misspelling ['^a[utho]+r(%d+)$'] = 'author$1', -- misspelling, enumerated ['^author link(%d+)$'] = 'author-link$1', -- Polish, enumerated ['^autor[e]?(%d+)$'] = 'author$1', -- Italian/Spanish/German, enumerated ['^authorfirst(%d+)$'] = 'author-first$1', -- old parameter name, enumerated ['^author(%d+)first$'] = 'author-first$1', -- old parameter name, enumerated ['^authorgiven(%d+)$'] = 'author-given$1', -- old parameter name, enumerated ['^author(%d+)given$'] = 'author-given$1', -- old parameter name, enumerated ['^authorlast(%d+)$'] = 'author-last$1', -- old parameter name, enumerated ['^author(%d+)last$'] = 'author-last$1', -- old parameter name, enumerated ['^authormask(%d+)$'] = 'author-mask$1', -- old parameter name, enumerated ['^author(%d+)mask$'] = 'author-mask$1', -- old parameter name, enumerated ['^authorsurname(%d+)$'] = 'author-surname$1', -- old parameter name, enumerated ['^author(%d+)surname$'] = 'author-surname$1', -- old parameter name, enumerated ['^cognome(%d+)$'] = 'last$1', -- Italian, enumerated ['^editorfirst(%d+)$'] = 'editor-first$1', -- old parameter name, enumerated ['^editor(%d+)first$'] = 'editor-first$1', -- old parameter name, enumerated ['^editorgiven(%d+)$'] = 'editor-given$1', -- old parameter name, enumerated ['^editor(%d+)given$'] = 'editor-given$1', -- old parameter name, enumerated ['^editorlast(%d+)$'] = 'editor-last$1', -- old parameter name, enumerated ['^editor(%d+)last$'] = 'editor-last$1', -- old parameter name, enumerated ['^editorlink(%d+)$'] = 'editor-link$1', -- old parameter name, enumerated ['^editor(%d+)link$'] = 'editor-link$1', -- old parameter name, enumerated ['^editormask(%d+)$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editor(%d+)mask$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editorsurname(%d+)$'] = 'editor-surname$1', -- old parameter name, enumerated ['^editor(%d+)surname$'] = 'editor-surname$1', -- old parameter name, enumerated ['^enlaceautore(%d+)$'] = 'author-link$1', -- Spanish, enumerated ['^first (%d+)$'] = 'first$1', -- enumerated ['^last (%d+)$'] = 'last$1', -- enumerated ['^nom[e]?(%d+)$'] = 'last$1', -- Italian/French, enumerated ['^nombre(%d+)$'] = 'first$1', -- Spanish, enumerated ['^primero(%d+)$'] = 'first$1', -- Spanish, enumerated ['^pu[blish]+ers?$'] = 'publisher', -- misspelling ['^subjectlink(%d+)$'] = 'subject-link$1', -- old parameter name, enumerated ['^subject(%d+)link$'] = 'subject-link$1', -- old parameter name, enumerated ['^wkautore(%d+)$'] = 'author-link$1', -- Italian, enumerated } return {suggestions = suggestions, patterns=patterns}; s9u0skifck4dhobdjqt9lm3lqovddp6 736809 736808 2022-01-22T14:11:12Z en>Trappist the monk 0 update per [[Wikipedia:Village_pump_(proposals)#rfc:_shall_we_update_cs1/2?|RfC]]; 736809 Scribunto text/plain -- Please insert new suggestions in alphabetical order -- The form is ['incorrect'] = 'correct', suggestions = { ['ASIN-TLD'] = 'asin-tld', -- old parameter name ['abruf'] = 'access-date', -- German ['abruf-verborgen'] = 'access-date', -- German ['accessmonth'] = 'access-date', ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', ['acessodata'] = 'access-date', -- Brazilian Portuguese ['ad'] = 'first', -- Turkish ['address'] = 'location', ['anno'] = 'date', -- Italian ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['annooriginale'] = 'orig-date', -- Italian ['année'] = 'date', -- French ['apellido'] = 'last', -- Spanish ['apellidos'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archiv-url'] = 'archive-url', -- German ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish ['artikelnr'] = 'id', -- German (as 'id=Article No. ...') ['artist'] = 'others', ['arşiv-tarihi'] = 'archive-date', -- Turkish ['arşiv-url'] = 'archive-url', -- Turkish ['arşivtarihi'] = 'archive-date', -- Turkish ['arşivurl'] = 'archive-url', -- Turkish ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'author-link', -- Polish ['authorfirst'] = 'author-first', -- old parameter name ['authorgiven'] = 'author-given', -- old parameter name ['authorlast'] = 'author-last', -- old parameter name ['authormask'] = 'author-mask', -- old parameter name ['authorsurname'] = 'author-surname', -- old parameter name ['autor'] = 'author', -- Spanish, German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', ['ay'] = 'month', -- Turkish ['año'] = 'date', -- Spanish ['año-original'] = 'orig-date', -- Spanish ['añoacceso'] = 'access-date', -- Spanish ['añooriginal'] = 'orig-date', -- Spanish ['band'] = 'volume', -- German ['bandreihe'] = 'volume', -- German ['baskı'] = 'edition', -- Turkish ['başlık'] = 'title', -- Turkish ['began'] = 'date', -- old parameter name (cite serial only); or orig-date= ['booktitle'] = 'book-title', -- old parameter name ['ch'] = 'language', -- German (as 'language=de-CH') ['chapter_title'] = 'chapter', ['chapterurl'] = 'chapter-url', -- old parameter name ['cid'] = 'ref', -- Italian ['cilt'] = 'volume', -- Turkish ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['città'] = 'location', -- Italian ['city'] = 'location', -- old parameter name (cite serial only) ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['conferenceurl'] = 'conference-url', -- old parameter name ['consulté le'] = 'access-date', -- French ['contributionurl'] = 'contribution-url', -- old parameter name ['curatore'] = 'publisher', -- Italian ['czasopismo'] = 'journal', -- Polish ['data dostępu'] = 'access-date', -- Polish ['data'] = 'date', -- Polish, Italian ['dataaccesso'] = 'access-date', -- Italian ['dataarchivio'] = 'archive-date', -- Italian ['datum'] = 'date', -- German ['dead-url'] = 'url-status', -- old parameter name ['deadlink'] = 'url-status', ['deadurl'] = 'url-status', -- old parameter name ['dergi'] = 'work', -- Turkish ['dil'] = 'language', -- Turkish ['displayauthors'] = 'display-authors', -- old parameter name ['displayeditors'] = 'display-editors', -- old parameter name ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') ['doi-broken'] = 'doi-broken-date', -- old parameter alias ['doi-inactive'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-inactive-date'] = 'doi-broken-date', -- old parameter alias ['doi_brokendate'] = 'doi-broken-date', -- old parameter alias ['doi_inactivedate'] = 'doi-inactive-date', -- old parameter alias ['doibroken'] = 'doi-broken-date', -- invalid name found in mainspace ['doiinactive'] = 'doi-broken-date', -- invalid name found in mainspace ['e-print'] = 'eprint', -- misspelling -- ['ed'] = 'edition', -- avoid suggestion as in English this could be short for editor or edition -- ['editora'] = 'publisher', -- can be either editor or publisher -- ['editore'] = 'agency', -- can be either publisher or agency -- ['editori'] = 'editor', -- can be either editor or publisher -- ['editorial'] = 'publisher', -- can be either publisher or work ['editoin'] = 'edition', -- misspelling ['editon'] = 'edition', -- misspelling ['editorfirst'] = 'editor-first', -- old parameter name ['editorgiven'] = 'editor-given', -- old parameter name ['editorlast'] = 'editor-last', -- old parameter name ['editorlink'] = 'editor-link', -- old parameter name ['editormask'] = 'editor-mask', -- old parameter name ['editors'] = 'editor', -- old parameter name (can be emulated using multiple singular |editor= params) ['editorsurname'] = 'editor-surname', -- old parameter name ['edizione'] = 'edition', -- Italian ['embargo'] = 'pmc-embargo-date', -- old parameter name ['ended'] = 'date', -- old parameter name (cite serial only) ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['enlaceroto'] = 'url-status', -- Spanish ['episodelink'] = 'episode-link', -- old parameter name ['erişimtarihi'] = 'access-date', -- Turkish ['eser'] = 'work', -- Turkish ['family'] = 'surname', -- misguess ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['foramt'] = 'format', -- misspelling ['fore-name'] = 'given', -- misguess/misspelling ['forename'] = 'given', -- misguess ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', -- misspelling ['fundstelle'] = 'at', -- German ['gazete'] = 'work', -- Turkish ['giornale'] = 'journal', -- Italian ['herausgeber'] = 'editor', -- German (singular and plural) ['hrsg'] = 'publisher', -- German ['hrsgreihe'] = 'editor', -- German ['idioma'] = 'language', -- Spanish ['ignore-isbn-error'] = 'isbn', -- old parameter (can be fully emulated using ((syntax))) ['ignoreisbnerror'] = 'isbn', -- old parameter alias (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['imię'] = 'first', -- Polish ['in-set'] = 'inset', -- misspelling ['interviewerlink'] = 'interviewer-link', -- old parameter alias ['interviewermask'] = 'interviewer-mask', -- old parameter alias ['isbndefekt'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnistformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isnb'] = 'isbn', -- misspelling ['issnformalfalsch'] = 'issn', -- German (can be fully emulated using ((syntax))) ['jahr'] = 'date', -- German ['jahrea'] = 'orig-date', -- German (not a direct replacement, but can be emulated) ['kapitel'] = 'chapter', -- German ['langauge'] = 'language', -- misspelling ['langue'] = 'language', -- French ['last-author-amp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['lastauthoramp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['laydate'] = 'lay-date', -- old parameter name ['laysource'] = 'lay-source', -- old parameter name ['lay-summary'] = 'lay-url', -- old parameter ['laysummary'] = 'lay-url', -- old parameter ['layurl'] = 'lay-url', -- old parameter name ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License No. ...') ['loaction'] = 'location', -- misspelling ['local'] = 'location', -- Brazilian Portuguese ['locatoin'] = 'location', -- misspelling ['lugar'] = 'location', -- Spanish ['mailinglist'] = 'mailing-list', -- old parameter name ['mapurl'] = 'map-url', -- old parameter name ['mes'] = 'date', -- Spanish (not a direct replacement) ['mese'] = 'date', -- Italian (not a direct replacement) ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['name-list-format'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', -- misspelling ['net-work'] = 'network', -- misspelling ['newpaper'] = 'newspaper', -- misspelling ['news'] = 'newspaper', ['news-group'] = 'newsgroup', -- misspelling ['news-paper'] = 'newspaper', -- misspelling ['no-cat'] = 'no-tracking', -- old parameter ['nocat'] = 'no-tracking', -- old parameter ['nom'] = 'last', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['nopp'] = 'no-pp', -- old parameter name ['notracking'] = 'no-tracking', -- old parameter ['numero'] = 'number', -- Italian, Spanish ['nummer'] = 'number', -- German ['nummerreihe'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'url-status', -- German (as 'url-status=dead') ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opera'] = 'work', -- Italian ['opublikowany'] = 'agency', -- Polish ['origdate'] = 'orig-date', -- misspelling ['originaljahr'] = 'orig-date', -- German ['originalort'] = 'publication-place', -- German ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'publication-place', -- German ['ortea'] = 'publication-place', -- German (not a direct replacement, but can be emulated) ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', -- misspelling ['pagina'] = 'page', -- Italian ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['passage'] = 'pages', -- French ['periodico'] = 'magazine', -- Spanish ['plublisher'] = 'publisher', -- misspelling ['pmcid'] = 'pmc', ['post-script'] = 'postscript', -- misspelling ['praca'] = 'work', -- Polish ['primero'] = 'first', -- Spanish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubblicazione'] = 'magazine', -- could be any kind of work -- ['publicación'] = 'journal', -- could be any kind of work ['publicationdate'] = 'publication-date', -- old parameter name -- ['published'] = 'publisher', -- could be date, location, or name of publisher ['publicationplace'] = 'publication-place', -- old parameter name ['pulbication-place'] = 'publication-place', -- misspelling ['página'] = 'page', -- Spanish ['páginas'] = 'pages', -- Spanish ['périodique'] = 'publisher', -- French ['registration'] = 'url-access', -- old parameter name ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['richiestasottoscrizione'] = 'url-access', -- Italian (as |url-access=subscription) ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['sayfa'] = 'page', -- Turkish ['sayfalar'] = 'pages', -- Turkish ['sayı'] = 'issue', -- Turkish ['script-post'] = 'postscript', -- misspelling ['script-trans'] = 'transcript', -- misspelling ['season'] = 'date', -- old parameter name (cite serial only) ['sectionurl'] = 'section-url', -- old parameter name ['seiten'] = 'pages', -- German ['seria'] = 'series', -- Spanish, Polish ['serie'] = 'series', -- Italian ['série'] = 'series', -- French ['serieslink'] = 'series-link', -- old parameter name ['seriesno'] = 'series-number', -- old parameter name ['service'] = 'agency', ['sitioweb'] = 'website', -- Spanish ['sito'] = 'website', -- Italian ['soyadı'] = 'last', -- Turkish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['subjectlink'] = 'subject-link', -- old parameter name ['subscription'] = 'url-access', -- old parameter name (emulated as |url-access=subscription) ['sur-name'] = 'surname', -- misspelling ['suscripción'] = 'url-access', -- Spanish, Polish (as |url-access=subscription) ['tag'] = 'date', -- German ['tarih'] = 'date', -- Turkish ['template doc demo'] = 'no-tracking', -- old parameter alias ['tile'] = 'title', -- misspelling ['timecaption'] = 'time-caption', -- old parameter name ['titlelink'] = 'title-link', -- old parameter name ['tipo'] = 'type', -- Italian ['tite'] = 'title', -- misspelling ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titled'] = 'title', -- Brazilian Portuguese ['titolo'] = 'title', -- Italian ['titre'] = 'title', -- French ['trans-script'] = 'transcript', -- misspelling ['trans_chapter'] = 'trans-chapter', -- old parameter alias ['trans_title'] = 'trans-title', -- old parameter alias ['transchapter'] = 'trans-chapter', ['transcripturl'] = 'transcript-url', -- old parameter name ['transscript'] = 'transcript', -- misspelling ['transscript-format'] = 'transcript-format', -- misspelling ['transscript-url'] = 'transcript-url', -- misspelling ['transscripturl'] = 'transcript-url', -- misspelling ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['títle'] = 'title', ['título'] = 'title', -- Spanish ['ubicación'] = 'location', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urlarchivo'] = 'archive-url', -- Spanish ['urlmorto'] = 'url-status', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') ['v-authors'] = 'vauthors', -- misspelling ['v-editors'] = 'veditors', -- misspelling ['verlag'] = 'publisher', -- German ['verlagea'] = 'publisher', -- German (not a direct replacement, but can be emulated) ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['yardımcıyazarlar'] = 'author', -- Turkish ['yayımcı'] = 'publisher', -- Turkish ['yayıncı'] = 'publisher', -- Turkish ['yazar'] = 'author', -- Turkish ['yazarbağı'] = 'author-link', -- Turkish ['yer'] = 'location', -- Turkish ['yıl'] = 'date', -- Turkish ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German ['éditeur'] = 'editor', -- French ['ölüurl'] = 'url-status', -- Turkish ['übersetzer'] = 'translator', -- German (singular and plural) } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not REGEX though they are similar. The escape character is '%', not '\'. For more information about Lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', -- misspelling ['^apellido[s]?(%d+)$'] = 'last$1', -- Spanish, enumerated ['^a[utho]+r$'] = 'author', -- misspelling ['^a[utho]+r(%d+)$'] = 'author$1', -- misspelling, enumerated ['^author link(%d+)$'] = 'author-link$1', -- Polish, enumerated ['^autor[e]?(%d+)$'] = 'author$1', -- Italian/Spanish/German, enumerated ['^authorfirst(%d+)$'] = 'author-first$1', -- old parameter name, enumerated ['^author(%d+)first$'] = 'author-first$1', -- old parameter name, enumerated ['^authorgiven(%d+)$'] = 'author-given$1', -- old parameter name, enumerated ['^author(%d+)given$'] = 'author-given$1', -- old parameter name, enumerated ['^authorlast(%d+)$'] = 'author-last$1', -- old parameter name, enumerated ['^author(%d+)last$'] = 'author-last$1', -- old parameter name, enumerated ['^authormask(%d+)$'] = 'author-mask$1', -- old parameter name, enumerated ['^author(%d+)mask$'] = 'author-mask$1', -- old parameter name, enumerated ['^authorsurname(%d+)$'] = 'author-surname$1', -- old parameter name, enumerated ['^author(%d+)surname$'] = 'author-surname$1', -- old parameter name, enumerated ['^cognome(%d+)$'] = 'last$1', -- Italian, enumerated ['^editorfirst(%d+)$'] = 'editor-first$1', -- old parameter name, enumerated ['^editor(%d+)first$'] = 'editor-first$1', -- old parameter name, enumerated ['^editorgiven(%d+)$'] = 'editor-given$1', -- old parameter name, enumerated ['^editor(%d+)given$'] = 'editor-given$1', -- old parameter name, enumerated ['^editorlast(%d+)$'] = 'editor-last$1', -- old parameter name, enumerated ['^editor(%d+)last$'] = 'editor-last$1', -- old parameter name, enumerated ['^editorlink(%d+)$'] = 'editor-link$1', -- old parameter name, enumerated ['^editor(%d+)link$'] = 'editor-link$1', -- old parameter name, enumerated ['^editormask(%d+)$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editor(%d+)mask$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editorsurname(%d+)$'] = 'editor-surname$1', -- old parameter name, enumerated ['^editor(%d+)surname$'] = 'editor-surname$1', -- old parameter name, enumerated ['^enlaceautore(%d+)$'] = 'author-link$1', -- Spanish, enumerated ['^first (%d+)$'] = 'first$1', -- enumerated ['^last (%d+)$'] = 'last$1', -- enumerated ['^nom[e]?(%d+)$'] = 'last$1', -- Italian/French, enumerated ['^nombre(%d+)$'] = 'first$1', -- Spanish, enumerated ['^primero(%d+)$'] = 'first$1', -- Spanish, enumerated ['^pu[blish]+ers?$'] = 'publisher', -- misspelling ['^subjectlink(%d+)$'] = 'subject-link$1', -- old parameter name, enumerated ['^subject(%d+)link$'] = 'subject-link$1', -- old parameter name, enumerated ['^wkautore(%d+)$'] = 'author-link$1', -- Italian, enumerated } return {suggestions = suggestions, patterns=patterns}; fvy9my3azvema7o33x1ls9jjcjirsp8 736810 736809 2022-01-23T00:11:45Z en>Jonesey95 0 restore archive-link 736810 Scribunto text/plain -- Please insert new suggestions in alphabetical order -- The form is ['incorrect'] = 'correct', suggestions = { ['ASIN-TLD'] = 'asin-tld', -- old parameter name ['abruf'] = 'access-date', -- German ['abruf-verborgen'] = 'access-date', -- German ['accessmonth'] = 'access-date', ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', ['acessodata'] = 'access-date', -- Brazilian Portuguese ['ad'] = 'first', -- Turkish ['address'] = 'location', ['anno'] = 'date', -- Italian ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['annooriginale'] = 'orig-date', -- Italian ['année'] = 'date', -- French ['apellido'] = 'last', -- Spanish ['apellidos'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archiv-url'] = 'archive-url', -- German ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish ['archive-link'] = 'archive-url', ['artikelnr'] = 'id', -- German (as 'id=Article No. ...') ['artist'] = 'others', ['arşiv-tarihi'] = 'archive-date', -- Turkish ['arşiv-url'] = 'archive-url', -- Turkish ['arşivtarihi'] = 'archive-date', -- Turkish ['arşivurl'] = 'archive-url', -- Turkish ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'author-link', -- Polish ['authorfirst'] = 'author-first', -- old parameter name ['authorgiven'] = 'author-given', -- old parameter name ['authorlast'] = 'author-last', -- old parameter name ['authormask'] = 'author-mask', -- old parameter name ['authorsurname'] = 'author-surname', -- old parameter name ['autor'] = 'author', -- Spanish, German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', ['ay'] = 'month', -- Turkish ['año'] = 'date', -- Spanish ['año-original'] = 'orig-date', -- Spanish ['añoacceso'] = 'access-date', -- Spanish ['añooriginal'] = 'orig-date', -- Spanish ['band'] = 'volume', -- German ['bandreihe'] = 'volume', -- German ['baskı'] = 'edition', -- Turkish ['başlık'] = 'title', -- Turkish ['began'] = 'date', -- old parameter name (cite serial only); or orig-date= ['booktitle'] = 'book-title', -- old parameter name ['ch'] = 'language', -- German (as 'language=de-CH') ['chapter_title'] = 'chapter', ['chapterurl'] = 'chapter-url', -- old parameter name ['cid'] = 'ref', -- Italian ['cilt'] = 'volume', -- Turkish ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['città'] = 'location', -- Italian ['city'] = 'location', -- old parameter name (cite serial only) ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['conferenceurl'] = 'conference-url', -- old parameter name ['consulté le'] = 'access-date', -- French ['contributionurl'] = 'contribution-url', -- old parameter name ['curatore'] = 'publisher', -- Italian ['czasopismo'] = 'journal', -- Polish ['data dostępu'] = 'access-date', -- Polish ['data'] = 'date', -- Polish, Italian ['dataaccesso'] = 'access-date', -- Italian ['dataarchivio'] = 'archive-date', -- Italian ['datum'] = 'date', -- German ['dead-url'] = 'url-status', -- old parameter name ['deadlink'] = 'url-status', ['deadurl'] = 'url-status', -- old parameter name ['dergi'] = 'work', -- Turkish ['dil'] = 'language', -- Turkish ['displayauthors'] = 'display-authors', -- old parameter name ['displayeditors'] = 'display-editors', -- old parameter name ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') ['doi-broken'] = 'doi-broken-date', -- old parameter alias ['doi-inactive'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-inactive-date'] = 'doi-broken-date', -- old parameter alias ['doi_brokendate'] = 'doi-broken-date', -- old parameter alias ['doi_inactivedate'] = 'doi-inactive-date', -- old parameter alias ['doibroken'] = 'doi-broken-date', -- invalid name found in mainspace ['doiinactive'] = 'doi-broken-date', -- invalid name found in mainspace ['e-print'] = 'eprint', -- misspelling -- ['ed'] = 'edition', -- avoid suggestion as in English this could be short for editor or edition -- ['editora'] = 'publisher', -- can be either editor or publisher -- ['editore'] = 'agency', -- can be either publisher or agency -- ['editori'] = 'editor', -- can be either editor or publisher -- ['editorial'] = 'publisher', -- can be either publisher or work ['editoin'] = 'edition', -- misspelling ['editon'] = 'edition', -- misspelling ['editorfirst'] = 'editor-first', -- old parameter name ['editorgiven'] = 'editor-given', -- old parameter name ['editorlast'] = 'editor-last', -- old parameter name ['editorlink'] = 'editor-link', -- old parameter name ['editormask'] = 'editor-mask', -- old parameter name ['editors'] = 'editor', -- old parameter name (can be emulated using multiple singular |editor= params) ['editorsurname'] = 'editor-surname', -- old parameter name ['edizione'] = 'edition', -- Italian ['embargo'] = 'pmc-embargo-date', -- old parameter name ['ended'] = 'date', -- old parameter name (cite serial only) ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['enlaceroto'] = 'url-status', -- Spanish ['episodelink'] = 'episode-link', -- old parameter name ['erişimtarihi'] = 'access-date', -- Turkish ['eser'] = 'work', -- Turkish ['family'] = 'surname', -- misguess ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['foramt'] = 'format', -- misspelling ['fore-name'] = 'given', -- misguess/misspelling ['forename'] = 'given', -- misguess ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', -- misspelling ['fundstelle'] = 'at', -- German ['gazete'] = 'work', -- Turkish ['giornale'] = 'journal', -- Italian ['herausgeber'] = 'editor', -- German (singular and plural) ['hrsg'] = 'publisher', -- German ['hrsgreihe'] = 'editor', -- German ['idioma'] = 'language', -- Spanish ['ignore-isbn-error'] = 'isbn', -- old parameter (can be fully emulated using ((syntax))) ['ignoreisbnerror'] = 'isbn', -- old parameter alias (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['imię'] = 'first', -- Polish ['in-set'] = 'inset', -- misspelling ['interviewerlink'] = 'interviewer-link', -- old parameter alias ['interviewermask'] = 'interviewer-mask', -- old parameter alias ['isbndefekt'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnistformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isnb'] = 'isbn', -- misspelling ['issnformalfalsch'] = 'issn', -- German (can be fully emulated using ((syntax))) ['jahr'] = 'date', -- German ['jahrea'] = 'orig-date', -- German (not a direct replacement, but can be emulated) ['kapitel'] = 'chapter', -- German ['langauge'] = 'language', -- misspelling ['langue'] = 'language', -- French ['last-author-amp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['lastauthoramp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['laydate'] = 'lay-date', -- old parameter name ['laysource'] = 'lay-source', -- old parameter name ['lay-summary'] = 'lay-url', -- old parameter ['laysummary'] = 'lay-url', -- old parameter ['layurl'] = 'lay-url', -- old parameter name ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License No. ...') ['loaction'] = 'location', -- misspelling ['local'] = 'location', -- Brazilian Portuguese ['locatoin'] = 'location', -- misspelling ['lugar'] = 'location', -- Spanish ['mailinglist'] = 'mailing-list', -- old parameter name ['mapurl'] = 'map-url', -- old parameter name ['mes'] = 'date', -- Spanish (not a direct replacement) ['mese'] = 'date', -- Italian (not a direct replacement) ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['name-list-format'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', -- misspelling ['net-work'] = 'network', -- misspelling ['newpaper'] = 'newspaper', -- misspelling ['news'] = 'newspaper', ['news-group'] = 'newsgroup', -- misspelling ['news-paper'] = 'newspaper', -- misspelling ['no-cat'] = 'no-tracking', -- old parameter ['nocat'] = 'no-tracking', -- old parameter ['nom'] = 'last', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['nopp'] = 'no-pp', -- old parameter name ['notracking'] = 'no-tracking', -- old parameter ['numero'] = 'number', -- Italian, Spanish ['nummer'] = 'number', -- German ['nummerreihe'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'url-status', -- German (as 'url-status=dead') ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opera'] = 'work', -- Italian ['opublikowany'] = 'agency', -- Polish ['origdate'] = 'orig-date', -- misspelling ['originaljahr'] = 'orig-date', -- German ['originalort'] = 'publication-place', -- German ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'publication-place', -- German ['ortea'] = 'publication-place', -- German (not a direct replacement, but can be emulated) ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', -- misspelling ['pagina'] = 'page', -- Italian ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['passage'] = 'pages', -- French ['periodico'] = 'magazine', -- Spanish ['plublisher'] = 'publisher', -- misspelling ['pmcid'] = 'pmc', ['post-script'] = 'postscript', -- misspelling ['praca'] = 'work', -- Polish ['primero'] = 'first', -- Spanish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubblicazione'] = 'magazine', -- could be any kind of work -- ['publicación'] = 'journal', -- could be any kind of work ['publicationdate'] = 'publication-date', -- old parameter name -- ['published'] = 'publisher', -- could be date, location, or name of publisher ['publicationplace'] = 'publication-place', -- old parameter name ['pulbication-place'] = 'publication-place', -- misspelling ['página'] = 'page', -- Spanish ['páginas'] = 'pages', -- Spanish ['périodique'] = 'publisher', -- French ['registration'] = 'url-access', -- old parameter name ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['richiestasottoscrizione'] = 'url-access', -- Italian (as |url-access=subscription) ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['sayfa'] = 'page', -- Turkish ['sayfalar'] = 'pages', -- Turkish ['sayı'] = 'issue', -- Turkish ['script-post'] = 'postscript', -- misspelling ['script-trans'] = 'transcript', -- misspelling ['season'] = 'date', -- old parameter name (cite serial only) ['sectionurl'] = 'section-url', -- old parameter name ['seiten'] = 'pages', -- German ['seria'] = 'series', -- Spanish, Polish ['serie'] = 'series', -- Italian ['série'] = 'series', -- French ['serieslink'] = 'series-link', -- old parameter name ['seriesno'] = 'series-number', -- old parameter name ['service'] = 'agency', ['sitioweb'] = 'website', -- Spanish ['sito'] = 'website', -- Italian ['soyadı'] = 'last', -- Turkish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['subjectlink'] = 'subject-link', -- old parameter name ['subscription'] = 'url-access', -- old parameter name (emulated as |url-access=subscription) ['sur-name'] = 'surname', -- misspelling ['suscripción'] = 'url-access', -- Spanish, Polish (as |url-access=subscription) ['tag'] = 'date', -- German ['tarih'] = 'date', -- Turkish ['template doc demo'] = 'no-tracking', -- old parameter alias ['tile'] = 'title', -- misspelling ['timecaption'] = 'time-caption', -- old parameter name ['titlelink'] = 'title-link', -- old parameter name ['tipo'] = 'type', -- Italian ['tite'] = 'title', -- misspelling ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titled'] = 'title', -- Brazilian Portuguese ['titolo'] = 'title', -- Italian ['titre'] = 'title', -- French ['trans-script'] = 'transcript', -- misspelling ['trans_chapter'] = 'trans-chapter', -- old parameter alias ['trans_title'] = 'trans-title', -- old parameter alias ['transchapter'] = 'trans-chapter', ['transcripturl'] = 'transcript-url', -- old parameter name ['transscript'] = 'transcript', -- misspelling ['transscript-format'] = 'transcript-format', -- misspelling ['transscript-url'] = 'transcript-url', -- misspelling ['transscripturl'] = 'transcript-url', -- misspelling ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['títle'] = 'title', ['título'] = 'title', -- Spanish ['ubicación'] = 'location', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urlarchivo'] = 'archive-url', -- Spanish ['urlmorto'] = 'url-status', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') ['v-authors'] = 'vauthors', -- misspelling ['v-editors'] = 'veditors', -- misspelling ['verlag'] = 'publisher', -- German ['verlagea'] = 'publisher', -- German (not a direct replacement, but can be emulated) ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['yardımcıyazarlar'] = 'author', -- Turkish ['yayımcı'] = 'publisher', -- Turkish ['yayıncı'] = 'publisher', -- Turkish ['yazar'] = 'author', -- Turkish ['yazarbağı'] = 'author-link', -- Turkish ['yer'] = 'location', -- Turkish ['yıl'] = 'date', -- Turkish ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German ['éditeur'] = 'editor', -- French ['ölüurl'] = 'url-status', -- Turkish ['übersetzer'] = 'translator', -- German (singular and plural) } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not REGEX though they are similar. The escape character is '%', not '\'. For more information about Lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', -- misspelling ['^apellido[s]?(%d+)$'] = 'last$1', -- Spanish, enumerated ['^a[utho]+r$'] = 'author', -- misspelling ['^a[utho]+r(%d+)$'] = 'author$1', -- misspelling, enumerated ['^author link(%d+)$'] = 'author-link$1', -- Polish, enumerated ['^autor[e]?(%d+)$'] = 'author$1', -- Italian/Spanish/German, enumerated ['^authorfirst(%d+)$'] = 'author-first$1', -- old parameter name, enumerated ['^author(%d+)first$'] = 'author-first$1', -- old parameter name, enumerated ['^authorgiven(%d+)$'] = 'author-given$1', -- old parameter name, enumerated ['^author(%d+)given$'] = 'author-given$1', -- old parameter name, enumerated ['^authorlast(%d+)$'] = 'author-last$1', -- old parameter name, enumerated ['^author(%d+)last$'] = 'author-last$1', -- old parameter name, enumerated ['^authormask(%d+)$'] = 'author-mask$1', -- old parameter name, enumerated ['^author(%d+)mask$'] = 'author-mask$1', -- old parameter name, enumerated ['^authorsurname(%d+)$'] = 'author-surname$1', -- old parameter name, enumerated ['^author(%d+)surname$'] = 'author-surname$1', -- old parameter name, enumerated ['^cognome(%d+)$'] = 'last$1', -- Italian, enumerated ['^editorfirst(%d+)$'] = 'editor-first$1', -- old parameter name, enumerated ['^editor(%d+)first$'] = 'editor-first$1', -- old parameter name, enumerated ['^editorgiven(%d+)$'] = 'editor-given$1', -- old parameter name, enumerated ['^editor(%d+)given$'] = 'editor-given$1', -- old parameter name, enumerated ['^editorlast(%d+)$'] = 'editor-last$1', -- old parameter name, enumerated ['^editor(%d+)last$'] = 'editor-last$1', -- old parameter name, enumerated ['^editorlink(%d+)$'] = 'editor-link$1', -- old parameter name, enumerated ['^editor(%d+)link$'] = 'editor-link$1', -- old parameter name, enumerated ['^editormask(%d+)$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editor(%d+)mask$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editorsurname(%d+)$'] = 'editor-surname$1', -- old parameter name, enumerated ['^editor(%d+)surname$'] = 'editor-surname$1', -- old parameter name, enumerated ['^enlaceautore(%d+)$'] = 'author-link$1', -- Spanish, enumerated ['^first (%d+)$'] = 'first$1', -- enumerated ['^last (%d+)$'] = 'last$1', -- enumerated ['^nom[e]?(%d+)$'] = 'last$1', -- Italian/French, enumerated ['^nombre(%d+)$'] = 'first$1', -- Spanish, enumerated ['^primero(%d+)$'] = 'first$1', -- Spanish, enumerated ['^pu[blish]+ers?$'] = 'publisher', -- misspelling ['^subjectlink(%d+)$'] = 'subject-link$1', -- old parameter name, enumerated ['^subject(%d+)link$'] = 'subject-link$1', -- old parameter name, enumerated ['^wkautore(%d+)$'] = 'author-link$1', -- Italian, enumerated } return {suggestions = suggestions, patterns=patterns}; m16nckx5oqze6p7w1k19jmtk3t0io9r 736811 736810 2022-07-01T17:45:19Z en>Trappist the monk 0 sync from sandbox; 736811 Scribunto text/plain -- Please insert new suggestions in alphabetical order -- The form is ['incorrect'] = 'correct', suggestions = { ['ASIN-TLD'] = 'asin-tld', -- old parameter name ['abruf'] = 'access-date', -- German ['abruf-verborgen'] = 'access-date', -- German ['accessmonth'] = 'access-date', ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', ['acessodata'] = 'access-date', -- Brazilian Portuguese ['ad'] = 'first', -- Turkish ['address'] = 'location', ['anno'] = 'date', -- Italian ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['annooriginale'] = 'orig-date', -- Italian ['année'] = 'date', -- French ['apellido'] = 'last', -- Spanish ['apellidos'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archiv-url'] = 'archive-url', -- German ['archive date'] = 'archive-date', ['archive url'] = 'archive-url', -- Spanish ['archive-link'] = 'archive-url', ['artikelnr'] = 'id', -- German (as 'id=Article No. ...') ['artist'] = 'others', ['arşiv-tarihi'] = 'archive-date', -- Turkish ['arşiv-url'] = 'archive-url', -- Turkish ['arşivtarihi'] = 'archive-date', -- Turkish ['arşivurl'] = 'archive-url', -- Turkish ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', ['author link'] = 'author-link', -- Polish ['authorfirst'] = 'author-first', -- old parameter name ['authorgiven'] = 'author-given', -- old parameter name ['authorlast'] = 'author-last', -- old parameter name ['authormask'] = 'author-mask', -- old parameter name ['authorsurname'] = 'author-surname', -- old parameter name ['autor'] = 'author', -- Spanish, German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', ['ay'] = 'month', -- Turkish ['año'] = 'date', -- Spanish ['año-original'] = 'orig-date', -- Spanish ['añoacceso'] = 'access-date', -- Spanish ['añooriginal'] = 'orig-date', -- Spanish ['band'] = 'volume', -- German ['bandreihe'] = 'volume', -- German ['baskı'] = 'edition', -- Turkish ['başlık'] = 'title', -- Turkish ['began'] = 'date', -- old parameter name (cite serial only); or orig-date= ['booktitle'] = 'book-title', -- old parameter name ['ch'] = 'language', -- German (as 'language=de-CH') ['chapter_title'] = 'chapter', ['chapterurl'] = 'chapter-url', -- old parameter name ['cid'] = 'ref', -- Italian ['cilt'] = 'volume', -- Turkish ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['città'] = 'location', -- Italian ['city'] = 'location', -- old parameter name (cite serial only) ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['conferenceurl'] = 'conference-url', -- old parameter name ['consulté le'] = 'access-date', -- French ['contributionurl'] = 'contribution-url', -- old parameter name ['curatore'] = 'publisher', -- Italian ['czasopismo'] = 'journal', -- Polish ['data dostępu'] = 'access-date', -- Polish ['data'] = 'date', -- Polish, Italian ['dataaccesso'] = 'access-date', -- Italian ['dataarchivio'] = 'archive-date', -- Italian ['datum'] = 'date', -- German ['dead-url'] = 'url-status', -- old parameter name ['deadlink'] = 'url-status', ['deadurl'] = 'url-status', -- old parameter name ['dergi'] = 'work', -- Turkish ['dil'] = 'language', -- Turkish ['displayauthors'] = 'display-authors', -- old parameter name ['displayeditors'] = 'display-editors', -- old parameter name ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') ['doi-broken'] = 'doi-broken-date', -- old parameter alias ['doi-inactive'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-inactive-date'] = 'doi-broken-date', -- old parameter alias ['doi_brokendate'] = 'doi-broken-date', -- old parameter alias ['doi_inactivedate'] = 'doi-inactive-date', -- old parameter alias ['doibroken'] = 'doi-broken-date', -- invalid name found in mainspace ['doiinactive'] = 'doi-broken-date', -- invalid name found in mainspace ['e-print'] = 'eprint', -- misspelling -- ['ed'] = 'edition', -- avoid suggestion as in English this could be short for editor or edition -- ['editora'] = 'publisher', -- can be either editor or publisher -- ['editore'] = 'agency', -- can be either publisher or agency -- ['editori'] = 'editor', -- can be either editor or publisher -- ['editorial'] = 'publisher', -- can be either publisher or work ['editoin'] = 'edition', -- misspelling ['editon'] = 'edition', -- misspelling ['editorfirst'] = 'editor-first', -- old parameter name ['editorgiven'] = 'editor-given', -- old parameter name ['editorlast'] = 'editor-last', -- old parameter name ['editorlink'] = 'editor-link', -- old parameter name ['editormask'] = 'editor-mask', -- old parameter name ['editors'] = 'editor', -- old parameter name (can be emulated using multiple singular |editor= params) ['editorsurname'] = 'editor-surname', -- old parameter name ['edizione'] = 'edition', -- Italian ['embargo'] = 'pmc-embargo-date', -- old parameter name ['ended'] = 'date', -- old parameter name (cite serial only) ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['enlaceroto'] = 'url-status', -- Spanish ['episodelink'] = 'episode-link', -- old parameter name ['erişimtarihi'] = 'access-date', -- Turkish ['eser'] = 'work', -- Turkish ['family'] = 'surname', -- misguess ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['foramt'] = 'format', -- misspelling ['fore-name'] = 'given', -- misguess/misspelling ['forename'] = 'given', -- misguess ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', -- misspelling ['fundstelle'] = 'at', -- German ['gazete'] = 'work', -- Turkish ['giornale'] = 'journal', -- Italian ['herausgeber'] = 'editor', -- German (singular and plural) ['hrsg'] = 'publisher', -- German ['hrsgreihe'] = 'editor', -- German ['idioma'] = 'language', -- Spanish ['ignore-isbn-error'] = 'isbn', -- old parameter (can be fully emulated using ((syntax))) ['ignoreisbnerror'] = 'isbn', -- old parameter alias (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['imię'] = 'first', -- Polish ['in-set'] = 'inset', -- misspelling ['interviewerlink'] = 'interviewer-link', -- old parameter alias ['interviewermask'] = 'interviewer-mask', -- old parameter alias ['isbndefekt'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnistformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isnb'] = 'isbn', -- misspelling ['issnformalfalsch'] = 'issn', -- German (can be fully emulated using ((syntax))) ['jahr'] = 'date', -- German ['jahrea'] = 'orig-date', -- German (not a direct replacement, but can be emulated) ['kapitel'] = 'chapter', -- German ['langauge'] = 'language', -- misspelling ['langue'] = 'language', -- French ['last-author-amp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['lastauthoramp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License No. ...') ['loaction'] = 'location', -- misspelling ['local'] = 'location', -- Brazilian Portuguese ['locatoin'] = 'location', -- misspelling ['lugar'] = 'location', -- Spanish ['mailinglist'] = 'mailing-list', -- old parameter name ['mapurl'] = 'map-url', -- old parameter name ['mes'] = 'date', -- Spanish (not a direct replacement) ['mese'] = 'date', -- Italian (not a direct replacement) ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['name-list-format'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', -- misspelling ['net-work'] = 'network', -- misspelling ['newpaper'] = 'newspaper', -- misspelling ['news'] = 'newspaper', ['news-group'] = 'newsgroup', -- misspelling ['news-paper'] = 'newspaper', -- misspelling ['no-cat'] = 'no-tracking', -- old parameter ['nocat'] = 'no-tracking', -- old parameter ['nom'] = 'last', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['nopp'] = 'no-pp', -- old parameter name ['notracking'] = 'no-tracking', -- old parameter ['numero'] = 'number', -- Italian, Spanish ['nummer'] = 'number', -- German ['nummerreihe'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'url-status', -- German (as 'url-status=dead') ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opera'] = 'work', -- Italian ['opublikowany'] = 'agency', -- Polish ['origdate'] = 'orig-date', -- misspelling ['originaljahr'] = 'orig-date', -- German ['originalort'] = 'publication-place', -- German ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'publication-place', -- German ['ortea'] = 'publication-place', -- German (not a direct replacement, but can be emulated) ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', -- misspelling ['pagina'] = 'page', -- Italian ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['passage'] = 'pages', -- French ['periodico'] = 'magazine', -- Spanish ['plublisher'] = 'publisher', -- misspelling ['pmcid'] = 'pmc', ['post-script'] = 'postscript', -- misspelling ['praca'] = 'work', -- Polish ['primero'] = 'first', -- Spanish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubblicazione'] = 'magazine', -- could be any kind of work -- ['publicación'] = 'journal', -- could be any kind of work ['publicationdate'] = 'publication-date', -- old parameter name -- ['published'] = 'publisher', -- could be date, location, or name of publisher ['publicationplace'] = 'publication-place', -- old parameter name ['pulbication-place'] = 'publication-place', -- misspelling ['página'] = 'page', -- Spanish ['páginas'] = 'pages', -- Spanish ['périodique'] = 'publisher', -- French ['registration'] = 'url-access', -- old parameter name ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', ['richiestasottoscrizione'] = 'url-access', -- Italian (as |url-access=subscription) ['rok'] = 'date', -- Polish ['sammelwerk'] = 'work', -- German ['sayfa'] = 'page', -- Turkish ['sayfalar'] = 'pages', -- Turkish ['sayı'] = 'issue', -- Turkish ['script-post'] = 'postscript', -- misspelling ['script-trans'] = 'transcript', -- misspelling ['season'] = 'date', -- old parameter name (cite serial only) ['sectionurl'] = 'section-url', -- old parameter name ['seiten'] = 'pages', -- German ['seria'] = 'series', -- Spanish, Polish ['serie'] = 'series', -- Italian ['série'] = 'series', -- French ['serieslink'] = 'series-link', -- old parameter name ['seriesno'] = 'series-number', -- old parameter name ['service'] = 'agency', ['sitioweb'] = 'website', -- Spanish ['sito'] = 'website', -- Italian ['soyadı'] = 'last', -- Turkish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['subjectlink'] = 'subject-link', -- old parameter name ['subscription'] = 'url-access', -- old parameter name (emulated as |url-access=subscription) ['sur-name'] = 'surname', -- misspelling ['suscripción'] = 'url-access', -- Spanish, Polish (as |url-access=subscription) ['tag'] = 'date', -- German ['tarih'] = 'date', -- Turkish ['template doc demo'] = 'no-tracking', -- old parameter alias ['tile'] = 'title', -- misspelling ['timecaption'] = 'time-caption', -- old parameter name ['titlelink'] = 'title-link', -- old parameter name ['tipo'] = 'type', -- Italian ['tite'] = 'title', -- misspelling ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titled'] = 'title', -- Brazilian Portuguese ['titolo'] = 'title', -- Italian ['titre'] = 'title', -- French ['trans-script'] = 'transcript', -- misspelling ['trans_chapter'] = 'trans-chapter', -- old parameter alias ['trans_title'] = 'trans-title', -- old parameter alias ['transchapter'] = 'trans-chapter', ['transcripturl'] = 'transcript-url', -- old parameter name ['transscript'] = 'transcript', -- misspelling ['transscript-format'] = 'transcript-format', -- misspelling ['transscript-url'] = 'transcript-url', -- misspelling ['transscripturl'] = 'transcript-url', -- misspelling ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['títle'] = 'title', ['título'] = 'title', -- Spanish ['ubicación'] = 'location', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urlarchivo'] = 'archive-url', -- Spanish ['urlmorto'] = 'url-status', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') ['v-authors'] = 'vauthors', -- misspelling ['v-editors'] = 'veditors', -- misspelling ['verlag'] = 'publisher', -- German ['verlagea'] = 'publisher', -- German (not a direct replacement, but can be emulated) ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['yardımcıyazarlar'] = 'author', -- Turkish ['yayımcı'] = 'publisher', -- Turkish ['yayıncı'] = 'publisher', -- Turkish ['yazar'] = 'author', -- Turkish ['yazarbağı'] = 'author-link', -- Turkish ['yer'] = 'location', -- Turkish ['yıl'] = 'date', -- Turkish ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German ['éditeur'] = 'editor', -- French ['ölüurl'] = 'url-status', -- Turkish ['übersetzer'] = 'translator', -- German (singular and plural) } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not REGEX though they are similar. The escape character is '%', not '\'. For more information about Lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', -- misspelling ['^apellido[s]?(%d+)$'] = 'last$1', -- Spanish, enumerated ['^a[utho]+r$'] = 'author', -- misspelling ['^a[utho]+r(%d+)$'] = 'author$1', -- misspelling, enumerated ['^author link(%d+)$'] = 'author-link$1', -- Polish, enumerated ['^autor[e]?(%d+)$'] = 'author$1', -- Italian/Spanish/German, enumerated ['^authorfirst(%d+)$'] = 'author-first$1', -- old parameter name, enumerated ['^author(%d+)first$'] = 'author-first$1', -- old parameter name, enumerated ['^authorgiven(%d+)$'] = 'author-given$1', -- old parameter name, enumerated ['^author(%d+)given$'] = 'author-given$1', -- old parameter name, enumerated ['^authorlast(%d+)$'] = 'author-last$1', -- old parameter name, enumerated ['^author(%d+)last$'] = 'author-last$1', -- old parameter name, enumerated ['^authormask(%d+)$'] = 'author-mask$1', -- old parameter name, enumerated ['^author(%d+)mask$'] = 'author-mask$1', -- old parameter name, enumerated ['^authorsurname(%d+)$'] = 'author-surname$1', -- old parameter name, enumerated ['^author(%d+)surname$'] = 'author-surname$1', -- old parameter name, enumerated ['^cognome(%d+)$'] = 'last$1', -- Italian, enumerated ['^editorfirst(%d+)$'] = 'editor-first$1', -- old parameter name, enumerated ['^editor(%d+)first$'] = 'editor-first$1', -- old parameter name, enumerated ['^editorgiven(%d+)$'] = 'editor-given$1', -- old parameter name, enumerated ['^editor(%d+)given$'] = 'editor-given$1', -- old parameter name, enumerated ['^editorlast(%d+)$'] = 'editor-last$1', -- old parameter name, enumerated ['^editor(%d+)last$'] = 'editor-last$1', -- old parameter name, enumerated ['^editorlink(%d+)$'] = 'editor-link$1', -- old parameter name, enumerated ['^editor(%d+)link$'] = 'editor-link$1', -- old parameter name, enumerated ['^editormask(%d+)$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editor(%d+)mask$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editorsurname(%d+)$'] = 'editor-surname$1', -- old parameter name, enumerated ['^editor(%d+)surname$'] = 'editor-surname$1', -- old parameter name, enumerated ['^enlaceautore(%d+)$'] = 'author-link$1', -- Spanish, enumerated ['^first (%d+)$'] = 'first$1', -- enumerated ['^last (%d+)$'] = 'last$1', -- enumerated ['^nom[e]?(%d+)$'] = 'last$1', -- Italian/French, enumerated ['^nombre(%d+)$'] = 'first$1', -- Spanish, enumerated ['^primero(%d+)$'] = 'first$1', -- Spanish, enumerated ['^pu[blish]+ers?$'] = 'publisher', -- misspelling ['^subjectlink(%d+)$'] = 'subject-link$1', -- old parameter name, enumerated ['^subject(%d+)link$'] = 'subject-link$1', -- old parameter name, enumerated ['^wkautore(%d+)$'] = 'author-link$1', -- Italian, enumerated } return {suggestions = suggestions, patterns=patterns}; lyv8oknf0erxtppnd4bn5uatviufsor 736812 736740 2026-10-07T15:16:49Z King ChristLike 13051 71 revisions imported from [[:en:Module:Citation/CS1/Suggestions]] 736735 Scribunto text/plain -- Please insert new suggestions in alphabetical order -- The form is ['incorrect'] = 'correct', suggestions = { ['ASIN-TLD'] = 'asin-tld', -- old parameter name ['abruf'] = 'access-date', -- German ['abruf-verborgen'] = 'access-date', -- German ['accessmonth'] = 'access-date', ['accesso'] = 'access-date', -- Italian ['accessyear'] = 'access-date', ['acessodata'] = 'access-date', -- Brazilian Portuguese ['ad'] = 'first', -- Turkish ['address'] = 'location', ['anno'] = 'date', -- Italian ['annoaccesso'] = 'access-date', -- Italian ['annodiaccesso'] = 'access-date', -- Italian ['annooriginale'] = 'orig-date', -- Italian ['année'] = 'date', -- French ['apellido'] = 'last', -- Spanish ['apellidos'] = 'last', -- Spanish ['archiv-datum'] = 'archive-date', -- German ['archiv-url'] = 'archive-url', -- German ['archive date'] = 'archive-date', -- misspelling ['archive url'] = 'archive-url', -- misspelling ['archive-link'] = 'archive-url', -- old parameter name ['archiv-url'] = 'archive-url', -- German ['arkivdatum'] = 'archive-date', -- Swedish, Norwegian ['arkivurl'] = 'archive-url', -- Swedish, Norwegian ['artist'] = 'others', ['arşiv-tarihi'] = 'archive-date', -- Turkish ['arşiv-url'] = 'archive-url', -- Turkish ['arşivtarihi'] = 'archive-date', -- Turkish ['arşivurl'] = 'archive-url', -- Turkish ['auflage'] = 'edition', -- German ['auteur'] = 'author', -- French ['auther'] = 'author', -- misspelling ['author link'] = 'author-link', -- Polish ['authorfirst'] = 'author-first', -- old parameter name ['authorgiven'] = 'author-given', -- old parameter name ['authorlast'] = 'author-last', -- old parameter name ['authormask'] = 'author-mask', -- old parameter name ['authorsurname'] = 'author-surname', -- old parameter name ['autor'] = 'author', -- Spanish, German (singular and plural) ['autore'] = 'author', -- Italian ['autthor'] = 'author', -- misspelling ['ay'] = 'month', -- Turkish ['año'] = 'date', -- Spanish ['año-original'] = 'orig-date', -- Spanish ['añoacceso'] = 'access-date', -- Spanish ['añooriginal'] = 'orig-date', -- Spanish ['band'] = 'volume', -- German ['bandreihe'] = 'volume', -- German ['baskı'] = 'edition', -- Turkish ['başlık'] = 'title', -- Turkish ['began'] = 'date', -- old parameter name (cite serial only); or orig-date= ['booktitle'] = 'book-title', -- old parameter name ['ch'] = 'language', -- German (as 'language=de-CH') ['chapter_title'] = 'chapter', ['chapterurl'] = 'chapter-url', -- old parameter name ['cid'] = 'ref', -- Italian ['cilt'] = 'volume', -- Turkish ['cita'] = 'quote', -- Spanish ['citazione'] = 'quote', -- Italian ['città'] = 'location', -- Italian ['city'] = 'location', -- old parameter name (cite serial only) ['coauthor'] = 'author', ['coauthors'] = 'author', ['coautores'] = 'author', -- Spanish ['coautori'] = 'author', -- Italian ['cognome'] = 'last', -- Italian ['conferenceurl'] = 'conference-url', -- old parameter name ['consulté le'] = 'access-date', -- French ['contributionurl'] = 'contribution-url', -- old parameter name ['curatore'] = 'publisher', -- Italian ['czasopismo'] = 'journal', -- Polish ['data dostępu'] = 'access-date', -- Polish ['data'] = 'date', -- Polish, Italian ['dataaccesso'] = 'access-date', -- Italian ['dataarchivio'] = 'archive-date', -- Italian ['datum'] = 'date', -- German, Swedish ['dead-url'] = 'url-status', -- old parameter name ['deadlink'] = 'url-status', -- old parameter name ['deadurl'] = 'url-status', -- old parameter name ['dergi'] = 'work', -- Turkish ['dil'] = 'language', -- Turkish ['displayauthors'] = 'display-authors', -- old parameter name ['displayeditors'] = 'display-editors', -- old parameter name ['distributor'] = 'publisher', ['dnb'] = 'id', -- German (as 'id={{DNB-IDN|...}}') ['doi-broken'] = 'doi-broken-date', -- old parameter alias ['doi-inactive'] = 'doi-broken-date', -- invalid name found in mainspace ['doi-inactive-date'] = 'doi-broken-date', -- old parameter alias ['doi_brokendate'] = 'doi-broken-date', -- old parameter alias ['doi_inactivedate'] = 'doi-inactive-date', -- old parameter alias ['doibroken'] = 'doi-broken-date', -- invalid name found in mainspace ['doiinactive'] = 'doi-broken-date', -- invalid name found in mainspace ['e-print'] = 'eprint', -- misspelling -- ['ed'] = 'edition', -- avoid suggestion as in English this could be short for editor or edition -- ['editora'] = 'publisher', -- can be either editor or publisher -- ['editore'] = 'agency', -- can be either publisher or agency -- ['editori'] = 'editor', -- can be either editor or publisher -- ['editorial'] = 'publisher', -- can be either publisher or work ['editoin'] = 'edition', -- misspelling ['editon'] = 'edition', -- misspelling ['editorfirst'] = 'editor-first', -- old parameter name ['editorgiven'] = 'editor-given', -- old parameter name ['editorlast'] = 'editor-last', -- old parameter name ['editorlink'] = 'editor-link', -- old parameter name ['editormask'] = 'editor-mask', -- old parameter name ['editors'] = 'editor', -- old parameter name (can be emulated using multiple singular |editor= params) ['editorsurname'] = 'editor-surname', -- old parameter name ['edizione'] = 'edition', -- Italian ['embargo'] = 'pmc-embargo-date', -- old parameter name ['ended'] = 'date', -- old parameter name (cite serial only) ['en ligne le'] = 'archive-date', -- French ['encyclopædia'] = 'encyclopedia', ['enlaceautor'] = 'author-link', -- Spanish ['enlaceroto'] = 'url-status', -- Spanish ['episodelink'] = 'episode-link', -- old parameter name ['erişimtarihi'] = 'access-date', -- Turkish ['eser'] = 'work', -- Turkish ['family'] = 'surname', -- misguess ['fecha'] = 'date', -- Spanish ['fechaacceso'] = 'access-date', -- Spanish ['fechaarchivo'] = 'archive-date', -- Spanish ['filetype'] = 'format', ['foramt'] = 'format', -- misspelling ['fore-name'] = 'given', -- misguess/misspelling ['forename'] = 'given', -- misguess ['författare'] = 'author', -- Swedish, Norwegian ['formato'] = 'format', -- Spanish, Italian, Polish ['frist'] = 'first', -- misspelling ['fundstelle'] = 'at', -- German ['gazete'] = 'work', -- Turkish ['giornale'] = 'journal', -- Italian ['hämtdatum'] = 'access-date', -- Swedish ['herausgeber'] = 'editor', -- German (singular and plural) ['hrsg'] = 'publisher', -- German ['hrsgreihe'] = 'editor', -- German ['idioma'] = 'language', -- Spanish ['ignore-isbn-error'] = 'isbn', -- old parameter (can be fully emulated using ((syntax))) ['ignoreisbnerror'] = 'isbn', -- old parameter alias (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['imię'] = 'first', -- Polish ['in-set'] = 'inset', -- misspelling ['interviewerlink'] = 'interviewer-link', -- old parameter alias ['interviewermask'] = 'interviewer-mask', -- old parameter alias ['isbndefekt'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isbnistformalfalsch'] = 'isbn', -- German (suggest |isbn as |ignore-isbn-error is deprecated), not a direct replacement, but can be fully emulated using ((syntax)) ['isnb'] = 'isbn', -- misspelling ['issnformalfalsch'] = 'issn', -- German (can be fully emulated using ((syntax))) ['jahr'] = 'date', -- German ['jahrea'] = 'orig-date', -- German (not a direct replacement, but can be emulated) ['kapitel'] = 'chapter', -- German ['langauge'] = 'language', -- misspelling ['langue'] = 'language', -- French ['last-author-amp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['lastauthoramp'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['lieu'] = 'location', -- French ['lingua'] = 'language', -- Italian ['lire en ligne'] = 'url', -- French ['lizenznummer'] = 'id', -- German (as 'id=License No. ...') ['loaction'] = 'location', -- misspelling ['local'] = 'location', -- Brazilian Portuguese ['locatoin'] = 'location', -- misspelling ['lugar'] = 'location', -- Spanish ['mailinglist'] = 'mailing-list', -- old parameter name ['mapurl'] = 'map-url', -- old parameter name ['mes'] = 'date', -- Spanish (not a direct replacement) ['mese'] = 'date', -- Italian (not a direct replacement) ['miejsce'] = 'location', -- Polish ['miesiąc'] = 'date', -- Polish ['mois'] = 'date', -- French ['monat'] = 'date', -- German -- ['name'] = 'author', -- 'name' is often erroneously used for 'title' and 'work' as well, so no suggestion is better than a wrong suggestion ['name-list-format'] = 'name-list-style', -- old parameter name (as |name-list-style=amp) ['nazwisko'] = 'last', -- Polish ['nespaper'] = 'newspaper', -- misspelling ['net-work'] = 'network', -- misspelling ['newpaper'] = 'newspaper', -- misspelling ['news'] = 'newspaper', ['news-group'] = 'newsgroup', -- misspelling ['news-paper'] = 'newspaper', -- misspelling ['no-cat'] = 'no-tracking', -- old parameter ['nocat'] = 'no-tracking', -- old parameter ['nom'] = 'last', -- French ['nombre'] = 'first', -- Spanish ['nome'] = 'first', -- Italian ['nopp'] = 'no-pp', -- old parameter name ['notracking'] = 'no-tracking', -- old parameter ['numero'] = 'number', -- Italian, Spanish ['nummer'] = 'number', -- German ['nummerreihe'] = 'number', -- German ['obra'] = 'work', -- Spanish ['odpowiedzialność'] = 'agency', -- Polish ['offline'] = 'url-status', -- German (as 'url-status=dead') ['online'] = 'url', -- German (not a direct replacement, but can be emulated) ['opera'] = 'work', -- Italian ['opublikowany'] = 'agency', -- Polish ['origdate'] = 'orig-date', -- misspelling ['originaljahr'] = 'orig-date', -- German ['originalort'] = 'publication-place', -- German ['originalsprache'] = 'language', -- German ['originaltitel'] = 'title', -- German (if 'originaltitel' is specified, any possible contents of 'title' should be put in 'trans-title') ['ort'] = 'publication-place', -- German ['ortea'] = 'publication-place', -- German (not a direct replacement, but can be emulated) ['other'] = 'others', ['oznaczenie'] = 'agency', -- Polish ['pagees'] = 'pages', -- misspelling ['pagina'] = 'page', -- Italian ['pagina'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['pagine'] = 'pages', -- Italian ['passage'] = 'pages', -- French ['periodico'] = 'magazine', -- Spanish ['plublisher'] = 'publisher', -- misspelling ['pmcid'] = 'pmc', ['post-script'] = 'postscript', -- misspelling ['praca'] = 'work', -- Polish ['primero'] = 'first', -- Spanish ['prénom'] = 'first', -- French ['prénom1'] = 'first1', -- French ['ps'] = 'postscript', ['pub'] = 'publisher', -- ['pubblicazione'] = 'magazine', -- could be any kind of work -- ['publicación'] = 'journal', -- could be any kind of work ['publicationdate'] = 'publication-date', -- old parameter name -- ['published'] = 'publisher', -- could be date, location, or name of publisher ['publicationplace'] = 'publication-place', -- old parameter name ['pulbication-place'] = 'publication-place', -- misspelling ['página'] = 'page', -- Spanish ['páginas'] = 'pages', -- Spanish ['périodique'] = 'publisher', -- French ['registration'] = 'url-access', -- old parameter name ['reihe'] = 'series', -- German ['retrieved'] = 'access-date', -- old parameter name ['richiestasottoscrizione'] = 'url-access', -- Italian (as |url-access=subscription) ['rivista'] = 'magazine', -- Italian ['rok'] = 'date', -- Polish ['rubrik'] = 'title', -- Swedish ['sammelwerk'] = 'work', -- German ['sayfa'] = 'page', -- Turkish ['sayfalar'] = 'pages', -- Turkish ['sayı'] = 'issue', -- Turkish ['script-post'] = 'postscript', -- misspelling ['script-trans'] = 'transcript', -- misspelling ['season'] = 'date', -- old parameter name (cite serial only) ['sectionurl'] = 'section-url', -- old parameter name ['seiten'] = 'pages', -- German ['seria'] = 'series', -- Spanish, Polish ['serie'] = 'series', -- Italian ['série'] = 'series', -- French ['serieslink'] = 'series-link', -- old parameter name ['seriesno'] = 'series-number', -- old parameter name ['service'] = 'agency', ['sitioweb'] = 'website', -- Spanish ['sito'] = 'website', -- Italian ['soyadı'] = 'last', -- Turkish ['spalten'] = 'at', -- German (not a direct replacement, but can be emulated) ['sprache'] = 'language', -- German ['språk'] = 'language', -- Swedish, Norwegian ['stron'] = 'page', -- Polish ['strony'] = 'pages', -- Polish ['subjectlink'] = 'subject-link', -- old parameter name ['subscription'] = 'url-access', -- old parameter name (emulated as |url-access=subscription) ['sur-name'] = 'surname', -- misspelling ['suscripción'] = 'url-access', -- Spanish, Polish (as |url-access=subscription) ['tag'] = 'date', -- German ['tarih'] = 'date', -- Turkish ['template doc demo'] = 'no-tracking', -- old parameter alias ['tidning'] = 'work', -- Swedish ['tile'] = 'title', -- misspelling ['timecaption'] = 'time-caption', -- old parameter name ['titlelink'] = 'title-link', -- old parameter name ['tipo'] = 'type', -- Italian ['tite'] = 'title', -- misspelling ['titel'] = 'title', -- German ['titel-p'] = 'title', -- German ('postscript=none' should be added as well) ['titelerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['titled'] = 'title', -- Brazilian Portuguese ['titolo'] = 'title', -- Italian ['titre'] = 'title', -- French ['trans-script'] = 'transcript', -- misspelling ['trans_chapter'] = 'trans-chapter', -- old parameter alias ['trans_title'] = 'trans-title', -- old parameter alias ['transchapter'] = 'trans-chapter', ['transcripturl'] = 'transcript-url', -- old parameter name ['transscript'] = 'transcript', -- misspelling ['transscript-format'] = 'transcript-format', -- misspelling ['transscript-url'] = 'transcript-url', -- misspelling ['transscripturl'] = 'transcript-url', -- misspelling ['transtitle'] = 'trans-title', ['typ'] = 'author-mask', -- German (not a direct replacement, but the only valid argument 'typ=wl' can be emulated using 'author-mask') ['tytuł'] = 'title', -- Polish ['títle'] = 'title', ['título'] = 'title', -- Spanish ['ubicación'] = 'location', -- Spanish ['urlarchivio'] = 'archive-url', -- Italian ['urlarchivo'] = 'archive-url', -- Spanish ['urlmorto'] = 'url-status', -- Italian ['urn'] = 'id', -- German (as 'id={{URN|...}}') ['v-authors'] = 'vauthors', -- misspelling ['v-editors'] = 'veditors', -- misspelling ['verlag'] = 'publisher', -- German ['verlagea'] = 'publisher', -- German (not a direct replacement, but can be emulated) ['vol'] = 'volume', ['volumen'] = 'volume', -- Spanish ['werk'] = 'work', -- German ['werkerg'] = 'contribution', -- German (not a direct replacement, but can be emulated) ['wkautore'] = 'author-link', -- Italian ['wolumin'] = 'volume', -- Polish ['wydanie'] = 'number', -- Polish ['wydawca'] = 'publisher', -- French ['yardımcıyazarlar'] = 'author', -- Turkish ['yayımcı'] = 'publisher', -- Turkish ['yayıncı'] = 'publisher', -- Turkish ['yazar'] = 'author', -- Turkish ['yazarbağı'] = 'author-link', -- Turkish ['yer'] = 'location', -- Turkish ['yıl'] = 'date', -- Turkish ['zaprezentowany'] = 'publisher', -- French ['zdb'] = 'id', -- German (as 'id={{ZDB|...}}') ['zitat'] = 'quote', -- German ['zugriff'] = 'access-date', -- German ['éditeur'] = 'editor', -- French ['ölüurl'] = 'url-status', -- Turkish ['übersetzer'] = 'translator', -- German (singular and plural) } --[[--------------------------< P A T T E R N S >-------------------------------------------------------------- Here we use Lua patterns to make suggestions. The form is ['pattern'] = 'correct', Lua patterns are not REGEX though they are similar. The escape character is '%', not '\'. For more information about Lua patterns, see: Extension:Scribunto/Lua_reference_manual#Patterns Patterns should probably always include the '^' and '$' anchor assertions to prevent a partial match from incorrectly suggesting the wrong parameter name. For instance, the pattern 'a[utho]+r' matches 'author' in the no-longer-supported parameter |author-separator= so the code suggests '|author='; the same pattern also matches the no-longer-supported parameter |separator= (returning 'ator') so again, the code suggests '|author='. One capture is supported, typically the enumerator from an enumerated parameter (the '6' in |author6=, etc.) The value from the capture replaces $1 in the 'correct' value. ]] local patterns = { ['^ac+es+ ?d?a?t?e?$'] = 'access-date', -- misspelling ['^apellido[s]?(%d+)$'] = 'last$1', -- Spanish, enumerated ['^a[utho]+r$'] = 'author', -- misspelling ['^a[utho]+r(%d+)$'] = 'author$1', -- misspelling, enumerated ['^author link(%d+)$'] = 'author-link$1', -- Polish, enumerated ['^autor[e]?(%d+)$'] = 'author$1', -- Italian/Spanish/German, enumerated ['^authorfirst(%d+)$'] = 'author-first$1', -- old parameter name, enumerated ['^author(%d+)first$'] = 'author-first$1', -- old parameter name, enumerated ['^authorgiven(%d+)$'] = 'author-given$1', -- old parameter name, enumerated ['^author(%d+)given$'] = 'author-given$1', -- old parameter name, enumerated ['^authorlast(%d+)$'] = 'author-last$1', -- old parameter name, enumerated ['^author(%d+)last$'] = 'author-last$1', -- old parameter name, enumerated ['^authormask(%d+)$'] = 'author-mask$1', -- old parameter name, enumerated ['^author(%d+)mask$'] = 'author-mask$1', -- old parameter name, enumerated ['^authorsurname(%d+)$'] = 'author-surname$1', -- old parameter name, enumerated ['^author(%d+)surname$'] = 'author-surname$1', -- old parameter name, enumerated ['^cognome(%d+)$'] = 'last$1', -- Italian, enumerated ['^editorfirst(%d+)$'] = 'editor-first$1', -- old parameter name, enumerated ['^editor(%d+)first$'] = 'editor-first$1', -- old parameter name, enumerated ['^editorgiven(%d+)$'] = 'editor-given$1', -- old parameter name, enumerated ['^editor(%d+)given$'] = 'editor-given$1', -- old parameter name, enumerated ['^editorlast(%d+)$'] = 'editor-last$1', -- old parameter name, enumerated ['^editor(%d+)last$'] = 'editor-last$1', -- old parameter name, enumerated ['^editorlink(%d+)$'] = 'editor-link$1', -- old parameter name, enumerated ['^editor(%d+)link$'] = 'editor-link$1', -- old parameter name, enumerated ['^editormask(%d+)$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editor(%d+)mask$'] = 'editor-mask$1', -- old parameter name, enumerated ['^editorsurname(%d+)$'] = 'editor-surname$1', -- old parameter name, enumerated ['^editor(%d+)surname$'] = 'editor-surname$1', -- old parameter name, enumerated ['^enlaceautore(%d+)$'] = 'author-link$1', -- Spanish, enumerated ['^first (%d+)$'] = 'first$1', -- enumerated ['^last (%d+)$'] = 'last$1', -- enumerated ['^nom[e]?(%d+)$'] = 'last$1', -- Italian/French, enumerated ['^nombre(%d+)$'] = 'first$1', -- Spanish, enumerated ['^primero(%d+)$'] = 'first$1', -- Spanish, enumerated ['^pu[blish]+ers?$'] = 'publisher', -- misspelling ['^subjectlink(%d+)$'] = 'subject-link$1', -- old parameter name, enumerated ['^subject(%d+)link$'] = 'subject-link$1', -- old parameter name, enumerated ['^wkautore(%d+)$'] = 'author-link$1', -- Italian, enumerated } return {suggestions = suggestions, patterns=patterns}; 2ijnwqp0v6qxv0w5m0mwrt72z46ubhu Module:Citation/CS1/Suggestions/doc 828 81184 736737 2026-09-29T00:56:01Z Northern Moonlight 37961 736737 wikitext text/x-wiki {{#lst:Module:Citation/CS1/doc|header}} This is a list of suggested alternatives to use when an unknown parameter is encountered by a citation template. When an unknown parameter is found within a citation template an error message is generated, and when possible the software makes a suggestion for what the user may have meant by consulting this list of common mistakes and typos. Each entry takes the form: {{code|1=['bad input parameter'] = 'suggested parameter to use'}} The bad input parameter will have been transformed to lower case before checking this list, so all input forms on this list should be written in lowercase. {{#lst:Module:Citation/CS1/doc|module_components_table}} <noinclude> [[Category:Module documentation pages]] </noinclude> kiim19nqvm4f8dqucbu9x1346q7j1zu 736738 736737 2026-10-07T15:16:04Z King ChristLike 13051 1 revision imported from [[:en:Module:Citation/CS1/Suggestions/doc]] 736737 wikitext text/x-wiki {{#lst:Module:Citation/CS1/doc|header}} This is a list of suggested alternatives to use when an unknown parameter is encountered by a citation template. When an unknown parameter is found within a citation template an error message is generated, and when possible the software makes a suggestion for what the user may have meant by consulting this list of common mistakes and typos. Each entry takes the form: {{code|1=['bad input parameter'] = 'suggested parameter to use'}} The bad input parameter will have been transformed to lower case before checking this list, so all input forms on this list should be written in lowercase. {{#lst:Module:Citation/CS1/doc|module_components_table}} <noinclude> [[Category:Module documentation pages]] </noinclude> kiim19nqvm4f8dqucbu9x1346q7j1zu Ojiarụ:Telovemi97 2 81185 736831 2026-10-08T01:18:06Z Telovemi97 61737 stuff 736831 wikitext text/x-wiki Ekele na nsajụta I am still learning igbo, so give me grace pls border-c = #fff | id = [[File:Fremantle Football Club colours.jpg|45px]] | id-c = #2E1654 | id-fc = #2E1654 | id-s = 10 | info = This user is a supporter of the <br>'''[[Fremantle Football Club|<span style="color: #fff">Fremantle Football Club</span>]]'''<br/>''Freeeeo, way to go!'' | info-c = #2E1654 | info-fc = {{{info-color|#fff}}} 2rw9272o8rnu9q7cftypcthgzcbzar2 Nawal El Saadawi 0 81186 736853 2026-10-08T09:10:17Z Adimora chidinma 15845 Ekere na itugharị ihụakwụkwọ nke a "[[:en:Special:Redirect/revision/1373499281|Nawal El Saadawi]]" 736853 wikitext text/x-wiki   '''Nawal El Saadawi''' (Arabic: نوال السعداوي, ALA-LC: Nawāl as-Saʿdāwī; 27 Ọktoba 1931 – 21 Maachị 2021) bụ onye edemede nwanyị na Ijipt, onye na-akwado ikike mmadụ, dọkịta, na onye na-agwọ ọrịa uche. O dere ọtụtụ akwụkwọ gbasara ụmụ nwanyị na Islam, na-elekwasị anya n'okwu ndị metụtara ụmụ nwanyị na ndịda ụwa, gụnyere mmekọahụ, nna ochie, ọkwa mmekọrịta mmadụ na ibe ya, na ọchịchị onye kwuo uche ya. Ọ bụ onye guzobere na onye isi oche nke Arab Women's Solidarity Association . Ọ bụkwa onye guzobere Arab Association for Human Rights . Ọ natara nzere nsọpụrụ site na mahadum dị na kọntinent atọ. N'afọ 2004, Council of Europe nyere ya onyinye North-South. N'afọ 2005, ọ natara Inana International Prize na [[Belgium]]. N'afọ 2012, ụlọ ọrụ International Peace Bureau nyere ya Seán MacBride Peace Prize. == Oge ọ malitere == Nwa nke abụọ n'ime ụmụ itoolu, a mụrụ Saadawi na 27 Ọktoba 1931 na obere obodo Kafr Tahla, Egypt. A na-ebipụ Saadawi akụkụ ahụ nwanyị mgbe ọ dị afọ isii, ọ bụ ezie na nna ya kwenyere na ụmụ nwanyị na ụmụ nwoke kwesịrị ịgụ akwụkwọ. Ọ kọwara nne ya na nna ya dị ka ndị nwere nnwere onwe mgbe ha na-etolite.<ref name=":1" /> Nna ya nke dị elu n'Ijipt bụ onye ọrụ gọọmentị na Ministry of Education, onye lụsoro ndị Britain agha megide ndị Britain weghaara Ijipt n'oge mgbanwe Ijipt nke afọ 1919. N'ihi ya, a chụpụrụ ya n'obodo nta dị na Nile Delta, gọọmentị ekweghịkwa ịkwalite ya ruo afọ 10. Ọ bụ onye na-aga n'ihu ma kụziere nwa ya nwanyị ịkwanyere onwe ya ùgwù na ikwu okwu n'uche ya. Ọ gbakwara ya ume ka ọ mụọ asụsụ Arabik. Agbanyeghị, mgbe El Saadawi dị afọ 10, ezinụlọ ya gbalịrị ime ka ọ lụọ di, mana nne ya kwadoro ya n'ịjụ.[1] Ndị mụrụ ya abụọ nwụrụ mgbe ọ dị obere,[2] hapụrụ Saadawi naanị ibu ọrụ nke ilekọta ezinụlọ buru ibu.[3] Nne ya, Zaynab, sitere n'agbụrụ Ottoman bara ọgaranya;[4] Saadawi kọwara ma nna nna ya, Shoukry,[5] na nne nne ya dịka ndị Ottoman si malite.[6]  Ọbụna mgbe ọ bụ nwata, ọ katọrọ obodo ndị nwoke bi na ya, ebe ụmụ nwoke ji ha kpọrọ ihe karịa ụmụ nwanyị, na-emeghachi omume n'iwe nye nne nne ya bụ́ onye kwuru na "nwoke bara uru ụmụ agbọghọ iri na ise ma ọ dịkarịa ala... Ụmụ agbọghọ bụ nsogbu".[1] O ji nganga kọwaa onwe ya dị ka nwanyị Ijipt gbara ọchịchịrị kemgbe ọ dị obere.[7][8].<ref>{{Citation |last=El Saadawi |first=Nawal |title=My Childhood in Egypt, Not Knowing I Was in Africa |date=13 June 2019 |work=zora.medium.com |url=https://zora.medium.com/my-childhood-in-egypt-not-knowing-i-was-in-africa-27580b07a93b}}</ref> == Ọrụ == Saadawi gụsịrị akwụkwọ dị ka dọkịta na 1955 na Mahadum Cairo. N'afọ ahụ, ọ lụrụ Ahmed Helmi, onye ọ zutere dị ka nwa akwụkwọ ibe ya na ụlọ akwụkwọ ahụike. Ha nwere nwa nwanyị, Mona Helmi.<ref name="Khaleeli" /> Alụmdi na nwunye ahụ kwụsịrị mgbe afọ abụọ gasịrị. Site n'ọrụ ahụike ya, ọ hụrụ nsogbu anụ ahụ na nke uche ụmụ nwanyị ma jikọta ha na omume mmegbu, mmegbu nna ochie, mmegbu klas na mmegbu nke alaeze ukwu. Di ya nke abụọ bụ onye ọrụ ibe ya, Rashad Bey . <ref name="JoISR" /> Mgbe ọ na-arụ ọrụ dị ka dọkịta n'ebe a mụrụ ya na Kafr Tahla, ọ hụrụ ihe isi ike na enweghị nhata nke ụmụ nwanyị ime obodo na-eche ihu. Mgbe ọ nwara ichebe otu n'ime ndị ọrịa ya pụọ na Ime ihe ike n'ụlọ, a kpọrọ Saadawi ka ọ laghachi Cairo. O mechara bụrụ onye nduzi nke Ministry of Public Health ma zute di ya nke atọ, Sherif Hatata, mgbe ọ na-arụkọ ọrụ na Ministry of Health. Hatata, onye bụkwa dọkịta na onye edemede, bụ Onye mkpọrọ ndọrọ ndọrọ ọchịchị ruo afọ 13. Ha lụrụ na 1964 ma nwee nwa nwoke. Saadawi na Hatata biri ọnụ ruo afọ 43 ma gbaa alụkwaghịm na 2010. [[File:Shirin_Ershadi,_Shirin_Ebadi_and_Nawal_el-Saadawi_(2413951897).jpg|thumb|[[Shirin Ershadi]], Shirin Ebadi na Nawal el-Saadawi]] Saadawi gara Mahadum Columbia, nweta nzere masta na ahụike ọha na eze na 1966. N'afọ 1972, o bipụtara Woman and Sex ({{Lang|ar|المرأة والجنس}}), na-eche ihu ma na-akọwa ihe omume dị iche iche a na-eme megide ahụ ụmụ nwanyị, gụnyere ibi úgwù ụmụ nwanyị. Akwụkwọ ahụ ghọrọ ederede ntọala nke ụmụ nwanyị nke abụọ. N'ihi akwụkwọ ahụ na ọrụ ndọrọ ndọrọ ọchịchị ya, a chụpụrụ Saadawi n'ọkwa ya na Ministri ahụike. Ọ tụfuru ọkwa ya dị ka onye isi nchịkọta akụkọ nke akwụkwọ akụkọ ahụike, na dị ka onye enyemaka odeakwụkwọ ukwu na Medical Association na Egypt. Site na 1973 ruo 1976, Saadawi rụrụ ọrụ na nyocha ụmụ nwanyị na neurosis na Faculty of Medicine nke Mahadum Ain Shams. Site na 1979 ruo 1980, ọ bụ onye ndụmọdụ United Nations maka mmemme ụmụ nwanyị na Africa (ECA) na Middle East (ECWA). === Ikpe ụlọ ikpe megide ya === N'afọ 2002, Nabih el-Wahsh mere mgbalị iwu n'ụlọ ikpe Ijipt iji gbaa el-Saadawi alụkwaghịm n'ụzọ iwu kwadoro n'ihi hesba, ụkpụrụ nke narị afọ nke itoolu nke iwu Sharia, nke na-enye ohere maka ikpe ndị Alakụba a na-ahụ na ha na-emerụ Islam. Ihe akaebe e ji megide ya bụ ajụjụ ọnụ March nke el-Wahsh kwuru na ọ bụ ihe akaebe na ọ hapụrụ Islam. Mgbalị iwu ahụ enweghị isi. N'afọ 2008, e mere mgbalị yiri nke ahụ iji wepụ el-Saadawi nwa amaala Ijipt ya n'ihi echiche ya na edemede ya, mgbalị a enweghịkwa ihe ịga nke ọma. === Mkpọrọ Mkpọrọ === Ọ dịla anya gọọmentị Ijipt lere ya anya dị ka ihe na-ese okwu na ihe dị ize ndụ, Saadawi nyere aka bipụta magazin ụmụ nwanyị na 1981 nke a na-akpọ Confrontation. Onye isi ala Ijipt Anwar Sadat tụrụ ya mkpọrọ na Septemba. Saadawi kwuru otu ugboro n'ajụjụ ọnụ: "E jidere m n'ihi na ekwere m Sadat. O kwuru na enwere ọchịchị onye kwuo uche ya na anyị nwere usoro ọtụtụ pati ma ị nwere ike ịkatọ. Ya mere, amalitere m ịkatọ iwu ya wee banye n'ụlọ mkpọrọ. "Sadat kwuru na gọọmentị e guzobere bụ ọchịchị onye kwuo uche ya maka ndị mmadụ nakwa na ọchịchị onye kwuo ike dị ka ọ dị mgbe niile bụ maka nkatọ na-ewuli elu. Dị ka Saadawi si kwuo, Sadat tụrụ ya mkpọrọ n'ihi nkatọ ọ na-akatọ ọchịchị onye kwuo uche ya. Ọbụna n'ụlọ mkpọrọ, ọ ka chọtara ụzọ iji lụso mmegbu ụmụ nwanyị ọgụ. Mgbe ọ nọ n'ụlọ mkpọrọ, o guzobere Arab Women's Solidarity Association. Nke a bụ òtù ụmụ nwanyị mbụ iwu kwadoro na nke nwere onwe ya n'Ijipt. N'ụlọ mkpọrọ, a jụrụ ya mkpịsị akwụkwọ na akwụkwọ, Otú ọ dị, nke ahụ egbochighị ya ịga n'ihu na-ede akwụkwọ. O jiri "ihe odide anya ojii" na "obere mpịakọta mpịakwasị ochie" dekọọ echiche ya. A tọhapụrụ ya n'ikpeazụ n'afọ ahụ, otu ọnwa mgbe e gbusịrị onye isi ala. Banyere ahụmịhe ya, o dere, sị: "Ihe ize ndụ abụwo akụkụ nke ndụ m kemgbe m nwetara mkpịsị akwụkwọ wee dee. Ọ dịghị ihe dị ize ndụ karịa eziokwu n'ụwa na-agha ụgha. " N'afọ 1982, o guzobere Arab Women's Solidarity Association . Ọ kọwara nzukọ ya dị ka "akụkọ ihe mere eme, nke ndọrọ ndọrọ ọchịchị, na nke ụmụ nwanyị". Saadawi bụ otu n'ime ụmụ nwanyị ndị e jidere n'ụlọ mkpọrọ ụmụ nwanyị Qanatir. Memoirs from the Women's Prison (Arabic) nke afọ 1983 bụ ihe ndabere maka Memoirs si n'ụlọ mkpọrọ ụmụ nwanyị. Mmekọrịta ya na onye mkpọrọ nọ na Qanatir, afọ itoolu tupu a tụọ ya mkpọrọ n'ebe ahụ, bụ ihe mkpali maka ọrụ mbụ, akwụkwọ akụkọ akpọrọ Woman at Point Zero (Arabic), '''Egwuregwu''' * ''Ụmụ nwanyị na Mmekọahụ'' (Cairo, 1969) * ''Nwaanyị bụ Mmalite'' (Cairo, 1971) * ''Ụmụ nwoke na Mmekọahụ'' (Cairo, 1973) * Ihu gba ọtọ nke ụmụ nwanyị Arab (Cairo, 1974) * Ụmụ nwanyị na Ọrịa Ọrịa Ọkụ (Cairo, 1975) * ''Al-Wajh al-'ari lil-mar'a al-'arabiyy'' (1977). Ihu zoro ezo nke Iv: Ụmụ nwanyị n'ụwa ndị Arab, trans. Sherif Hetata (Zed Press, 1980) * On Women (Cairo, 1986) * ''Agha Ọhụrụ Na Nnwere Onwe Ụmụ nwanyị Arab'' (Cairo, 1992) * ''Nchịkọta nke edemede'' (Cairo, 1998) * ''Nchịkọta nke edemede'' (Cairo, 2001) * Ịkwụsị Ihe mgbochi (Cairo, 2004) '''Nchịkọta n'asụsụ Bekee''' == Hụkwa ==   *   *   *   * Thesis/dissertation.  <templatestyles src="Module:Side box/styles.css"></templatestyles> * Ebe nrụọrụ weebụ Nawal El Saadawi na archive.org * Adele Newson-Horst, "[https://www.worldliteraturetoday.org/blog/literary-tributes/remembering-nawal-el-saadawi-adele-newson-horst "Ịcheta Nawal El Saadawi"]", World Literature Today, 24 March 2021. * [[Ernest Emenyonu]], "NAWAL EL SAADAWI: Ndụ na edemede (Ọktoba 27, 1931 - Machị 21, 2021) ", Boydell na Brewer, 13 Mee 2021. [[Otú:Articles with hCards]] [[Otú:Pages with unreviewed translations]] 3992icj5o80olxqydosc3vnti3kca7p