„Modul:WikibaseLink“ – Versionsunterschied
Erscheinungsbild
KKeine Bearbeitungszusammenfassung |
KKeine Bearbeitungszusammenfassung Markierung: Manuelle Zurücksetzung |
||
| (39 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
local p = {} | local p = {} | ||
-- Hilfsfunktion: | ------------------------------------------------------------------ | ||
local function | -- 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 | end | ||
-- 1) | -- 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 | 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 | end | ||
-- | -- 2) Nur SHORTDESC-Wikitext zurückgeben (falls sinnvoll) | ||
-- | -- Hinweis: Ob die ShortDescription-Extension {{SHORTDESC:...}} | ||
function p. | -- 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 | end | ||
return p | return p | ||
Aktuelle Version vom 14. Dezember 2025, 11:05 Uhr
| 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