Modul:Citation
Die Dokumentation für dieses Modul kann unter Modul:Citation/doc erstellt werden
-- documentation
local scrollGallery = {
suite = 'Citation',
serial = '2020-03-22',
}
-- module import
local cx = require( 'Module:Check isxn' )
local li = require( 'Module:LinkISBN' )
local uc = require( 'Module:UrlCheck' )
local yn = require( 'Module:Yesno' )
-- module variable
local ci = {}
local types = {
book = { 'book', 'Buch' },
map = { 'map', 'Karte' },
collection = { 'collection', 'Sammelwerk' },
journal = { 'journal', 'Zeitschrift' },
newspaper = { 'newspaper', 'Zeitung' }
}
local params = {
type = { 'type', 'Typ' },
author = { 'Autor', COinS = 'rft.au' },
editor = { 'Herausgeber', 'Hrsg' },
title = { 'Titel', COinS = 'rft.title' },
chapter = { 'Kapitel', types = 'book', COinS = 'rft.atitle' },
collection = { 'Sammelwerk', types = 'collection' },
journal = { 'Zeitschrift', 'Sammelwerk', types = 'journal', COinS = 'rft.jtitle' },
newspaper = { 'Zeitung', 'Sammelwerk', types = 'newspaper', COinS = 'rft.jtitle' },
abbr = { 'Abk', types = { 'collection', 'journal', 'newspaper' } },
url = { 'Online', 'URL' },
articleUrl = { 'Onlineaufsatz', types = { 'collection', 'journal', 'newspaper' } },
jstor = { 'JSTOR', types = { 'journal', 'newspaper' } },
kBytes = { 'kBytes' },
accessDate = { 'Zugriff' },
scale = { 'Maßstab', types = 'map' },
place = { 'Ort', COinS = 'rft.place' },
publisher = { 'Verlag', types = { 'book', 'map', 'collection' }, COinS = 'rft.pub' },
date = { 'Datum', 'Jahr', COinS = 'rft.date' },
edition = { 'Auflage', types = { 'book', 'map', 'collection' }, COinS = 'rft.edition' },
volume = { 'Band', COinS = 'rft.volume' },
issue = { 'Ausgabe', 'Nummer', types = { 'journal', 'newspaper' }, COinS = 'rft.issue' },
pages = { 'Seite', 'Seiten', types = { 'book', 'collection', 'journal', 'newspaper' }, COinS = 'rft.pages' },
columns = { 'Spalten', types = { 'book', 'collection', 'journal', 'newspaper' }, COinS = 'rft.pages' },
extent = { 'Umfang', 'Seitenanzahl', types = { 'book', 'collection', 'map' } },
series = { 'Serie', 'Reihe', types = { 'book', 'collection', 'map' }, COinS = 'rft.series' },
series2 = { 'Serie2', 'Reihe2', types = { 'book', 'collection', 'map' } },
series3 = { 'Serie3', 'Reihe3', types = { 'book', 'collection', 'map' } },
isbn = { 'ISBN', types = { 'book', 'collection', 'map', 'journal' }, COinS = 'rft.isbn' },
dnb = { 'DNB', types = { 'book', 'collection', 'map' } },
oclc = { 'OCLC', types = { 'book', 'collection', 'map' }, COinS_id = 'info:oclcnum' },
issn = { 'ISSN', COinS = 'rft.issn' },
doi = { 'DOI', COinS_id = 'info:doi' },
language = { 'Sprache' },
comment = { 'Kommentar' },
noError = { 'noError', 'noerror', 'keinFefler', 'kein Fehler' }
}
local formatters = {
auAuthor = '%s: ',
auEditor = '%s (Hrsg.)',
auAuthorEditor = '%s ; %s',
tiAll = "%s. ",
tiTitle = "''%s''",
tiVolume = "''%s''; Bd. %s",
tiScale = 'Maßstab: %s. ',
tiIn = 'In: ',
puAll = '%s.',
puPlaceDate = '%s, %s',
puPlacePub = '%s: %s',
puDateEdition = '%s (%d. Auflage)',
addSeries = '(%s)',
addPages = 'S. %s',
addColumns = 'Sp. %s',
addDelimiter1 = ', ',
addDelimiter2 = '; ',
addDoi = '[[w:Digital Object Identifier|doi]]:%s',
addLanguage = ' (%s)',
addComment = ' %s',
prPlace = ' <%s>',
prAbbr = ' (%s)',
prVolume = 'Bd. %s',
prIssue = 'Nr. %s',
prVolIssue = '%s,%s',
prVolYear = '%s (%s)',
nsVolume = 'Jg. %s',
nsNrOfDay = '%s vom %s',
dbDnb = '[[w:Deutsche Nationalbibliothek|DNB]] [http://d-nb.info/%s %s]',
dbOclc = '[[w:Online Computer Library Center|OCLC]] [https://worldcat.org/oclc/%s %s]',
dbIssn = '[[w:Internationale Standardnummer für fortlaufende Sammelwerke|ISSN]] [http://zdb-katalog.de/list.xhtml?t=iss%3D%22xx1xx%22&key=cql xx1xx]',
dbJstor = '[[w:JSTOR|JSTOR]] [https://www.jstor.org/stable/%s %s]',
}
local texts = {
noTitel = '<span class="error">Fehlender Titel</span>',
noURL = '<span class="error">Fehlerhafte URL</span>[[Category:Literatur: fehlerhafte URL]]',
unknownParam = '<span class="error">Fehlerhafter Parameter: %s</span>[[Category:Literatur: fehlerhafte Parameter]]',
unknownParams = '<span class="error">Fehlerhafte Parameter: %s</span>[[Category:Literatur: fehlerhafte Parameter]]',
unknownTitle = '[[Category:Literatur: fehlender Titel]]',
unknownPeriodical = '[[Category:Literatur: fehlender Titel eines Periodikums]]',
wrongDate = '<span class="error">Ungültiges Datum</span>[[Category:Literatur: ungültiges Datum]]',
wrongIssn = '<span class="error">Ungültige ISSN</span>[[Category:Seiten mit ISSN-Fehlern]]',
wrongType = '<span class="error">Fehlerhafter Typ</span>[[Category:Literatur: fehlerhafter Typ]]'
}
local errorMsgs = {}
-- check if table contains the value
local function inArray( tab, val )
if type( tab ) == 'string' then
return tab == val
end
local index, value
for index, value in ipairs( tab ) do
if value == val then
return true
end
end
return false
end
-- returns a single value from frame argument table
local function getArgValue( param, args )
value = '', k, v
if params[ param ] then
for k, v in ipairs( params[ param ] ) do
if args[ v ] and args[ v ] ~= '' then
value = args[ v ]
break
end
end
end
return value
end
local function cleanupParameters( value )
if not value or value == '' then
return value
end
value = value:gsub( '[\009\010\013]', ' ' ) -- horizontal tab, line feed, carriage return
value = value:gsub( '[%z%c]', '' ) -- control characters
value = value:gsub( ' ', ' ' );
value = value:gsub( '\226\128\138', ' ' ); -- hair space
value = mw.ustring.gsub( value, '[\226\128\141\226\128\139\194\173]', '' ); -- zero-width joiner, zero-width space, soft hyphen
value = mw.ustring.gsub( value, '%.%.%.', '…' )
value = mw.ustring.gsub( value, '%.%.', '‥' )
value = mw.ustring.gsub( value, '<br%s*/*>', '' )
value = mw.ustring.gsub( value, '</*p%s*/*>', '' )
return mw.ustring.gsub( value, '</*span%s*/*>', '' )
end
-- check for possible arguments against params table
local function checkParams( frameArgs )
local args = {}, key, key2, ok, value, value2
local complete = {}
local wrongParams = {}
local aType = getArgValue( 'type', frameArgs )
-- convert type values if translated
for key, value in pairs( types ) do
if inArray( value, aType ) then
aType = key
break
end
end
for key, value in pairs( params ) do
if not value.types or inArray( value.types, aType ) then
for key2, value2 in ipairs( value ) do
complete[ value2 ] = key
args[ key ] = args[ key ] or
cleanupParameters( frameArgs[ value2 ] )
end
args[ key ] = args[ key ] or ''
end
end
for key, value in pairs( frameArgs ) do
if not complete[ key ] then
table.insert( wrongParams, key )
end
end
if #wrongParams == 1 then
table.insert( errorMsgs,
mw.ustring.format( texts.unknownParam, table.concat( wrongParams, ', ' ) ) )
elseif #wrongParams > 0 then
table.insert( errorMsgs,
mw.ustring.format( texts.unknownParams, table.concat( wrongParams, ', ' ) ) )
end
return args
end
local function makeAuthor( author, editor )
if editor ~= '' then
editor = mw.ustring.format( formatters.auEditor, editor )
end
if author ~= '' and editor ~= '' then
author = mw.ustring.format( formatters.auAuthorEditor, author, editor )
elseif author == '' and editor ~= '' then
author = editor
end
if author ~= '' then
return mw.ustring.format( formatters.auAuthor, author )
else
return ''
end
end
local function makeTitle( title, volume, url, scale )
if not title or title == '' then
title = texts.noTitle
table.insert( errorMsgs, texts.unknownTitle )
end
if url and url ~= '' then
if uc.isUrl( url ) > 2 then
table.insert( errorMsgs, texts.noURL )
else
title = '[' .. url .. ' ' .. title .. ']'
end
end
if volume and volume ~= '' then
title = mw.ustring.format( formatters.tiVolume, title, volume )
else
title = mw.ustring.format( formatters.tiTitle, title )
end
title = mw.ustring.format( formatters.tiAll, title )
if scale and scale ~= '' then
title = title .. mw.ustring.format( formatters.tiScale, scale )
end
return title
end
local function makeDoiLink( doi )
doi = mw.ustring.gsub( doi, 'https?://doi.org/', '' )
return '[' .. mw.uri.encode( 'https://doi.org/' .. doi )
.. '<nowiki>' .. doi .. '</nowiki>]'
end
local function makeIssnLink( issn )
return formatters.dbIssn:gsub( 'xx1xx', issn )
.. cx.check_issn( { args = { [ 1 ] = issn, error = texts.wrongIssn } } )
end
local function getNoError( noEerror )
noError = yn( noError, false )
if noError then
return 'true'
else
return 'false'
end
end
local function makePublished( args )
args.edition = args.edition:match( '%d+' ) or ''
if args.edition == '1' then
args.edition = ''
end
if args.dnb ~= '' and not tonumber( args.dnb ) then
args.dnb = ''
end
if args.oclc ~= '' and not tonumber( args.oclc ) then
args.oclc = ''
end
args.noError = getNoError( args.noError )
local theDate = args.date
local published = ''
if theDate ~= '' and args.edition ~= '' then
theDate = mw.ustring.format( formatters.puDateEdition, args.date, args.edition )
end
if args.place ~= '' and args.publisher ~= '' then
published = mw.ustring.format( formatters.puPlacePub, args.place, args.publisher )
elseif args.place ~= '' then
published = args.place
elseif args.publisher ~= '' then
published = args.publisher
end
if published == '' then
published = theDate
elseif theDate ~= '' then
published = mw.ustring.format( formatters.puPlaceDate, published, theDate )
end
local additions = { published }
if args.series ~= '' then
table.insert( additions, mw.ustring.format( formatters.addSeries, args.series ) )
end
if args.series2 ~= '' then
table.insert( additions, mw.ustring.format( formatters.addSeries, args.series2 ) )
end
if args.series3 ~= '' then
table.insert( additions, mw.ustring.format( formatters.addSeries, args.series3 ) )
end
if args.isbn ~= '' then
table.insert( additions,
li._linkISBNSet( { isbn = args.isbn, noerror = args.noError } ) )
elseif args.dnb ~= '' then
table.insert( additions, mw.ustring.format( formatters.dbDnb, args.dnb, args.dnb ) )
elseif args.oclc ~= '' then
table.insert( additions, mw.ustring.format( formatters.dbOclc, args.oclc, args.oclc ) )
end
if args.issn ~= '' then
table.insert( additions, makeIssnLink( args.issn ) )
end
if args.pages ~= '' then
table.insert( additions,
mw.ustring.format( formatters.addPages, args.pages:gsub( '-', '–' ) ) )
end
if args.columns ~= '' then
table.insert( additions,
mw.ustring.format( formatters.addColumns, args.columns:gsub( '-', '–' ) ) )
end
additions = { table.concat( additions, formatters.addDelimiter1 ) }
if args.extent ~= '' then
table.insert( additions, args.extent )
end
if args.doi ~= '' then
table.insert( additions,
mw.ustring.format( formatters.addDoi, makeDoiLink( args.doi ) ) )
end
additions = table.concat( additions, formatters.addDelimiter2 )
if args.language ~= '' then
additions = additions .. mw.ustring.format( formatters.addLanguage, args.language )
end
if additions ~= '' then
additions = mw.ustring.format( formatters.puAll, additions )
end
if args.comment ~= '' then
additions = additions .. mw.ustring.format( formatters.addComment, args.comment )
end
return additions
end
local function makeBook( args )
if args.type ~= 'map' then
args.scale = ''
end
local author, title
if args.type == 'map' or args.type == 'book' then
author = makeAuthor( args.author, args.editor )
title = makeTitle( args.title, args.volume, args.url, args.scale )
else
author = makeAuthor( '', args.editor )
title = makeTitle( args.collection, args.volume, args.url, args.scale )
end
return author .. title .. makePublished( args )
end
local function makeCollection( args )
local author, collection, editor, title
author = makeAuthor( args.author, '' )
title = makeTitle( args.title, args.volume, args.articleUrl, '' )
editor = makeAuthor( '', args.editor )
collection = makeTitle( args.collection, args.volume, args.articleUrl, '' )
return author .. title .. formatters.tiIn .. editor .. collection
.. makePublished( args )
end
local function makeJournalTitle( args )
local title
if args.type == 'journal' then
title = args.journal
else
title = args.newspaper
end
if not title or title == '' then
title = texts.noTitel
table.insert( errorMsgs, texts.unknownPeriodical )
end
if args.url ~= '' then
title = '[' .. args.url .. ' ' .. title .. ']'
end
if args.place ~= '' then
title = title .. mw.ustring.format( formatters.prPlace, args.place )
end
if args.abbr ~= '' then
title = title .. mw.ustring.format( formatters.prAbbr, args.abbr )
end
return title
end
local function getDate( aDate, aFormat )
local function formatDate( aDate, aFormat )
return mw.getContentLanguage():formatDate( aFormat, aDate, true )
end
if aDate ~='' then
local success, t;
success, t = pcall( formatDate, aDate, aFormat )
if success then
return t
else
table.insert( errorMsgs, texts.wrongDate )
return ''
end
else
return ''
end
end
local function makePeriodical( args )
args.noError = getNoError( args.noError )
local result = { makeAuthor( args.author, '' )
.. makeTitle( args.title, '', args.articleUrl, '' ) .. formatters.tiIn
.. makeJournalTitle( args ) }
if args.isbn and args.isbn ~= '' then
table.insert( result,
li._linkISBNSet( { isbn = args.isbn, noerror = args.noError } ) )
end
if args.issn and args.issn ~= '' then
table.insert( result, makeIssnLink( args.issn ) )
end
if args.type == 'journal' then
local aFormat = 'Y'
if args.date:match( '^[12]%d+%-%d+' ) then
aFormat = 'M Y'
end
local year = getDate( args.date, aFormat )
local volume = ''
if args.volume ~= '' then
volume = mw.ustring.format( formatters.prVolume, args.volume )
if args.issue ~= '' then
volume = mw.ustring.format( formatters.prVolIssue, volume, args.issue )
end
if year ~= '' then
volume = mw.ustring.format( formatters.prVolYear, volume, year )
end
else
if args.issue ~= '' then
volume = mw.ustring.format( formatters.prIssue, args.issue )
if year ~= '' then
volume = mw.ustring.format( formatters.prVolYear, volume, year )
end
else
volume = year
end
end
if volume ~= '' then
table.insert( result, volume )
end
else
if args.volume ~= '' then
table.insert( result,
mw.ustring.format( formatters.nsVolume, args.volume ) )
end
if args.date:match( '^[12]%d+%-%d+%-%d+$' ) then
day = getDate( args.date, 'l, j. F Y' )
else
day = ''
table.insert( errorMsgs, texts.wrongDate )
end
local issue = ''
if args.issue ~= '' then
issue = mw.ustring.format( formatters.prIssue, args.issue )
if day ~= '' then
issue = mw.ustring.format( formatters.nsNrOfDay, issue, day )
end
else
issue = day
end
if issue ~= '' then
table.insert( result, issue )
end
end
if args.pages ~= '' then
table.insert( result,
mw.ustring.format( formatters.addPages, args.pages:gsub( '-', '–' ) ) )
end
if args.columns ~= '' then
table.insert( result,
mw.ustring.format( formatters.addColumns, args.columns:gsub( '-', '–' ) ) )
end
if args.doi ~= '' then
table.insert( result,
mw.ustring.format( formatters.addDoi, makeDoiLink( args.doi ) ) )
end
if args.jstor ~= '' then
table.insert( result,
mw.ustring.format( formatters.dbJstor, args.jstor, args.jstor ) )
end
result = table.concat( result, formatters.addDelimiter1 )
if args.language ~= '' then
result = result .. mw.ustring.format( formatters.addLanguage, args.language )
end
if result ~= '' then
result = mw.ustring.format( formatters.puAll, result )
end
if args.comment ~= '' then
result = result .. mw.ustring.format( formatters.addComment, args.comment )
end
return result
end
local function getPageNumbers( pages )
if not pages then
return ''
end
pages = ( '' .. pages ):gsub( '–', '-' ); -- replace endashes with hyphens
return pages:gsub( '&%w+;', '-' ); -- replace html entities with hyphens
end
local function makeCOinS( args )
local rft = {}, key, value
for key, value in pairs( params ) do
if value.COinS and value.COinS:find( 'rft.' ) and args[ key ] and args[ key ] ~= '' then
table.insert( rft, value.COinS .. '=' .. mw.uri.encode( '' .. args[ key ] ) )
end
end
if next( rft ) then
if args.type == 'book' or args.type == 'map' or args.type == 'collection' then
if args.type == 'collection' then
table.insert( rft, 'rft.atitle=' .. mw.uri.encode( args.title ) )
table.insert( rft, 'rft.btitle=' .. mw.uri.encode( args.collection ) )
table.insert( rft, 1, 'rft.genre=bookitem' )
else
table.insert( rft, 'rft.btitle=' .. mw.uri.encode( args.title ) )
table.insert( rft, 1, 'rft.genre=book' )
end
table.insert( rft, 1, 'rft_val_fmt=' .. mw.uri.encode( 'info:ofi/fmt:kev:mtx:book' ) )
else
table.insert( rft, 1, 'rft.genre=journal' )
table.insert( rft, 1, 'rft_val_fmt=info:ofi/fmt:kev:mtx:journal' )
if args.type == 'journal' then
table.insert( rft, 'rft.jtitle=' .. mw.uri.encode( args.journal ) )
else
table.insert( rft, 'rft.jtitle=' .. mw.uri.encode( args.newspaper ) )
end
table.insert( rft, 'rft.atitle=' .. mw.uri.encode( args.title ) )
end
table.insert( rft, 1, 'ctx_ver=Z39.88-2004' )
rft = table.concat( rft, '&' )
return '<span class="Z3988" title="' .. rft .. '"></span>'
end
end
local function makeCitation( frameArgs )
local args, citation
args = checkParams( frameArgs )
args.pages = getPageNumbers( args.pages )
args.columns = getPageNumbers( args.columns )
if args.type == 'map' or args.type == 'book' then
citation = makeBook( args )
elseif args.type == 'collection' then
citation = makeCollection( args )
elseif args.type == 'journal' or args.type == 'newspaper' then
citation = makePeriodical( args )
else
citation = texts.wrongType
end
-- remove adjoining punctuation marks
citation = mw.ustring.gsub( citation, '([!%?,:])(%.+)', '%1' )
-- prepare for COinS
args.date = args.date:match( '%d+' ) or ''
args.pages = args.pages:match( '%d+%-%d+' ) or args.pages:match( '%d+' )
args.columns = args.columns:match( '%d+%-%d+' ) or args.columns:match( '%d+' )
local at = args.author:find( ';' )
if at then
args.author = mw.text.trim( args.author:sub( 1, at - 1 ) )
end
return table.concat( errorMsgs, ' ' )
.. '<cite style="font-style: normal;" class="citation ' .. args.type
.. ' printNoLink">' .. citation .. '</cite>' .. makeCOinS( args )
end
function ci.book( frame )
local args = frame:getParent().args, ok
args.type = 'book'
return makeCitation( args )
end
function ci.map( frame )
local args = frame:getParent().args
args.type = 'map'
return makeCitation( args )
end
function ci.collection( frame )
local args = frame:getParent().args
args.type = 'collection'
return makeCitation( args )
end
function ci.journal( frame )
local args = frame:getParent().args
args.type = 'journal'
return makeCitation( args )
end
function ci.newspaper( frame )
local args = frame:getParent().args
args.type = 'newspaper'
return makeCitation( args )
end
function ci.citation( frame )
local args = frame:getParent().args
-- local args = frame
aType = getArgValue( 'type', args )
if not aType or aType == '' or not inArray( types, aType ) then
if getArgValue( 'scale', args ) ~= '' then
aType = 'map'
elseif getArgValue( 'collection', args ) ~= '' then
aType = 'collection'
elseif getArgValue( 'journal', args ) ~= '' then
aType = 'journal'
elseif getArgValue( 'newspaper', args ) ~= '' then
aType = 'newspaper'
else
aType = 'book'
end
args.type = aType
end
return makeCitation( args )
end
return ci