Modul:WikibaseLink
Erscheinungsbild
| Vorlagenprogrammierung | Diskussionen | Lua | Unterseiten | ||
| Modul | Deutsch
|
Modul: | Dokumentation | ||
Diese Seite enthält Code in der Programmiersprache Lua. Einbindungszahl Cirrus
local p = {}
------------------------------------------------------------------
-- Modul:WikibaseLink – überarbeitete Fassung (sichtbare Ausgabe)
-- Ziel:
-- 1) Links zu Q / P / L ausgeben (Special:EntityPage/...)
-- 2) Für P und L passende Kurzbeschreibung ermitteln
-- - P: Wikibase-Beschreibung
-- - L: lexikalische Kategorie (Label)
-- 3) OPTIONAL: Kurzbeschreibung als {{SHORTDESC:...}} bereitstellen
-- (über p.shortdesc), aber NICHT mehr automatisch im sichtbaren
-- Seitentext ausgeben.
-- 4) Für P und L sichtbares Muster:
-- ID Label (Kurzbeschreibung)
-- z.B. L2 Dingwort (Wortewort)
--
-- Nutzung (direkt per #invoke):
-- {{#invoke:WikibaseLink|link|entity=Q123}}
-- {{#invoke:WikibaseLink|link|P=P31}}
-- {{#invoke:WikibaseLink|link|L=L1}}
-- {{#invoke:WikibaseLink|shortdesc|P=P31|mode=P}}
-- {{#invoke:WikibaseLink|shortdesc|L=L1|mode=L}}
-- {{#invoke:WikibaseLink|linkAndShortdesc|L=L1|mode=L}}
--
-- Empfohlene Vorlage:WikibaseLink (Beispiel im Chat), die intern
-- {{#invoke:WikibaseLink|linkAndShortdesc|entity={{{1|}}}|mode={{{mode|auto}}}|label={{{label|}}}}}
-- aufruft.
--
-- Parameter (alle Funktionen):
-- |entity= Q123 / P31 / L1 (allgemein)
-- |Q= explizit Item
-- |P= explizit Property
-- |L= explizit Lexem
-- |mode= 'auto' (Standard) / 'Q' / 'P' / 'L'
-- steuert v. a. die Kurzbeschreibung.
-- |label= optionaler Basis-Linktext statt Wikibase-Label/Lemma
--
-- Fallback:
-- Wenn keine Entity per Parameter angegeben ist, versucht
-- das Modul mw.wikibase.getEntityIdForCurrentPage().
------------------------------------------------------------------
-- Hilfsfunktion: Trim
local function trim(s)
if type(s) ~= 'string' then
return s
end
return (s:gsub('^%s+', ''):gsub('%s+$', ''))
end
-- Hilfsfunktion: Argumente nur aus dem aktuellen frame holen
-- (keine Parent-Args, damit Aufrufe wie L=L2 zuverlässig wirken)
local function getArgs(frame)
local args = {}
if not frame then
return args
end
for k, v in pairs(frame.args or {}) do
if v ~= '' and v ~= nil then
args[k] = v
end
end
return args
end
-- Entity-Typ bestimmen
local function getEntityType(id)
if type(id) ~= 'string' then
return nil
end
if id:match('^Q%d+$') then
return 'item' -- Q
elseif id:match('^P%d+$') then
return 'property' -- P
elseif id:match('^L%d+$') then
return 'lexeme' -- L
end
return nil
end
local function detectEntityId(args)
-- Kandidaten aus diesem Aufruf in fester Priorität;
-- wir bauen die Liste ohne Nil-Werte, damit ipairs
-- nicht durch führende Nil-Einträge vorzeitig abbricht.
-- 1) explizite Typen (L, P, Q)
local rawL = args.L or args.lexeme or args.l
local rawP = args.P or args.p
local rawQ = args.Q or args.q
-- 2) generische entity/id
local rawEntity = args.entity or args.Entity
local rawId = args.id or args.ID
-- 3) Positionsparameter (1)
local rawPos = args[1]
local ordered = {}
local function push(v)
if v ~= nil and v ~= '' then
table.insert(ordered, v)
end
end
-- Reihenfolge der Priorität
push(rawL)
push(rawP)
push(rawQ)
push(rawEntity)
push(rawId)
push(rawPos)
for _, v in ipairs(ordered) do
local s = trim(tostring(v))
if s ~= '' then
-- Direkte ID (Q123 / P31 / L2)
local id = s:match('^[QPL]%d+$')
-- Oder mit Namensraum-Präfix (z.B. "Lexeme:L2", "Property:P31", "Item:Q6")
if not id then
id = s:match('^.-:([QPL]%d+)$')
end
if id then
return id
end
end
end
-- Fallback: Entity zur aktuellen Seite (z. B. Q bei Sitelink)
local ok, currentId = pcall(mw.wikibase.getEntityIdForCurrentPage)
if ok and type(currentId) == 'string' and currentId:match('^[QPL]%d+$') then
return currentId
end
return nil
end
-- Label-/Lemma-Ermittlung für eine Entity (ohne Wikitext)
local function buildEntityLabel(entityId)
if not entityId then
return nil
end
local etype = getEntityType(entityId)
-- Spezieller Fall: Lexeme → Lemma in Inhalts-Sprache
if etype == 'lexeme' then
local ok, entity = pcall(mw.wikibase.getEntity, entityId)
if ok and type(entity) == 'table' and type(entity.lemmas) == 'table' then
local contentLang = 'de'
if mw.getContentLanguage then
local cl = mw.getContentLanguage()
if cl and cl.getCode then
contentLang = cl:getCode()
end
end
local lemma
if entity.lemmas[contentLang] and entity.lemmas[contentLang].value then
lemma = entity.lemmas[contentLang].value
else
-- Fallback: irgendein Lemma
for _, obj in pairs(entity.lemmas) do
if type(obj) == 'table' and obj.value then
lemma = obj.value
break
end
end
end
if lemma and lemma ~= '' then
return lemma
end
end
end
-- Standard: Label über Wikibase
local ok, fetched = pcall(mw.wikibase.getLabel, entityId)
if ok and fetched and fetched ~= '' then
return fetched
end
return entityId
end
-- Link auf eine Entity bauen (mit optionalem Label)
local function buildEntityLink(entityId, labelOverride)
if not entityId then
return ''
end
local label = labelOverride
if not label or label == '' then
label = buildEntityLabel(entityId) or entityId
end
return string.format('[[Special:EntityPage/%s|%s]]', entityId, label)
end
-- Kurzbeschreibung für eine Entity bestimmen
-- mode:
-- 'auto' / nil ->
-- Q (item) → Wikibase-Beschreibung
-- P (property) → Wikibase-Beschreibung
-- L (lexeme) → Label der lexikalischen Kategorie
-- 'Q' / 'item' → Wikibase-Beschreibung
-- 'P' / 'property' → Wikibase-Beschreibung
-- 'L' / 'lexeme' → Label der lexikalischen Kategorie
local function buildShortdescText(entityId, mode)
if not entityId then
return nil
end
local etype = getEntityType(entityId)
if not etype then
return nil
end
mode = mode and tostring(mode):lower() or 'auto'
if mode == 'auto' then
if etype == 'item' then
mode = 'q'
elseif etype == 'property' then
mode = 'p'
elseif etype == 'lexeme' then
mode = 'l'
end
end
-- Q und P: Wikibase-Beschreibung verwenden
if mode == 'q' or mode == 'item'
or mode == 'p' or mode == 'property'
then
local ok, desc = pcall( mw.wikibase.getDescription, entityId )
if ok and type( desc ) == 'string' and desc ~= '' then
return desc
end
return nil
elseif mode == 'l' or mode == 'lexeme' then
-- Lexem: lexikalische Kategorie → Label dieser Kategorie
local ok, entity = pcall( mw.wikibase.getEntity, entityId )
if not ok or type( entity ) ~= 'table' then
return nil
end
local lc = entity.lexicalCategory
if type( lc ) == 'table' then
lc = lc.id or lc.value
end
if type( lc ) ~= 'string' or lc == '' then
return nil
end
local okLabel, label = pcall( mw.wikibase.getLabel, lc )
if okLabel and type( label ) == 'string' and label ~= '' then
return label
else
return lc
end
end
return nil
end
-- Gloss für einen Lexem-Sinn ermitteln (z.B. S=1, S='S1', S='L1-S1')
local function getLexemeSenseGloss(entityId, senseParam)
if not entityId or not senseParam or senseParam == '' then
return nil
end
local etype = getEntityType(entityId)
if etype ~= 'lexeme' then
return nil
end
-- Sense-ID kanonisieren
local s = tostring(senseParam)
local senseId
-- Vollständige ID: L123-S4
if s:match('^L%d+-S%d+$') then
senseId = s
else
-- „S4“ oder „4“ → L123-S4
local num = s:match('^S(%d+)$') or s:match('^(%d+)$')
if not num then
return nil
end
senseId = string.format('%s-S%s', entityId, num)
end
-- Lexem-Entity holen
local ok, entity = pcall( mw.wikibase.getEntity, entityId )
if not ok or type(entity) ~= 'table' or type(entity.senses) ~= 'table' then
return nil
end
-- Ziel-Sense in entity.senses suchen
local targetSense = nil
for key, sense in pairs(entity.senses) do
if type(sense) == 'table' then
local sid = sense.id or key
if sid == senseId then
targetSense = sense
break
end
end
end
if not targetSense or type(targetSense.glosses) ~= 'table' then
return nil
end
-- Inhalts-Sprache bestimmen
local contentLang = 'de'
if mw.getContentLanguage then
local cl = mw.getContentLanguage()
if cl and cl.getCode then
contentLang = cl:getCode()
end
end
-- Gloss in Inhalts-Sprache bevorzugen, sonst irgendeinen
local gloss
local g = targetSense.glosses[contentLang]
if g and type(g) == 'table' and g.value then
gloss = g.value
else
for _, obj in pairs(targetSense.glosses) do
if type(obj) == 'table' and obj.value then
gloss = obj.value
break
end
end
end
if gloss and gloss ~= '' then
return gloss
end
return nil
end
-- Form (Wortform) für ein Lexem ermitteln (z.B. F=1, F='F1', F='L2-F1')
local function getLexemeFormRepresentation(entityId, formParam)
if not entityId or not formParam or formParam == '' then
return nil
end
local etype = getEntityType(entityId)
if etype ~= 'lexeme' then
return nil
end
-- Form-ID kanonisieren
local s = tostring(formParam)
local formId
-- Vollständige ID: L123-F4
if s:match('^L%d+-F%d+$') then
formId = s
else
-- „F4“ oder „4“ → L123-F4
local num = s:match('^F(%d+)$') or s:match('^(%d+)$')
if not num then
return nil
end
formId = string.format('%s-F%s', entityId, num)
end
-- Lexem-Entity holen
local ok, entity = pcall( mw.wikibase.getEntity, entityId )
if not ok or type(entity) ~= 'table' or type(entity.forms) ~= 'table' then
return nil
end
-- Ziel-Form in entity.forms suchen
local targetForm = nil
for key, form in pairs(entity.forms) do
if type(form) == 'table' then
local fid = form.id or key
if fid == formId then
targetForm = form
break
end
end
end
if not targetForm or type(targetForm.representations) ~= 'table' then
return nil
end
-- Inhalts-Sprache bestimmen
local contentLang = 'de'
if mw.getContentLanguage then
local cl = mw.getContentLanguage()
if cl and cl.getCode then
contentLang = cl:getCode()
end
end
-- Wortform in Inhalts-Sprache bevorzugen, sonst irgendeine
local formText
local r = targetForm.representations[contentLang]
if r and type(r) == 'table' and r.value then
formText = r.value
else
for _, obj in pairs(targetForm.representations) do
if type(obj) == 'table' and obj.value then
formText = obj.value
break
end
end
end
if formText and formText ~= '' then
return formText
end
return nil
end
------------------------------------------------------------------
-- Öffentliche Funktionen
------------------------------------------------------------------
-- 1) Nur Link ausgeben (ohne sichtbaren Untertitel)
-- Q: Label
-- P/L: ID Label
function p.link(frame)
local args = getArgs(frame)
local entityId = detectEntityId(args)
if not entityId then
return ''
end
local etype = getEntityType(entityId)
local baseLabel = args.label or args.text or buildEntityLabel(entityId) or entityId
local linkLabel
if etype == 'item' then
-- Q: nur das Label
linkLabel = baseLabel
else
-- P/L: ID + Label
linkLabel = string.format('%s %s', entityId, baseLabel)
end
-- Sicherheit: keine Zeilenumbrüche im Linktext
linkLabel = trim(linkLabel):gsub('\n', ' ')
return buildEntityLink(entityId, linkLabel)
end
-- 2) Nur SHORTDESC-Wikitext zurückgeben (falls sinnvoll)
-- Hinweis: Ob die ShortDescription-Extension {{SHORTDESC:...}}
-- aus Vorlagen heraus verarbeitet, hängt von der lokalen
-- Konfiguration ab.
function p.shortdesc(frame)
local args = getArgs(frame)
local entityId = detectEntityId(args)
if not entityId then
return ''
end
local mode = args.mode or args.typ or args.type
local text = buildShortdescText(entityId, mode)
if not text or text == '' then
return ''
end
text = trim(text):gsub('\n', ' ')
-- SHORTDESC als Parserfunktion aufrufen, so als stünde
-- {{SHORTDESC:text}} im Quelltext.
local ok, result = pcall(function()
-- Entspricht {{SHORTDESC:text}}
return frame:callParserFunction('SHORTDESC', text)
end)
if not ok then
-- Falls die Parserfunktion nicht verfügbar ist, lieber
-- still scheitern, damit Seiten nicht kaputtgehen.
return ''
end
-- SHORTDESC gibt in der Regel nichts Sichtbares zurück.
-- Wir geben das Ergebnis (typisch leer) zurück, so dass
-- der #invoke-Aufruf im Seitentext nichts anzeigt.
return result or ''
end
-- 3) Link mit Untertitel kombinieren
-- Muster:
-- Lexem ohne Sinn/Form: [[.../L2|L2 Dingwort]] (Wortewort)
-- Lexem mit Sinn (S): [[.../L2|L2 Dingwort]] (Wortewort)
-- Ding benennendes Wort
-- Lexem mit Sinn + Form: [[.../L2|L2 Dingwort]] (Wortewort)
-- Ding benennendes Wort
-- Ding benennende Wörter (z.B. F1)
-- Item/Property: [[.../Q6|Q6 Dingwort]] (…Beschreibung…)
function p.subtitle(frame)
local args = getArgs(frame)
local entityId = detectEntityId(args)
if not entityId then
return ''
end
local mode = args.mode or args.typ or args.type
local etype = getEntityType(entityId)
-- Basislabel: explizit oder aus Wikibase/Lexem-Lemma
local baseLabel = args.label or args.text or buildEntityLabel(entityId) or entityId
-- Untertitel: Beschreibung (Q/P) bzw. Wortart (L)
local desc = buildShortdescText(entityId, mode)
if desc ~= nil then
desc = trim(desc):gsub('\n', ' ')
end
----------------------------------------------------------------
-- Sinn (Sense) für Lexeme optional bestimmen (S=…)
----------------------------------------------------------------
local senseParam = args.S or args.s or args.sense
local senseGloss = nil
if senseParam and etype == 'lexeme' then
senseGloss = getLexemeSenseGloss(entityId, senseParam)
if senseGloss ~= nil then
senseGloss = trim(senseGloss):gsub('\n', ' ')
end
end
----------------------------------------------------------------
-- Form (Wortform) für Lexeme optional bestimmen (F=…)
----------------------------------------------------------------
local formParam = args.F or args.f or args.form or args.Form
local formText = nil
if formParam and etype == 'lexeme' then
formText = getLexemeFormRepresentation(entityId, formParam)
if formText ~= nil then
formText = trim(formText):gsub('\n', ' ')
end
end
----------------------------------------------------------------
-- Steuerung, ob der Untertitel im sichtbaren Text stehen soll
-- subtitle: ja/1 (Standard) → sichtbar
-- nein/0 → unsichtbar
----------------------------------------------------------------
local subtitleParam = args.subtitle
local showSubtitle = true -- Default: ja
if subtitleParam ~= nil and subtitleParam ~= '' then
local s = tostring(subtitleParam):lower()
if s == 'nein' or s == '0' then
showSubtitle = false
elseif s == 'ja' or s == '1' then
showSubtitle = true
end
end
-- SHORTDESC als Seiteneigenschaft setzen (für Suche), falls vorhanden
-- (weiterhin nur aus der Kurzbeschreibung, nicht aus Sinn/Form)
if desc and desc ~= '' then
pcall(function()
frame:callParserFunction('SHORTDESC', desc)
end)
end
-- Sichtbarer Link-Teil: für Q/P/L immer "ID Label"
local visibleLabel = string.format('%s %s', entityId, baseLabel)
visibleLabel = trim(visibleLabel):gsub('\n', ' ')
-- Link nur um ID + Label
local linkText = buildEntityLink(entityId, visibleLabel)
-- Wenn keine sichtbaren Untertitel gewünscht → nur Link zurückgeben
if not showSubtitle then
return linkText
end
-- Spezielles Layout für Lexeme: Zeile 1 + optional Zeile 2/3
if etype == 'lexeme' then
local line1
if desc and desc ~= '' then
line1 = string.format('%s (%s)', linkText, desc)
else
line1 = linkText
end
local lines = { line1 }
if senseGloss and senseGloss ~= '' then
table.insert(lines, senseGloss)
end
if formText and formText ~= '' then
table.insert(lines, formText)
end
-- Zeilen mit <br /> verbinden
return table.concat(lines, '<br />')
end
-- Standardfall: Q / P → Link + (Beschreibung)
if desc and desc ~= '' then
return string.format('%s (%s)', linkText, desc)
else
return linkText
end
end
return p