Zum Inhalt springen

Modul:RE

aus Wikisource, der freien Quellensammlung

Dieses Modul stellt Funktionen zur Arbeit mit Paulys Realencyclopädie der classischen Altertumswissenschaft (RE) zur Verfügung.

Vorlagen

[Bearbeiten]

Die Vorlage „RE siehe“ wird benutzt um auf einen Artikel in der RE zu verweisen. Ist der Artikel noch nicht vorhanden wird stattdessen das Register verwiesen. Das Modul wird als {{#invoke:RE|siehe}} in die Vorlage eingebunden.

Beispiel: Aphrodite verweist auf den Artikel, während Kymbros auf das Register kl verweist.

Die Vorlage „RE Scan“ wird verwendet um eine URL auf einen spezifischen Scan der RE zu erzeugen. Als Eingabeparameter werden der Band in der RE benötigt und die Spaltennummer, die auf dem Scan abgebildet sein soll. Die Spaltennummer in der URL muss nicht der gewollten Spaltennummer übereinstimmen, da sich mehrere Spalten auf einer gescannten Seite befinden.

Beispiel: {{RE Scan|I|1234}} erzeugt einen Link zum Bild https://elexikon.ch/meyers/RE/I_1233.png.

Die Vorlage „REDaten“ ist am Anfang jedes Artikels der RE eingebunden und zeigt die Infobox, kategorisiert den Artikel und blendet einen Hinweis zur Gemeinfreiheit ein. Auch Nachträge beginnen mit der Vorlage.

Zur Formatierung der einzelnen Komponenten werden Untervorlagen verwendet:

Die Vorlage „REAutor“ fügt einen Link zum Autorenkürzel hinzu und kategorisiert die Seite passend.

Tabellen

[Bearbeiten]

Die RE benutzt einige zusätzliche Tabellen um Daten zu speichern:

  • Modul:RE/Autoren bildet verschiedene Autorenkürzel unter den Artikeln auf Personennamen ab. THEbotIT integriert diese Tabelle in das grössere Python-File authors_mapping.json, das auf GitHub gepflegt wird.
  • Modul:RE/Jahre kennt für jeden Band die Veröffentlichungsjahr(e).

local p       = {}
local RE_LONG = 'Paulys Realencyclopädie der classischen Altertumswissenschaft'

-- Hilfsfunktionen

-- Entfernt Whitespace.
-- Der Wert nil und der leere String ergeben beide nil.
local function fromText(text)
	if not text then return nil end
	text = mw.text.trim(text)
	if text == '' then return nil end
	return text
end

-- Konvertiert ON/OFF zu Boolean.
-- ON wird as wahr akzeptiert. OFF/(leerer Wert)/nil wird als falsch erkannt.
-- Andere Werte verursachen einen Fehler.
local function fromOnOff(onOff)
	local onOff = fromText(onOff)
	if onOff == 'ON' then return true
	elseif onOff == 'OFF' or onOff == nil then return false
	else error('ON/OFF erwartet, Wert ist aber: ' .. onOff)
	end
end

-- Ersetzt einen Wert von OFF mit nil.
local function fromOptional(value)
	if value == 'OFF' then
		return nil
	else return value end
end

local function getIAScan(path, column, columnsOnPage)
	if column < 3 then
		page = "0001"
	else
		page = string.format("%04d", tostring((math.floor((column - (columnsOnPage-1)) / columnsOnPage) * columnsOnPage) + (columnsOnPage - 1)))
	end
	return "https://www.archive.org/download/" .. path .. "_" .. page .. ".png"
end

local function getELScan(volume, column, columnsOnPage)
	return "https://elexikon.ch/meyers/RE/" .. string.gsub(volume, " ", "") .. "_" .. tostring(((math.ceil((column + (columnsOnPage / 2)) / columnsOnPage) - 1) * columnsOnPage) + 1) .. ".png"
end

local function getExternalScan(band, spalte)
	spalte = tonumber(spalte)
    if     band == "I,1"    then return getIAScan("PWRE01-02/Pauly-Wissowa_I1", spalte, 2)
    elseif band == "I,2"    then return getIAScan("PWRE01-02/Pauly-Wissowa_I2", spalte, 2)
    elseif band == "II,1"   then return getIAScan("PWRE03-04/Pauly-Wissowa_II1", spalte, 2)
    elseif band == "II,2"   then return getIAScan("PWRE03-04/Pauly-Wissowa_II2", spalte, 2)
    elseif band == "III,1"  then return getIAScan("PWRE05-06/Pauly-Wissowa_III1", spalte, 2)
    elseif band == "III,2"  then return getIAScan("PWRE05-06/Pauly-Wissowa_III2", spalte, 2)
    elseif band == "IV,1"   then return getIAScan("PWRE07/Pauly-Wissowa_IV1", spalte, 2)
    elseif band == "IV,2"   then return getIAScan("PWRE08/Pauly-Wissowa_IV2", spalte, 4)
    elseif band == "V,1"    then return getIAScan("PWRE09-10/Pauly-Wissowa_V1", spalte, 4)
    elseif band == "V,2"    then return getIAScan("PWRE09-10/Pauly-Wissowa_V2", spalte, 2)
    elseif band == "VI,1"   then return getIAScan("PWRE11/Pauly-Wissowa_VI1", spalte, 4)
    elseif band == "VI,2"   then return getIAScan("PWRE12/Pauly-Wissowa_VI2", spalte, 4)
    elseif band == "VII,1"  then return getIAScan("PWRE13/Pauly-Wissowa_VII1", spalte, 4)
    elseif band == "VII,2"  then return getIAScan("PWRE14/Pauly-Wissowa_VII2", spalte, 4)
    elseif band == "VIII,1" then return getIAScan("PWRE15/Pauly-Wissowa_VIII1", spalte, 4)
    elseif band == "VIII,2" then return getIAScan("PWRE16/Pauly-Wissowa_VIII2", spalte, 4)
    elseif band == "IX,2"   then return getIAScan("PWRE18/Pauly-Wissowa_IX2", spalte, 4)
    elseif band == "X,1"    then return getIAScan("PWRE19/Pauly-Wissowa_X1", spalte, 4)
    elseif band == "X,2"    then return getIAScan("PWRE20/Pauly-Wissowa_X2", spalte, 4)
    elseif band == "XI,1"   then return getIAScan("PWRE21/Pauly-Wissowa_XI1", spalte, 2)
    elseif band == "XI,2"   then return getIAScan("PWRE22/Pauly-Wissowa_XI2", spalte, 4)
    elseif band == "XII,1"  then return getIAScan("PWRE23/Pauly-Wissowa_XII,1,", spalte, 2)
    elseif band == "XII,2"  then return getIAScan("PWRE24/Pauly-Wissowa_XII,2,", spalte, 2)
    elseif band == "I A,1"  then return getIAScan("PWRE48/Pauly-Wissowa_I_A1", spalte, 4)
    elseif band == "I A,2"  then return getIAScan("PWRE49/Pauly-Wissowa_I_A2", spalte, 4)
    elseif band == "II A,1" then return getIAScan("PWRE50/Pauly-Wissowa_II_A1", spalte, 4)
    elseif band == "II A,2" then return getIAScan("PWRE51/Pauly-Wissowa_II_A,2,", spalte, 2)
    elseif band == "R"      then return getELScan(band, spalte, 2)
    else                         return getELScan(band, spalte, 4)
    end
end

local function selectRegister(title)
    local prefix  = string.lower(string.sub(title, 1, 2))
    local initial = string.sub(prefix, 1, 1)

    if     'aa' <= prefix and prefix <= 'aj' then return 'a'
    elseif 'ak' <= prefix and prefix <= 'am' then return 'ak'
    elseif 'an' <= prefix and prefix <= 'aq' then return 'an'
    elseif                    prefix == 'ar' then return 'ar'
    elseif 'as' <= prefix and prefix <= 'az' then return 'as'
    elseif                    initial == 'b' then return 'b'
    elseif 'ca' <= prefix and prefix <= 'ce' then return 'c'
    elseif 'cf' <= prefix and prefix <= 'cz' then return 'ch'
    elseif 'da' <= prefix and prefix <= 'dh' then return 'd'
    elseif 'di' <= prefix and prefix <= 'dz' then return 'di'
    elseif 'ea' <= prefix and prefix <= 'eq' then return 'e'
    elseif 'er' <= prefix and prefix <= 'ez' then return 'er'
    elseif                    initial == 'f' then return 'f'
    elseif                    initial == 'g' then return 'g'
    elseif 'ha' <= prefix and prefix <= 'hh' then return 'h'
    elseif 'hi' <= prefix and prefix <= 'hz' then return 'hi'
    elseif initial == 'i'  or initial == 'j' then return 'i'
    elseif 'ka' <= prefix and prefix <= 'ki' then return 'k'
    elseif 'kl' <= prefix and prefix <= 'kz' then return 'kl'
    elseif 'la' <= prefix and prefix <= 'le' then return 'l'
    elseif 'lf' <= prefix and prefix <= 'lz' then return 'lf'
    elseif                    prefix == 'ma' then return 'm'
    elseif 'mb' <= prefix and prefix <= 'mh' then return 'mb'
    elseif 'mi' <= prefix and prefix <= 'mz' then return 'mi'
    elseif                    initial == 'n' then return 'n'
    elseif                    initial == 'o' then return 'o'
    elseif 'pa' <= prefix and prefix <= 'pd' then return 'p'
    elseif 'pe' <= prefix and prefix <= 'ph' then return 'pe'
    elseif 'pi' <= prefix and prefix <= 'pn' then return 'pi'
    elseif 'po' <= prefix and prefix <= 'pq' then return 'po'
    elseif 'pr' <= prefix and prefix <= 'pz' then return 'pr'
    elseif                    initial == 'q' then return 'q'
    elseif                    initial == 'r' then return 'r'
    elseif 'sa' <= prefix and prefix <= 'sd' then return 's'
    elseif 'se' <= prefix and prefix <= 'sn' then return 'se'
    elseif 'so' <= prefix and prefix <= 'sz' then return 'so'
    elseif 'ta' <= prefix and prefix <= 'tg' then return 't'
    elseif                    prefix == 'th' then return 'th'
    elseif 'ti' <= prefix and prefix <= 'tz' then return 'ti'
    elseif 'ua' <= prefix and prefix <= 'ue' then return 'u'
    elseif 'uf' <= prefix and prefix <= 'uz' then return 'uf'
    elseif 'va' <= prefix and prefix <= 've' then return 'u'
    elseif 'vf' <= prefix and prefix <= 'vz' then return 'uf'
    elseif 'wa' <= prefix and prefix <= 'we' then return 'u'
    elseif 'wf' <= prefix and prefix <= 'wz' then return 'uf'
    elseif                    initial == 'x' then return 'x'
    elseif                    initial == 'y' then return 'y'
    elseif                    initial == 'z' then return 'z'
    else   return ''
    end
end

-- Berechnet das Jahr der Gemeinfreiheit basierend
-- auf dem Todesjahr wenn bekannt oder dem Geburtsjahr.
-- Gemeinfreiheit beginnt 70 Jahre nach dem Tod.
-- Falls nur ein Geburtsdatum bekannt ist geht man prakmatisch von 
-- Geburtsjahr + 151 Jahren aus.
-- Ist kein Datum angegeben wird die Gemeinfreiheit angenommen.
local function calcPublicDomainYear(TJ, GJ)
	if TJ then
		return tonumber(TJ) + 71
	elseif GJ then
		return tonumber(GJ) + 151
	else
		return 1000 -- long common free
	end
end

-- Prüft ob das Jahr der Gemeinfreiheit erreicht ist.
local function isInPublicDomain(TJ, GJ)
	currentYear = tonumber(os.date( "%Y" ))
	return calcPublicDomainYear(TJ, GJ) <= currentYear
end

local function getSubjectInfo()
	local result = {}
	
	-- Hole das Wikidata Objekt zum Artikel
    local entity = mw.wikibase.getEntity()
    if entity == nil then return result end
    
    -- Hole die Wikidata-ID zum Schlagwort ("subject")
    local subjectClaim = entity:getBestStatements('P921')
    if #subjectClaim == 0 or subjectClaim[1].mainsnak.snaktype ~= 'value' then
    	return result
    end
    local subjectId = subjectClaim[1].mainsnak.datavalue.value.id
    result.subject = subjectId
    
    -- Hole das Datenobjekt vom Schlagwort
    local subject = mw.wikibase.getEntity(subjectId)
    if subject == nil then
    	return result
    end

    -- Hole den Artikel in der deutschen Wikipedia zum Schlagwort
	result.dewiki = subject:getSitelink('dewiki')
    -- Hole den Artikel in der deutschen Wikisource zum Schlagwort
	result.dewikisource = subject:getSitelink('dewikisource')
   
   -- Hole das Label zum Schlagwort
    local label = subject:getLabel()
    if label then
	    result.label = label
	end

   -- Hole die GND zum Schlagwort
    local gndClaim = subject:getBestStatements('P227')
    if #gndClaim ~= 0 and gndClaim[1].mainsnak.snaktype == 'value' then
	    result.gnd =      gndClaim[1].mainsnak.datavalue.value
	end
	
	-- Hole Pleiades ID zum Schlagwort
    local plidClaim = subject:getBestStatements('P1584')
    if #plidClaim ~= 0 and plidClaim[1].mainsnak.snaktype == 'value' then
	    result.plid =      plidClaim[1].mainsnak.datavalue.value
	end
    return result
end

local function getInternalScan(volume, column)
	columnInt = tonumber(column)
	if columnInt then
		if columnInt % 2 == 0 then
			columnInt = columnInt - 1
		end
		columnStr = string.format("%04d", tonumber(columnInt))
	else
		columnStr = column
	end
	local name = "Pauly-Wissowa " .. volume .. ", " .. columnStr .. ".jpg"
	-- Prüfe ob Datei existiert
	if mw.title.new(name, 'Media').exists then
		return name
	end
	return nil
end

local function getYearPublished(volume)
	return mw.loadData("Modul:RE/Jahre")[volume]
end

function getAuthorName(kuerzel, band)
	local lookup = mw.loadData("Modul:RE/Autoren")[kuerzel]
	if type(lookup) == "table" then
		return lookup[band or 1] or lookup[1]
	else
		return lookup
	end
end

-- Vorlagenfunktionen

function p.siehe(frame)
	local args  = frame:getParent().args
	local title = args[1]
	local label = args[2]
	local fragment = args[3] or ''
	
	if not title then
		error('es muss ein Titel angegeben werden', 0)
	end
	
	-- Benutze das Label wenn angegeben, sonst den Titel
	if not label or label == '' then
		label = title
	end
	
	local page = mw.title.new('RE:' .. title)
	assert(page, 'ungültiger Titel', 0)
	if page.exists then
		return string.format('[[RE:%s#%s|%s]]', title, fragment, label)
	end
	
	local register = selectRegister(title)
	local link = string.format('%s/Register/%s', RE_LONG, register)
	assert(mw.title.new(link).exists, 'fehlendes Register')
	local linktext =  string.format(
		'[[%s#%s|<span style="color:#0B610B">%s</span>]]',
		link, title, label
	)
	-- Wartungskategorie für Quellentexte
	if mw.title.getCurrentTitle():inNamespace(0) then
		linktext = linktext .. '[[Kategorie:RE:Links auf Register]]'
	end
	return linktext
end

local function createInfoBanner(frame, args)
	if isInPublicDomain(args.TJ, args.GJ) then
		return ''
	end
	if args.KSCH then
		if args.TJ then
			jahrBlock = string.format("† %s", args.TJ)
		else
			jahrBlock = string.format("* %s", args.GJ)
		end
		return frame:expandTemplate{
			title='REDaten/Keine Schöpfungshöhe',
			args={JAHR=jahrBlock}
		}
	else
		return frame:expandTemplate{
			title='REDaten/Platzhalter',
			args={
				TITEL=args.TITEL,
				BAND=args.BD,
				JAHR=calcPublicDomainYear(args.TJ, args.GJ),
				EXTSCAN_START= getExternalScan(args.BD, args.SS)
			}
		}
	end
end

local function createProofRead(frame, args)
	local link = getExternalScan(args.BD, args.SS)
	if not args.NT then
		return frame:expandTemplate{
			title='ProofRead',
			args={link}
		}
	else
		return frame:expandTemplate{
			title='Seite',
			args={'Abschnitt korrekturlesen', '', link}
		}
	end
end

local function addOneYear(year)
	if year then
	    return tostring(tonumber(year) + 1)
	else
		return nil
	end
end

local function categorizePage(args)
	local result = string.format('[[Kategorie:%s]]', RE_LONG)
	result = result .. string.format('[[Kategorie:RE:Band %s]]', args.BD)
	if args.VW then
		result = result .. '[[Kategorie:RE:Verweisung]]'
	end
	-- die Wartungskategorie für Gemeinfreiheit sollen auch noch in dem Jahr 
	-- angezeigt werden in der der Artikel gemeinfrei wurde.
	if not isInPublicDomain(addOneYear(args.TJ), addOneYear(args.GJ)) then
		result = result .. '[[Kategorie:Wikisource:Gemeinfreiheit ' 
		                .. calcPublicDomainYear(args.TJ, args.GJ) .. ']]'
		if not args.KSCH then
			result = result .. '[[Kategorie:RE:Platzhalter]]'
		end
	end
	return result
end

local function getScanLink(volume, column)
	internalLink = getInternalScan(volume, column)
	externalLink = getExternalScan(volume, column)
	if internalLink then
		fullInternalLink = "[[:Media:" .. internalLink .. "|" .. column .. "]]"
		if externalLink:find("archive") then
			return fullInternalLink .. " ([" .. externalLink ..  " IA])"
		else
			return fullInternalLink .. " ([" .. externalLink ..  " EL])"
		end
	else
		return "[" .. externalLink ..  " " .. column .."]"	
	end
end

local function getScanRow(args)
	result = "Band [[:Kategorie:RE:Band " .. args.BD .. "|" .. args.BD .. "]]"
	result = result .. " (" .. getYearPublished(args.BD) .. ")"
	result = result .. " S. " .. getScanLink(args.BD, args.SS)
	if args.SE then
		result = result .. "–"  .. getScanLink(args.BD, args.SE)
	end
	return  result
end

-- Bestimme Text für den Korrekturstand
-- und gebe Links zu den Kategorien zurück
local function getStatus(args)
	local status = args.KOR
	args.KOR_TEXT = status
	if status == 'Ohne Quelle' or status == 'ohne quelle' or status == 'ohne Quelle' or status == 'ohne_Quelle' then
		args.KOR_TEXT = 'ohne Quelle'
		return '[[Kategorie:Ohne Quelle]][[Kategorie:RE:Problemfälle]]'
	elseif status == 'Scanfehler' then
		return '[[Kategorie:Scanfehler]][[Kategorie:RE:Problemfälle]]'
	elseif status == 'unkorrigiert' then
		return '[[Kategorie:Unkorrigiert]][[Kategorie:RE:Unkorrigiert]]'
	elseif status == 'korrigiert' then
		return '[[Kategorie:Korrigiert]][[Kategorie:RE:Korrigiert]]'
	elseif status == 'fertig' then
		return '[[Kategorie:Fertig]][[Kategorie:RE:Fertig]]'
	elseif status == 'teilkorrigiert' then
		return '[[Kategorie:Teilkorrigiert]][[Kategorie:RE:Teilkorrigiert]]'
	elseif status == 'Korrekturprobleme' then
		return '[[Kategorie:Korrekturprobleme]][[Kategorie:RE:Problemfälle]]'
	elseif status == 'unvollständig' then
		return '[[Kategorie:Unvollständig]][[Kategorie:RE:Unvollständig]]'
	elseif not status then
		args.KOR_TEXT = ''
		return '[[Kategorie:RE:Problemfälle]]'
	else
		args.KOR_TEXT = 'unbekannt'
		return '[[Kategorie:Unbekannter Bearbeitungsstand]][[Kategorie:RE:Unbekannter Korrekturstand]]'
	end
end

function serializeTable(val, name, skipnewlines, depth)
    skipnewlines = skipnewlines or false
    depth = depth or 0
    local tmp = string.rep(" ", depth)
    if name then tmp = tmp .. name .. " = " end
    if type(val) == "table" then
        tmp = tmp .. "{" .. (not skipnewlines and "\n" or "")
        for k, v in pairs(val) do
            tmp =  tmp .. serializeTable(v, k, skipnewlines, depth + 1) .. "," .. (not skipnewlines and "\n" or "")
        end
        tmp = tmp .. string.rep(" ", depth) .. "}"
    elseif type(val) == "number" then
        tmp = tmp .. tostring(val)
    elseif type(val) == "string" then
        tmp = tmp .. string.format("%q", val)
    elseif type(val) == "boolean" then
        tmp = tmp .. (val and "true" or "false")
    else
        tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\""
    end
    return tmp
end

function p.Daten(frame)
	-- Laden der Argumente
	local raw = frame:getParent().args
	local args = {
		TITEL = string.sub(mw.title.getCurrentTitle().text, 4),
		BD  = fromText(raw.BAND or raw.BD),
		SS  = fromText(raw.SPALTE_START or raw.SS),
		SE  = fromText(raw.SPALTE_END or raw.SE),
		VG  = fromText(raw['VORGÄNGER'] or raw.VG),
		NF  = fromText(raw.NACHFOLGER or raw.NF),
		SRT = fromText(raw.SORTIERUNG or raw.SRT),
		KOR = fromText(raw.KORREKTURSTAND or raw.KOR),
		KT  = fromText(raw.KURZTEXT or raw.KT),
		WS  = fromText(raw.WIKISOURCE or raw.WS),
		WP  = fromText(raw.WIKIPEDIA or raw.WP),
		GND = fromText(raw.GND),
		KSCH= fromOnOff(raw['KEINE_SCHÖPFUNGSHÖHE'] or raw.KSCH),
		TJ  = fromText(raw.TODESJAHR or raw.TJ),
		GJ  = fromText(raw.GEBURTSJAHR or raw.GJ),
		NT  = fromOnOff(raw.NACHTRAG or raw.NT),
		['ÜB'] = fromOnOff(raw['ÜBERSCHRIFT'] or raw['ÜB']
	    	or    raw['NACHTRAGSÜBERSCHRIFT'] or raw['NÜ']),
		VW  = fromOnOff(raw.VERWEIS or raw.VW)
	}
	-- Prüfung, ob die erforderlichen Werte vorhanden sind
	if not args.BD then
		error("Es wurde der Parameter BAND nicht gesetzt, dieser ist notwendig")
	elseif not args.SS then
		error("Es wurde der Parameter START_SPALTE nicht gesetzt, dieser ist notwendig")
	elseif not args.VG then
		error("Es wurde der Parameter VORGÄNGER nicht gesetzt, dieser ist notwendig")
	elseif not args.NF then
		error("Es wurde der Parameter NACHFOLGER nicht gesetzt, dieser ist notwendig")
	elseif (args.KSCH or isInPublicDomain(args.TJ, args.GJ)) and not args.KOR then
		error("Ein gemeinfreier Artikel muss einen KORREKTURSTAND haben")
	end
	-- Ersetze OFF durch nil
	args.SE = fromOptional(args.SE)
	args.VG = fromOptional(args.VG)
	args.NF = fromOptional(args.NF)
	-- Check Arguments logical
	if args.SS == args.SE then
		args.SE = nil	
	end
	-- Daten aus Wikidata holen
	local info = getSubjectInfo()
	args.WS = args.WS or info.dewikisource
	args.WP = args.WP or info.dewiki
	args.GND = args.GND or info.gnd
	args.WD = info.subject
	args.PLID = info.plid
	args.LABEL = info.label
	-- Wartungskategorien für widersprüchliche Angaben hinzufügen.
	local serviceCats = ''
	if info.dewikisource and args.WS ~= info.dewikisource then
		serviceCats = serviceCats .. '[[Kategorie:RE:Wartung Wikidata (WS)]]'
	end
	if info.dewiki and args.WP ~= info.dewiki then
		serviceCats = serviceCats .. '[[Kategorie:RE:Wartung Wikidata (WP)]]'
	end
	if info.gnd and args.GND ~= info.gnd then
		serviceCats = serviceCats .. '[[Kategorie:RE:Wartung Wikidata (GND)]]'
	end
	-- Veröffentlichungsjahr bestimmen, Vorschau Links
	args.VJAHR = getYearPublished(args.BD)
	assert(args.VJAHR, "Kürzel des Bandes ist unbekannt")
	local statusCats = ''
	if isInPublicDomain(args.TJ, args.GJ) or args.KSCH then
		statusCats = getStatus(args)
	end
	args.SCANROW = getScanRow(args)
	-- Ausgabe erzeugen
	local result = ""
	-- result = result .. serializeTable(info) -- for debugging only
	result = result .. '<div style="overflow:auto">'
	result = result .. frame:expandTemplate{title='Anker', args={args.BD}}
	if args['ÜB'] then
		result = result .. '\n== Nachträge und Berichtigungen =='
	end
	result = result .. '\n'
	-- result = result .. serializeTable(frame:expandTemplate{title='REDaten/InfoboxTest', args=args}) -- for debugging only
	result = result .. frame:expandTemplate{title='REDaten/Infobox', args=args}
	result = result .. '<div style="text-align:justify; width:100%-260px; padding-right:260px">'
	result = result .. createInfoBanner(frame, args)
	result = result .. createProofRead(frame, args)
	-- Füge Sortierung hinzu
	if not args.NT then
		result = result .. frame:callParserFunction{
			name='DEFAULTSORT',
			args=args.SRT or args.TITEL
		}
	end
	-- Kategorisiere Quellentexte
	if mw.title.getCurrentTitle():inNamespace(0) then
		result = result .. categorizePage(args)
		result = result .. statusCats
		result = result .. serviceCats
	end
	return  result
end

function p.Autor(frame)
	local kuerzel = frame.args[1]
	local band = frame.args[2]
	local altText = frame.args[3]
	local identification = frame.args[4]
	local name = ""
	if identification and identification ~= "" then
		name = identification
	else
		name = getAuthorName(kuerzel, band)
	end
	if name == nil then
		return kuerzel .. " [[Kategorie:RE:Kein Autor im Mapping gefunden]]"
	end
	if altText and altText ~= "" then
		result = altText .. "]]"
	else
		if kuerzel:match("%.$") then
			result = kuerzel:sub(1, -2) .. "]]."
		else
			result = kuerzel .. "]]"
		end
	end
	local kat, zusatz = mw.ustring.match(name, "^([^|]*)%|?(.*)$")
	return string.format("[[%s%s|%s [[Kategorie:RE:Autor:%s]]", kat, zusatz, result, kat)
end

function p.Scan(frame)
	local band = frame.args[1]
	local spalte = tonumber(frame.args[2])
	return getExternalScan(band, spalte)
end

function p.Jahr(frame)
	local band = frame.args[1]
	return getYearPublished(band)
end

return p