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; Dre egwu akpọrọ " Kwuo m " na ndị na-emepụta Cool &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; 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;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;B Album
|''Heaux Tales''
| {{Nom}}
|-
|Favorite Soul/R&amp;B Song
|"Pick Up Your Feelings"
| {{Nom}}
|-
! rowspan="6" scope="row" |BET Awards
| rowspan="3" |2009
|Best Female R&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;B Vocal Performance
|"Need U Bad"
| {{Nom}}
|-
|Best Traditional R&amp;B Performance
|"In Love With Another Man"
| {{Nom}}
|-
|Best R&amp;B Song
|"Bust Your Windows"
| {{Nom}}
|-
|Best Contemporary R&amp;B Album
|''Fearless''
| {{Nom}}
|-
| rowspan="2" |2010
|Best Female R&B Vocal Performance
| rowspan="2" |"Lions, Tigers &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;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;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;B Song
| {{Nom}}
|-
|Best R&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;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;B nke 2008
* Ndepụta nke R&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]|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 | 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>[[[Special:Edit/%s|e]]]</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]', {
['['] = '[',
[']'] = ']',
['\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 .. ' ', '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("—", 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 (' ',''); -- count nbsps
-- There is exactly 1 semicolon per 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#') or url:match ('%.pdf#');
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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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]', {
['['] = '[',
[']'] = ']',
['\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 .. ' ', '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("—", 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 (' ',''); -- count nbsps
-- There is exactly 1 semicolon per 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#') or url:match ('%.pdf#');
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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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]', {
['['] = '[',
[']'] = ']',
['\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 .. ' ', '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("—", 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 (' ',''); -- count nbsps
-- There is exactly 1 semicolon per 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#') or url:match ('%.pdf#');
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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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]', {
['['] = '[',
[']'] = ']',
['\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 .. ' ', '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("—", 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 (' ',''); -- count nbsps
-- There is exactly 1 semicolon per 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#') or url:match ('%.pdf#');
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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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]', {
['['] = '[',
[']'] = ']',
['\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 .. ' ', '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("—", 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 (' ',''); -- count nbsps
-- There is exactly 1 semicolon per 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#') or url:match ('%.pdf#');
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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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]', {
['['] = '[',
[']'] = ']',
['\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 .. ' ', '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("—", 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 (' ',''); -- count nbsps
-- There is exactly 1 semicolon per 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#') or url:match ('%.pdf#');
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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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]', {
['['] = '[',
[']'] = ']',
['\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 .. ' ', '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("—", 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 (' ',''); -- count nbsps
-- There is exactly 1 semicolon per 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#') or url:match ('%.pdf#');
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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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]', {
['['] = '[',
[']'] = ']',
['\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 .. ' ', '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("—", 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 (' ',''); -- count nbsps
-- There is exactly 1 semicolon per 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#') or url:match ('%.pdf#');
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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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]', {
['['] = '[',
[']'] = ']',
['\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 .. ' ', '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("—", 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 (' ',''); -- count nbsps
-- There is exactly 1 semicolon per 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#') or url:match ('%.pdf#');
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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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]', {
['['] = '[',
[']'] = ']',
['\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 .. ' ', '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("—", 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 (' ',''); -- count nbsps
-- There is exactly 1 semicolon per 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#') or url:match ('%.pdf#');
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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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]', {
['['] = '[',
[']'] = ']',
['\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 .. ' ', '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("—", 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 (' ',''); -- count nbsps
-- There is exactly 1 semicolon per 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#') or url:match ('%.pdf#');
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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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 .. ' ', '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 - 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"] [Biographical chronology] (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" [Interview/Jose Luis Cuevas/The navel of Cuevas]. ''Reforma'' (in Spanish). Mexico City. p. 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;">[''[[wikipedia:Tinye edensibịa|<span title="This claim needs references to reliable sources. (May 2013)">citation needed</span>]]'']</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;">[''[[wikipedia:Tinye edensibịa|<span title="This claim needs references to reliable sources. (May 2013)">citation needed</span>]]'']</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" [Jose Luis Cuevas: In the cave of Cuevas]. ''Reforma'' (in Spanish). Mexico City. p. 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
| 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)
|-
| 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;">[''[[wikipedia:Tinye edensibịa|<span title="This claim needs references to reliable sources. (July 2019)">citation needed</span>]]'']</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' | 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 | 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 | 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 | 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' | 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 | 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 | 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 | 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 | 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. <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;">[ ''[[wikipedia:Tinye edensibịa|<span title="This claim needs references to reliable sources. (February 2023)">a chọrọ nkọwa</span>]]'' ]</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]] [[Ọ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. 26. [[ISBN]] [[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. <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 : 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 - народилася Людмила Старицька-Черняхівська, письменниця, театрознавиця"] [1868 - Lyudmila Starytska-Chernyakhivska, writer, theater critic, was born]. ''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. Постаті"] [January-February 2025. Figures] <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 – народилася Оксана Стешенко (Старицька)"] [1875 – Oksana Steshenko (Starytska) was born]. ''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. 35. Jersey City, New Jersey. 28 August 1994. p. 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 "Черняхівська Вероніка Олександрівна"] [Cherniakhivska Veronika Oleksandrivna]. ''[[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;">[''[[wikipedia:Tinye edensibịa|<span title="This claim needs references to reliable sources. (September 2017)">citation needed</span>]]'']</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>
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; 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;">[''[[wikipedia:Tinye edensibịa|<span title="This claim needs references to reliable sources. (April 2022)">citation needed</span>]]'']</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 – 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 ed.). New York and London: Garland Science. [[ISBN]] [[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]] <span class="id-lock-free" title="Freely accessible">[https://www.ncbi.nlm.nih.gov/pmc/articles/PMC88952 88952]</span>. [[PMID (identifier)|PMID]] [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;">[''[[wikipedia:Tinye edensibịa|<span title="This claim needs references to reliable sources. (April 2022)">citation needed</span>]]'']</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).&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><skeptical air quotes></code>documentation<code></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]] 🌹 ([[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]] 🌹 ([[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}}.  <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.  <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]] 🌹 ([[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.  <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.  <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.  <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".  <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 ...))}}  <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]  <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*.  <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.  <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>]] [ [[User talk:ChompyTheGogoat|<span style="color:#D72D85">Bleat</span>]] | [[Special:Contributions/ChompyTheGogoat|<span style="color: #2da86c;">Munched</span>]] ]</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.  <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><skeptical air quotes></code>documentation<code></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]] 🌹 ([[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]] 🌹 ([[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}}.  <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.  <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]] 🌹 ([[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.  <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.  <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.  <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".  <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 ...))}}  <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]  <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*.  <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.  <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>]] [ [[User talk:ChompyTheGogoat|<span style="color:#D72D85">Bleat</span>]] | [[Special:Contributions/ChompyTheGogoat|<span style="color: #2da86c;">Munched</span>]] ]</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.  <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 ...')
['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 ...')
['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